Sprite rotation and camera movement in libparallax?

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
Silent Marauder
DCEmu Fast Newbie
DCEmu Fast Newbie
Posts: 24
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Wed Jul 21, 2004 8:06 pm
Has thanked: 0
Been thanked: 0

Sprite rotation and camera movement in libparallax?

Post by Silent Marauder »

I've been looking for a way to do sprite rotation, but I can't seem to find out how to do it through libparallax. The plx/matrix.h headers are less than helpful, and what I've found on the boards here seems to only be useful if I were using the PVR API directly. So, how would I rotate a sprite using matrices in libparallax?

While I was looking in the plx/matrix.h file, I saw a few comments that referred to camera movement. Is it possible to set the position of (for example) background tiles once and then simply move the camera in order to scroll? That would make things much easier. By the same token, can the camera zoom in and out?
c99koder
DC Developer
DC Developer
Posts: 200
Joined: Wed Oct 17, 2001 7:44 pm
Location: East Windsor, NJ
Has thanked: 0
Been thanked: 0
Contact:

Post by c99koder »

It's essentially the same as doing it with OpenGL. Draw your sprites or polygons centered around 0, ex for 2D your quad gets draw from -1 to 1 on the X and -1 to 1 on the Y

(-1, -1) (1, -1)



(-1, 1) (1, 1)

Call plx_mat_translate() and plx_mat_rotate() to position and rotate your sprite before drawing it.

To position a "camera" you really move the scene in the opposite direction -- ex the 'camera' moving left is really just the scene moving right. To 'zoom' the camera, you can scale the scene with plx_mat3d_scale().

A typical drawing cycle would be:

for(however you iterate your sprites) {
plx_mat3d_identiy(); //reset the matrix
plx_mat3d_rotate(camera_xrot,1,0,0); //Rotate the scene relative to the camera's X rotation
plx_mat3d_rotate(camera_zrot,0,0,1); //Rotate the scene relative to the camera's Z rotation
plx_mat3d_rotate(camera_yrot,0,1,0); //Rotate the scene relative to the camera's Y rotation
plx_mat3d_translate(-camera_x,-camera_y,camera_z); //Position the scene relative to the camera
plx_mat3d_translate(sprite.x, sprite.y, -sprite.z); //Move out to where this sprite belongs
plx_mat3d_rotate(sprite.xrot,1,0,0,0); //Rotate the sprite along the X axis
plx_mat3d_rotate(sprite.yrot,1,0,0,0); //Rotate the sprite along the Y axis
plx_mat3d_rotate(sprite.zrot,1,0,0,0); //Rotate the sprite along the Z axis

plx_mat3d_apply_all(); //Not sure if this is needed, I don't usually use parallax

(draw your sprite, using plx_vert or whatever)
}

Note that this was adapted from the OpenGL renderer in DCBlap, which inverts the Z axis. You can swap the negative signs around if you want to set it back to normal.

You might want to look into using Tsunami, which is an OOP layer on top of parallax. Using Tsunami's banner class would look something like:

Banner *sprite = new Banner(new Texture("coolsonicsprite.png",0));
sprite->setPosition(Vector(10,20,0)); //Position our sprite at 10,20
sprite->setSize(30,40); //Make our banner 30 x 40
sprite->setRotate(Vector(0,0,90)); // Rotate our banner 90 degrees on the Z axis
sprite->setScale(Vector(2,0,0)); //Scale our banner by a factor of 2 on the X axis
....
for(however you're iterating your list of sprites) {
Frame::begin();
sprite->draw(Drawable::Opaque);
Frame::finish();
}

This is using the slightly newer syntax of Tiki, but it should be more-or-less compatible with tsunami too. Check out the tsunami examples in the kos tree or feel free to ask if you have more questions about it.

-Sam
Image
c99koder
DC Developer
DC Developer
Posts: 200
Joined: Wed Oct 17, 2001 7:44 pm
Location: East Windsor, NJ
Has thanked: 0
Been thanked: 0
Contact:

Post by c99koder »

If you want to implement a camera in Tsunami, you can create a layer object and add all your sprites onto that, then move the layer around opposite to the camera, as in the parallax example. I'll post an example of this tomorrow, I need to get some sleep now :P

-Sam
Image
c99koder
DC Developer
DC Developer
Posts: 200
Joined: Wed Oct 17, 2001 7:44 pm
Location: East Windsor, NJ
Has thanked: 0
Been thanked: 0
Contact:

Post by c99koder »

fine, now I can't sleep. Here's an example of several sprites with a 'camera'. I skimmed through the Banner example included with KOS, so this should more closely match Tsunami's syntax:

Code: Select all

RefPtr<Banner> sprites[3];  //RefPtr is a template class that provides a 'smarter' pointer that tracks its usage.  Banner is a class that draws a textured quad on the screen
float camera_x=3, camera_y=4, camera_z=10;
float camera_zoom=1.2;

sprites[0] = new Banner(PVR_LIST_TR_POLY, new Texture("coolsonicsprite.png",1)); // 1 = enable transparency, PVR_LIST_TR_POLY is the PVR's translucent poly list
sprites[0]->setSize(32,32);
sprites[0]->setRotate(Vector(0,0,15));
sprites[0]->setPosition(Vector(10,30,0));

sprites[1] = new Banner(PVR_LIST_TR_POLY, new Texture("cooltailssprite.png",1)); 
sprites[1]->setSize(32,32);
sprites[1]->setRotate(Vector(0,0,55));
sprites[1]->setPosition(Vector(40,30,0));

sprites[2] = new Banner(PVR_LIST_OP_POLY, new Texture("coolknucklessprite.png",0)); // 0 = no transparency.  PVR_LIST_OP_POLY is the PVR's opaque poly list
sprites[2]->setSize(32,32);
sprites[2]->setRotate(Vector(0,0,76));
sprites[2]->setPosition(Vector(10,60,0));

//Create a new Scene object
RefPtr<Scene> = new Scene();

//Add the sprites as sub-drawables
sc->subAdd(sprites[0]);
sc->subAdd(sprites[1]);
sc->subAdd(sprites[2]);

while(1) {
	pvr_wait_ready();
	pvr_scene_begin();
	pvr_list_begin(PVR_LIST_OP_POLY);

	sc->translate(Vector(-camera_x, -camera_y, -camera_z)); //Translate the scene opposite to the camera's position
	sc->setScale(Vector(camera_zoom,camera_zoom,camera_zoom)); //Zoom the camera

	// Draw the scene's opaque poly list
	sc->draw(PVR_LIST_OP_POLY);

	pvr_list_begin(PVR_LIST_TR_POLY);

	// Draw the scene's transparent poly list
	sc->draw(PVR_LIST_TR_POLY);

	pvr_scene_finish();
}
-Sam
Image
Silent Marauder
DCEmu Fast Newbie
DCEmu Fast Newbie
Posts: 24
Joined: Wed Jul 21, 2004 8:06 pm
Has thanked: 0
Been thanked: 0

Post by Silent Marauder »

Thanks a million! :D
Silent Marauder
DCEmu Fast Newbie
DCEmu Fast Newbie
Posts: 24
Joined: Wed Jul 21, 2004 8:06 pm
Has thanked: 0
Been thanked: 0

Post by Silent Marauder »

I just have a couple quick questions about your code:

Code: Select all

 plx_mat3d_rotate(sprite.xrot,1,0,0,0); //Rotate the sprite along the X axis
plx_mat3d_rotate(sprite.yrot,1,0,0,0); //Rotate the sprite along the Y axis
plx_mat3d_rotate(sprite.zrot,1,0,0,0); //Rotate the sprite along the Z axis
Is that supposed to have five parameters? I can't find a parallax function which takes five parameters, so I'm betting that it should be:

plx_mat3d_rotate(sprite.zrot, 0, 0, 1);

Also, I have to call plx_mat3d_init() at the start of the program and apparently set the matrix I'm using in plx_mat3d_mode(). Would I use PLX_MAT_MODELVIEW or PLX_MAT_SCRATCH, or does it even matter?

Thanks, even though you said you don't usually use libparallax :)
c99koder
DC Developer
DC Developer
Posts: 200
Joined: Wed Oct 17, 2001 7:44 pm
Location: East Windsor, NJ
Has thanked: 0
Been thanked: 0
Contact:

Post by c99koder »

D'oh, yes it should be 4 not 5 parameters. I got a bit carried away with the zeros at the end :-P

Code: Select all

	plx_mat3d_init();
	plx_mat3d_mode(PLX_MAT_PROJECTION);
	plx_mat3d_identity();
	plx_mat3d_perspective(45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
	plx_mat3d_mode(PLX_MAT_MODELVIEW);
Will set you up if you're using 3D, it seems to set itself up for 2D by default, so all you should need is plx_mat3d_init(); for that.

-Sam
Image
Silent Marauder
DCEmu Fast Newbie
DCEmu Fast Newbie
Posts: 24
Joined: Wed Jul 21, 2004 8:06 pm
Has thanked: 0
Been thanked: 0

Post by Silent Marauder »

I've got it working now! Thanks, c99, this really helps tremendously. I had to make a couple changes, but it works beautifully!

In case anybody else finds this thread later, here's the code:

Make sure you #include <plx/matrix.h>

Also you need to call plx_mat3d_init(); before you use any of the mat3d functions. I usually put this right after my pvr_init_defaults();

Here's how you do the actual transforms:

Code: Select all

//do this FOR EACH sprite you wish to draw as part of the 'camera' scene
//don't use this for stuff you want on a HUD, etc.

//all angles are in degrees

plx_mat3d_identity();
plx_mat3d_translate(screen_width / 2, screen_height / 2, 0);
plx_mat3d_scale(zoom_factor, zoom_factor, 0);
plx_mat3d_rotate(camera_angle_x, 1, 0, 0);
plx_mat3d_rotate(camera_angle_z, 0, 0, 1);
plx_mat3d_rotate(camera_angle_y, 0, 1, 0);
plx_mat3d_translate(-camera_pos_x, -camera_pos_y, 0);
plx_mat3d_translate(sprite_pos_x, sprite_pos_y, 0);
plx_mat3d_rotate(sprite_angle_x, 1, 0, 0);
plx_mat3d_rotate(sprite_angle_y, 0, 1, 0);
plx_mat3d_rotate(sprite_angle_z, 0, 0, 1);
plx_mat3d_scale(sprite_width / 2.0f, sprite_height / 2.0f, 1);

//draw the sprite using the PVR somehow, centering it on (0,0).
//The four corners should be (1,1) (1,-1) (-1,1) (-1,-1)
//I prefer to use plx_spr_fmd() because it takes care of everything for you.
//Just call it with the 2nd-5th parameters equal to 2.0f, 2.0f, 0, 0, respectively
zoom_factor is a float, where 1.0 = normal, 0.5 = zoom out 2x, 2.0 = zoom in 2x, etc.

The transforms are actually applied in reverse order, according to the comments in the KOS parallax examples. So the sprite is scaled first, and translated by half the screen width and height last.

I had to halve the width and height parameters in the sprite scale, because it turned out that the parameters multiply the poly's width and height - which in this case are 2.0f each. I also had to add a final translate in order to keep the center of the camera's view in the center of the screen.
Post Reply