x
• Status: Solved
• Priority: Medium
• Security: Public
• Views: 465

# Rotate sprite in mcga

If I'm currently in Mcga mode, and have procedures to create and draw sprites from the screen and onto the screen, how do i go about rotating a sprite a have?  I don't know how to rotate anything really ):  If it also falls along the same lines, how would I scale something also?  As always, source is helpful!  Thanks!

-Brian
0
hansell
• 7
• 5
1 Solution

Commented:
Can I see the data structure (object, record, etc.) you are using to store your sprite?

The way I would go about doing it is mapping it to another sprite.  If you show me the data structure, I can show you how to scale and rotate it.

0

Commented:
Matrix multiplication is used to scale and rotate images.

Motaz
0

Commented:
program rotate;

{written by scrapdog  10/6/98}

uses crt;

const
MAX_WIDTH = 32;
MAX_HEIGHT = 32;

type
TSprite = record
Width, Height :integer;
Picture       :array[0..MAX_WIDTH, 0..MAX_WIDTH] of byte;
end;

procedure Rotate(var Sprite :TSprite;
var NewSprite :TSprite;
Theta :integer);
var
nx,ny,x,y,i,j  :integer;
CosA, SinA  :real;
CenterX, CenterY :integer;
begin
SinA := sin(Theta/180 * pi);
CosA := cos(Theta/180 * pi);
CenterX := Sprite.Width div 2;
CenterY := Sprite.Height div 2;
NewSprite.Width := Sprite.Width;
NewSprite.Height := Sprite.Height;
for i := 0 to Sprite.Width - 1 do
for j := 0 to Sprite.Height - 1 do begin
x := i - CenterX;
y := j - CenterY;
nx := (CenterX+(round(x*CosA-y*SinA)) mod Sprite.Width);
ny := (CenterY+(round(x*SinA+y*CosA)) mod Sprite.Height);
NewSprite.Picture[i,j] := Sprite.Picture[nx,ny];
end;
end;

procedure Scale(var Sprite :TSprite;
var NewSprite  :TSprite;
Scale :Real);
var
nx,ny,x,y,i,j  :integer;
CenterX, CenterY, NewCenterX, NewCenterY :integer;
begin
scale := abs(scale);
if scale = 0 then exit;
NewSprite.Width := round(Scale*Sprite.Width);
NewSprite.Height := round(Scale*Sprite.Height);
CenterX := Sprite.Width div 2;
CenterY := Sprite.Height div 2;
NewCenterX := NewSprite.Width div 2;
NewCenterY := NewSprite.Height div 2;
for i := 0 to NewSprite.Width - 1 do
for j := 0 to NewSprite.Height - 1 do begin
x := i- NewCenterX;
y := j- NewCenterY;
nx := (CenterX+round(x/scale) mod Sprite.Width);
ny := (CenterY+round(y/scale) mod Sprite.Height);
NewSprite.Picture[i,j] := Sprite.Picture[nx,ny]
end;
end;

procedure DisplaySprite(var Sprite :TSprite);
var i,j :integer;
begin
for i := 0 to Sprite.Height do begin
for j := 0 to Sprite.Width do write(Chr(Sprite.Picture[j,i]),Chr(Sprite.Picture[j,i]));
writeln;
end;
end;

var Sprite, NewSprite :TSprite;
i,j  :integer;
begin
Sprite.Width := 10;
Sprite.Height := 10;
NewSprite.Width := 10;
NewSprite.Height := 10;
for i := 0 to 20 do for j := 0 to 9 do
if (random(10)>7) then Sprite.Picture[j,i] := 219
else Sprite.Picture[j,i] := 32;
DisplaySprite(Sprite);
writeln('------');
for i := 0 to 360 do begin
Rotate(Sprite, NewSprite, i);
clrscr;
DisplaySprite(NewSprite);
Delay(1);
end;
writeln('press enter');
clrscr;
for i := 1 to 20 do begin
Scale(Sprite, NewSprite, i/10);
clrscr;
DisplaySprite(NewSprite);
Delay(30);
end;
for i := 20 downto 1 do begin
Scale(Sprite, NewSprite, i/10);
clrscr;
DisplaySprite(NewSprite);
Delay(30);
end;
writeln('press enter');
end.

------------------------------------------

This program is a demonstration of how to rotate sprites.  Text mode sprites are used to demonstrate the functions, but rotation of graphics in any mode is done the same way (MCGA, text, whatever).

The only functions you need to be concerned with are the Rotate and Scale functions.  You did not specify to me how you were storing your sprite, so I made my own data type TSprite (which you can change to fit your needs).

TSprite holds the height and width of the sprite in pixels, and the array "Picture" holds the pixels for the sprite.

To map one sprite onto another (rotated), call the rotate function.  The sprite will be rotated around its center, and the new sprite will have the same dimensions as the old one.

Example:

var
Sprite, RotatedSprite :TSprite;

Rotate(Sprite, RotatedSprite, 45);  {Copys the Sprite onto Rotated Sprite and rotates it by 45 degrees}

Note that this doesn't change Sprite in anyway.  It just puts the rotated version of the sprite into RotatedSprite.  (Rotating the ACTUAL sprite will result in loss of data eventually, so it is always good to keep a record of the original unrotated sprite, so thats why the function works this way).

Note that the number of degrees must be integer.  It can be positive or negative to indicate the diretion of rotation.

Scale works almost the same way.  It copys one sprite onto another and scales it.

Scale(Sprite, ScaledSprite, 1.5);

causes ScaledSprite to be a 1.5x copy of Sprite.

You can use the code above in your program (you might have to make some changes due to how your sprite data type works).  All you need are the Rotate and Scale procedures (and maybe the type declaration for TSprite).  The rest of the program is to demonstrate how they work and will not be needed by your program.  The only thing the rotate and scale functions handle are the mathematical transformations...it does not display the graphics.  Therefore this will work in any graphics mode.  Displaying the new rotated/scaled sprite is up to you.

Example:

Rotate(Sprite, RotatedSprite, 45);
DisplayOnScreen(RotatedSprite);    {one of your procedures, or however you want to do it}

----------------
When rotating a sprite, it is necessary that the height and width of the sprite are the same (or close), or there will be a loss of data.  Make sure the height and width are large enough so edges won't be cut out when you rotate it.  Making the height/width 1.414 times higher than the actual height/width of the graphic will accomplish this.

Example: if your graphic is 10 x 10, make the sprite height and width 14 x 14, and fill this outer edge with transparent pixels (value of 0,etc.), and in your display procedure don't map the transparent pixels.  Just a suggestion.

There are better ways of doing this, but this is the simplest.

scrapdog
0

Commented:
Hello ScrapDog.... I like your sprite rotating program, and was wondering if you could teach me how to rotate graphics... What are some of the principles of rotating images as a whole and working with graphics.???

10x

Regards,
Viktor Ivanov
0

Commented:
Viktor:

It is all about putting images through a transformation function.  A transformation function can rotate, scale, invert, or do anything that changes the actual contents of the images.

X and Y (where to extract the pixel) are dependent on a function of the X and Y of the new image.

For example, you would scan the coordinates of each pixel of the new image, and plug them into this function.  From the function you will get the coordinates of the old image.  So you take the pixel that is located at these coordinates in the old image, and plot it onto the coordinates of the new image.

ALL pixels in the new image will be defined, BUT not all pixels in the new image will necessarily make it to the old image.

For each coordinate of the old image, the new coordinate can be found by using this formula:

OldImageX = NewImageX * cos(theta) - NewImageY * sin(theta)
OldImageY = NewImageX * sin(theta) + NewImageY * cos(theta)

Let me try to clarify it.  You would use a loop for NewImageX and NewImageY (making it an independent variable), and for each of these get the OldImageX and OldImageY, extract the pixel from it, and plot it at NewImageX and NewImageY (does this make any sense?)

Scale works in almost the same way.  If you look at my code above you will see that it divides by the scale to get the old image coordinates.

I don't know what else I can tell you...any specific questions?

scrappy

0

Commented:
Hello scrapdog... 10x for clarifying things...

I have never worked with graphics and stuff and I'm planning to do so in the near future... I mean I'd have to find some interesting documents on how to work with the graphics and so on.... I have a few questions I'd like to ask you, though... The thing I really don't understand is how to rotate the pixel from one place to another, that is how to use cos() sin() what does it do to the pixel that is taken???

lets say we have a pixel  like so..

var
Pix : Byte;
begin
//What code do I need to rotate this pixel from one place to another??? take a look at scheme below
end;

This is like a sprite...

o -> pixel to move            c -> move pixel to here
o.......                                  ..........
........                                 ..........
........                                 ........c

what the code is going to be to move the pixel "o" to the same image but at the place of pixel "c"???

I hope you understand what I mean.,,,

Regards,
Viktor Ivanov

0

Commented:
You don't do anything with the pixel itself.  You only operate on it coordinates.

I will use the Cartesian coordinate system to simplify my explanation a bit.  Hopefully you are familiar with Cartesian coordinates.

First, lets say you are rotating 35 degrees.

In the destination image, let's say you want to get the pixel for (3,2).

.|...
.|... <-find pixel to place here
.|...
-------
.|...
.|...
.|...

Remember the formula:
OldImageX = NewImageX * cos(theta) - NewImageY * sin(theta)
OldImageY = NewImageX * sin(theta) + NewImageY * cos(theta)

OldImageX = 3 * cos(35 deg) - 2 * sin(35 deg)

3 * 0.819 - 2 * 0.574 = 2.457 - 1.148 = 1.309

OldImageY = 3 * sin(35 deg) + 2 * cos(35 deg)

3 * 0.574 + 2 * 0.819 = 1.722 + 1.638 = 3.36

So, the pixel will be taken from (1.309, 3.36) in the source image.

We have to round this off to (1,3).

.|*..
.|...
.|...
-------
.|...
.|...
.|...

The * is located at (1,3) in the source image.  So we take the color of the pixel that is located there, and place it in the destination image (the coordinates were (3,2)).

.|...
.|..* We now have the pixel from the source image
.|...
-------
.|...
.|...
.|...

That was only for one pixel.  We have to do it for the whole destination image.  So we do this one coordinate pair at a time until the destination image is full.

Just remember that the destination "extracts" from source, rather than source "copies" to destination.

Any clearer now?

scrappy
0

Commented:
Yup, it is getting clearer.... I'm pretty good in math but I don't know how to use that in programming..... How do you remmember all this stuff about cos() sin() tan() where to put it?? How do you know what the cos() for example or Sin() is gonna do to a coordinate or a value...or whatever...???  To clarify things, here is a summary of what I just said,,, How do you know what cos() is going to do for example to the coordinate (3,2) ... Man I want to learn these graphics so much but it seems to be difficult until you get the trick... 10x.. Would you please show me in a source code just a simple procedure that rotates an image as parameters to use the following...

procedure Rotate(SourceImg, DestImg : TImage; Angle : real);
begin
//the code??? . o O
end;

Can you show me an example program that draws a triangle...doesn't matter how big or what coordinates it has.... Then after it draws the original how it would mirror the triangle so the same triangle is drawn the opposite way..
.
.     .
........
........
.     .
.

Something like this thing above???

10x a lot for your time!

btw- How long did it take you to learn all this stuff???

Regards,
Viktor Ivanov
0

Commented:
Viktor:

1. Check out the thread on the Delphi board (How to rotate an image).  This thread is a few weeks old, so you might have to hunt a bit.  I just posted how to rotate one rectangle on a canvas to another rectangle in another canvas.  You could use plug Image1.Canvas into it if you wanted.

2. As much as I'd love to help you out with graphics programming, it is a huge domain and takes a lot of practice, so I don't know if I could teach you very efficiently in writing.  But if you ask me one question at a time I can try to answer them.  As far as your triangle question:

T1, T2, T3 are points (in Cartesian coordinates)

Line(T1.x, T1.y, T2.x, T2.y);
Line(T2.x, T2.y, T3.x, T3.y);
Line(T3.x, T3.y, T1.x, T1.y);

of course, Line is pseudocode.  (In Delphi you could use LineTo and MoveTo, etc.)

To mirror it, you could use the opposites of the points.

Line(T1.x, T1.y, T2.x, T2.y);
Line(T2.x, T2.y, -T3.x, -T3.y);
Line(-T3.x, -T3.y, T1.x, T1.y);

etc.

3.  To explain how Cos and Sin work would literally take hundreds of pages.  I would suggest a trigonometry course :)

4.  I don't know exactly how long it took to learn.  I just assimilated a little bit of it at a time over the last few years...I suppose I started learning this stuff the very first time I used Terrapin Logo (13 years ago).

scrap-doggy-dog

0

Commented:
Wow It seems like I need to eat a lot of food until I learn this stuff.... How old are you now??? I'm 16... I'm taking trigonometry now....so maybe I'd be able to learn some stuff in this year's math course... I knew how to do the tringle with LineTo() that was actually an example....but what I meant is do it pixel by pixel....

10x

Regards,
Viktor Ivanov
0

Commented:
I assume you mean *rotate* it pixel by pixel, because drawing it pixel by pixel would be very impractical :)

To flip it around, just pass it to the rotate function and rotate it 180 degrees.  Try my function I wrote in this thread (above).  Make a sprite containing a triangle, then do a trace to see how it works.

Scrapdog (22)

0

Commented:
ThanX I'll try that... I started programming three months ago so I don't feel like I'm much behind.... 10x for your help :-)

Regards,
Viktor Ivanov
0

Commented:
zup Viktor:

Just a little reflection 2 years later.  Reflecting back when you were just a naive little punk!

You really are the Lawn Mower Man.  How dare you surpass me in the top-100!

Punk!

Regards,
Scrapdog (24)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.