Sprite rotation and camera movement in libparallax?
-
- 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?
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?
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?
-
- DC Developer
- Posts: 200
- Joined: Wed Oct 17, 2001 7:44 pm
- Location: East Windsor, NJ
- Has thanked: 0
- Been thanked: 0
- Contact:
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
(-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
-
- DC Developer
- Posts: 200
- Joined: Wed Oct 17, 2001 7:44 pm
- Location: East Windsor, NJ
- Has thanked: 0
- Been thanked: 0
- Contact:
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:
-Sam
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();
}
-
- DCEmu Fast Newbie
- Posts: 24
- Joined: Wed Jul 21, 2004 8:06 pm
- Has thanked: 0
- Been thanked: 0
-
- DCEmu Fast Newbie
- Posts: 24
- Joined: Wed Jul 21, 2004 8:06 pm
- Has thanked: 0
- Been thanked: 0
I just have a couple quick questions about your code:
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
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
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
-
- DC Developer
- Posts: 200
- Joined: Wed Oct 17, 2001 7:44 pm
- Location: East Windsor, NJ
- Has thanked: 0
- Been thanked: 0
- Contact:
D'oh, yes it should be 4 not 5 parameters. I got a bit carried away with the zeros at the end
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
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);
-Sam
-
- DCEmu Fast Newbie
- Posts: 24
- Joined: Wed Jul 21, 2004 8:06 pm
- Has thanked: 0
- Been thanked: 0
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:
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.
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
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.