Solved

Rotate sprite in mcga

Posted on 1998-10-04
13
416 Views
Last Modified: 2010-04-16
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
Comment
Question by:hansell
  • 7
  • 5
13 Comments
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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
 
LVL 7

Expert Comment

by:Motaz
Comment Utility
Matrix multiplication is used to scale and rotate images.

Motaz
0
 
LVL 5

Accepted Solution

by:
scrapdog earned 70 total points
Comment Utility
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');
  readln;
  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');
  readln;
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}


Additional note
----------------
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
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
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
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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)

(theta is angle in radians)

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
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
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
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
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
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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
 
LVL 10

Expert Comment

by:viktornet
Comment Utility
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
 
LVL 5

Expert Comment

by:scrapdog
Comment Utility
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

HOW TO: Install and Configure VMware vSphere Hypervisor 6.5 (ESXi 6.5), Step by Step Tutorial with screenshots. From Download, Checking Media, to Completed Installation.
This article explains how to prepare an HTML email signature template file containing dynamic placeholders for users' Azure AD data. Furthermore, it explains how to use this file to remotely set up a department-wide email signature policy in Office …
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now