Merge pull request #7 from n00b87/sprite_animation

Sprite animation
This commit is contained in:
Rodney Cunningham
2024-10-19 09:37:06 -04:00
committed by GitHub
62 changed files with 1548 additions and 403 deletions

8
doc/files/canvasz.txt Normal file
View File

@@ -0,0 +1,8 @@
#title CanvasZ [RCBasic Doc]
#header function CanvasZ(c_num)
Returns the Canvas Z Order.
Note: Canvases with a higher Z order are drawn first and those with lower values will be drawn on top
#ref SetCanvasZ

View File

@@ -0,0 +1,10 @@
#title CreatePlaneMesh [RCBasic Doc]
#header Function CreatePlaneMesh( w, h, tileCount_w, tileCount_h )
Creates a flat plane
#list
#li w, h - The width and height of the plane
#li tileCount_w, TileCount_h - The number of subdivisions across and down the plane
#/list

View File

@@ -0,0 +1,9 @@
#title CreateSpriteAnimation [RCBasic Doc]
#header Function CreateSpriteAnimation(sprite, anim_length, speed)
Returns a new sprite animation id
#list ul
#li anim_length - number of frames in the animation
#li speed - frames per second for the animation
#/list

View File

@@ -0,0 +1,4 @@
#title CreateWaterActor [RCBasic Doc]
#header function CreateWaterActor( mesh, waveHeight, waveSpeed, waveLength )
Creates an actor with water properties set on a base mesh

View File

@@ -0,0 +1,4 @@
#title GetAN8SceneName$ [RCBasic Doc]
#header Function GetAN8SceneName$(an8_project, scene_num)
Returns the name of a scene in an an8 project

View File

@@ -0,0 +1,6 @@
#title GetNumAN8Scenes [RCBasic Doc]
#header Function GetNumAN8Scenes(an8_project)
Returns the number of scenes in an an8 project
#ref LoadAN8

View File

@@ -0,0 +1,12 @@
#title GetProjectionMatrix [RCBasic Doc]
#header Sub GetProjectionMatrix(matA)
Gets the camera projection matrix for the active canvas
Possible values for projection_type
#list ul
#li PROJECTION_TYPE_ORTHOGRAPHIC
#li PROJECTION_TYPE_PERSPECTIVE
#/list
#ref SetProjectionMatrix

View File

@@ -0,0 +1,6 @@
#title GetSpriteAnimation [RCBasic Doc]
#header Function GetSpriteAnimation(sprite)
Returns the current animation set on a sprite
#ref SetSpriteAnimation

View File

@@ -0,0 +1,4 @@
#title GetSpriteAnimationFrame [RCBasic Doc]
#header Function GetSpriteAnimationFrame(sprite, animation, anim_frame)
Returns the frame index in the image source that is set to anim_frame in a sprite's animation

View File

@@ -0,0 +1,4 @@
#title GetSpriteAnimationLength [RCBasic Doc]
#header Function GetSpriteAnimationLength(sprite, animation)
Returns the number of frames in a sprite animation

View File

@@ -0,0 +1,4 @@
#title GetSpriteAnimationSpeed [RCBasic Doc]
#header Function GetSpriteAnimationSpeed(sprite, animation)
Returns the frames per second of a sprite animation

View File

@@ -0,0 +1,4 @@
#title GetSpriteCurrentAnimationFrame [RCBasic Doc]
#header Function GetSpriteCurrentAnimationFrame(sprite)
Returns the current frame of a sprite's animation

View File

@@ -0,0 +1,4 @@
#title GetSpriteFrame [RCBasic Doc]
#header Function GetSpriteFrame(sprite)
Returns the current frame in a sprite's source that it's on in its animation

View File

@@ -0,0 +1,6 @@
#title GetSpritePosition [RCBasic Doc]
#header Sub GetSpritePosition(sprite, ByRef x, ByRef y)
Gets the position of a sprite on the canvas
#ref TranslateSprite SetSpritePosition

View File

@@ -0,0 +1,6 @@
#title GetSpriteRotation [RCBasic Doc]
#header Function GetSpriteRotation(sprite)
Returns the angle the sprite is rotated by
#ref SetSpriteRotation RotateSprite

View File

@@ -0,0 +1,6 @@
#title GetSpriteScale [RCBasic Doc]
#header Sub GetSpriteScale(sprite, ByRef x, ByRef y)
Gets the scale of a sprite
#ref ScaleSprite SetSpriteScale

View File

@@ -0,0 +1,6 @@
#title GetSpriteSize [RCBasic Doc]
#header Sub GetSpriteSize(sprite, ByRef w, ByRef h)
Gets the size of a sprite's frames
#ref CreateSprite

View File

@@ -0,0 +1,6 @@
#title GetSpriteSource [RCBasic Doc]
#header Function GetSpriteSource(sprite)
Returns the source image the sprite renders its frames from
#ref SetSpriteSource CreateSprite

View File

@@ -0,0 +1,15 @@
#title GetSpriteType [RCBasic Doc]
#header Function GetSpriteType(sprite)
Returns the collison body type of a sprite.
By default, sprites are dynamic when they are created.
Possible types returned
#list ul
#li SPRITE_TYPE_STATIC
#li SPRITE_TYPE_KINEMATIC
#li SPRITE_TYPE_DYNAMIC
#/list
#ref SetSpriteType

View File

@@ -0,0 +1,4 @@
#title GetWorldToViewportPosition [RCBasic Doc]
#header Sub GetWorldToViewportPosition(x, y, z, ByRef x, ByRef y)
Get the 2D coordinates for the given 3D position on the active canvas

6
doc/files/loadan8.txt Normal file
View File

@@ -0,0 +1,6 @@
#title LoadAN8 [RCBasic Doc]
#header Function LoadAN8( an8_file$ )
Loads an an8 project and returns an id that can be used in LoadMeshFromAN8()
#ref LoadMeshFromAN8

View File

@@ -0,0 +1,8 @@
#title LoadMeshFromAN8 [RCBasic Doc]
#header Function LoadMeshFromAN8(an8_project, an8_scene$)
Loads the figures in an anim8or scene as a mesh
Note: This only loads figures from a scene and it loads meshes not anim8or objects
#ref LoadAN8 LoadMesh LoadMeshFromArchive

View File

@@ -0,0 +1,6 @@
#title NumSpriteAnimationLoops [RCBasic Doc]
#header Function NumSpriteAnimationLoops(sprite)
Returns the number of animation loops the actor has set
#ref SetSpriteAnimationLoops SetSpriteAnimation

8
doc/files/preupdate.txt Normal file
View File

@@ -0,0 +1,8 @@
#title PreUpdate [RCBasic Doc]
#header Sub PreUpdate( )
Processes physics for sprites and actors.
This is useful if you need to know the post solve positions and rotations prior to drawing them.
#ref Update

View File

@@ -0,0 +1,6 @@
#title RotateSprite [RCBasic Doc]
#header Sub RotateSprite(sprite, angle)
Sets the angle the sprite is rotated by relative to its current rotation
#ref SetSpriteRotation GetSpriteRotation

View File

@@ -0,0 +1,6 @@
#title ScaleSprite [RCBasic Doc]
#header Sub ScaleSprite(sprite, x, y)
Sets the scale of a sprite relative to its current scale
#ref SetSpriteScale GetSpriteScale

View File

@@ -0,0 +1,12 @@
#title SetCameraProjectionMatrix [RCBasic Doc]
#header Sub SetCameraProjectionMatrix(matA, projection_type)
Sets the camera projection matrix for the active canvas
Possible values for projection_type
#list ul
#li PROJECTION_TYPE_ORTHOGRAPHIC
#li PROJECTION_TYPE_PERSPECTIVE
#/list
#ref GetCameraProjectionMatrix

View File

@@ -3,6 +3,6 @@
Sets the Canvas Z Order.
Note: Canvases with a lower Z order are drawn first and those with higher values will be drawn on top
Note: Canvases with a higher Z order are drawn first and those with lower values will be drawn on top
#ref SetCanvasZ

View File

@@ -0,0 +1,12 @@
#title SetProjectionMatrix [RCBasic Doc]
#header Sub SetProjectionMatrix(matA, projection_type)
Sets the camera projection matrix for the active canvas
Possible values for projection_type
#list ul
#li PROJECTION_TYPE_ORTHOGRAPHIC
#li PROJECTION_TYPE_PERSPECTIVE
#/list
#ref GetProjectionMatrix

View File

@@ -0,0 +1,8 @@
#title SetSpriteAnimation [RCBasic Doc]
#header Sub SetSpriteAnimation(sprite, animation)
Sets the current animation for a sprite
Note: Once an animation is set, it will automatically start
#ref GetSpriteAnimation

View File

@@ -0,0 +1,6 @@
#title SetSpriteAnimationFrame [RCBasic Doc]
#header Sub SetSpriteAnimationFrame(sprite, animation, anim_frame, frame)
Sets a frame in a sprite animation
#ref GetSpriteAnimationFrame

View File

@@ -0,0 +1,6 @@
#title SetSpriteAnimationLength [RCBasic Doc]
#header Sub SetSpriteAnimationLength(sprite, animation, anim_length)
Sets the number of frames in a sprite animation
#ref GetSpriteAnimationLength

View File

@@ -0,0 +1,6 @@
#title SetSpriteAnimationLoops [RCBasic Doc]
#header Sub SetSpriteAnimationLoops(sprite, num_loops)
Sets the number of animation loops for the sprite
#ref NumSpriteAnimationLoops

View File

@@ -0,0 +1,4 @@
#title SetSpriteAnimationSpeed [RCBasic Doc]
#header Sub SetSpriteAnimationSpeed(sprite, animation, speed)
Sets the speed in frames per second for a sprite animation

View File

@@ -0,0 +1,4 @@
#title SetSpriteFrame [RCBasic Doc]
#header Sub SetSpriteFrame(sprite, frame)
Sets a sprite to a frame in its frame sheet

View File

@@ -0,0 +1,7 @@
#title SetSpriteRotation [RCBasic Doc]
#header Sub SetSpriteRotation(sprite, angle)
Sets the angle the sprite is rotated by
#ref GetSpriteRotation RotateSprite

View File

@@ -0,0 +1,6 @@
#title SetSpriteScale [RCBasic Doc]
#header Sub SetSpriteScale(sprite, x, y)
Sets the scale of a sprite
#ref ScaleSprite GetSpriteScale

View File

@@ -0,0 +1,7 @@
#title SetSpriteSolid [RCBasic Doc]
#header Sub SetSpriteSolid(sprite, flag)
Sets whether a sprite has physics and collision response enabled
#ref SpriteIsSolid

View File

@@ -0,0 +1,8 @@
#title SetSpriteSource [RCBasic Doc]
#header Sub SetSpriteSource(sprite, img)
Changes the image source for a sprite frame sheet
Note: This needs to be the same size as the current image source or you will have rendering issues
#ref GetSpriteSource

View File

@@ -0,0 +1,12 @@
#title SetSpriteType [RCBasic Doc]
#header Sub SetSpriteType(sprite, sprite_type)
Sets the type of collision body a sprite has
#list ul
#li SPRITE_TYPE_STATIC
#li SPRITE_TYPE_KINEMATIC
#li SPRITE_TYPE_DYNAMIC
#/list
#ref GetSpriteType

View File

@@ -0,0 +1,6 @@
#title SetSpriteVisible [RCBasic Doc]
#header Sub SetSpriteVisible(sprite, flag)
Sets whether the sprite is visible
#ref SpriteIsVisible

9
doc/files/setspritez.txt Normal file
View File

@@ -0,0 +1,9 @@
#title SetSpriteZ [RCBasic Doc]
#header Sub SetSpriteZ(sprite, z)
Sets the drawing priority for sprites.
Note: Sprites with a higher Z order are drawn first and those with lower values will be drawn on top
#ref SpriteZ

View File

@@ -0,0 +1,7 @@
#title SpriteHeight [RCBasic Doc]
#header Function SpriteHeight(sprite)
Returns the frame height of a sprite
#ref SpriteWidth GetSpriteSize

View File

@@ -0,0 +1,6 @@
#title SpriteIsSolid [RCBasic Doc]
#header Function SpriteIsSolid(sprite)
Returns true if a sprite is has physics and collision response enabled
#ref SetSpriteSolid

View File

@@ -0,0 +1,6 @@
#title SpriteIsVisible [RCBasic Doc]
#header Function SpriteIsVisible(sprite)
Returns whether the sprite is visible
#ref SetSpriteVisible

View File

@@ -0,0 +1,6 @@
#title SpriteWidth [RCBasic Doc]
#header Function SpriteWidth(sprite)
Returns the frame width of a sprite
#ref SpriteHeight GetSpriteSize

7
doc/files/spritex.txt Normal file
View File

@@ -0,0 +1,7 @@
#title SpriteX [RCBasic Doc]
#header Function SpriteX(sprite)
Returns the X position of a sprite on a canvas
#ref SpriteY SetSpritePosition GetSpritePosition

6
doc/files/spritey.txt Normal file
View File

@@ -0,0 +1,6 @@
#title SpriteY [RCBasic Doc]
#header Function SpriteY(sprite)
Returns the Y position of a sprite on a canvas
#ref SpriteX SetSpritePosition GetSpritePosition

8
doc/files/spritez.txt Normal file
View File

@@ -0,0 +1,8 @@
#title SpriteZ [RCBasic Doc]
#header Function SpriteZ(sprite)
Returns the drawing priority for sprites.
Note: Sprites with a higher Z order are drawn first and those with lower values will be drawn on top
#ref SetSpriteZ

7
doc/files/textheight.txt Normal file
View File

@@ -0,0 +1,7 @@
#title TextHeight [RCBasic Doc]
#header function TextHeight(txt$)
The height of text rendered with the active font
#ref TextWidth GetTextSize

6
doc/files/textwidth.txt Normal file
View File

@@ -0,0 +1,6 @@
#title TextWidth [RCBasic Doc]
#header function TextWidth(txt$)
The width of text rendered with the active font
#ref TextHeight GetTextSize

View File

@@ -0,0 +1,8 @@
#title TranslateSprite [RCBasic Doc]
#header Sub TranslateSprite(sprite, x, y)
Move a sprite relative to its current position
Note: This function sets the position of a sprite without regards to physics properties so it will not trigger collision detection or collision response.
#ref SetSpritePosition GetSpritePosition

Binary file not shown.

View File

@@ -1238,6 +1238,10 @@ string rc_keywordToken(string sline)
return "<num>19";
else if(sline.compare("MD2_ANIMATION_BOOM")==0)
return "<num>20";
else if(sline.compare("PROJECTION_TYPE_ORTHOGRAPHIC")==0)
return "<num>0";
else if(sline.compare("PROJECTION_TYPE_PERSPECTIVE")==0)
return "<num>1";
else if(sline.compare("SPRITE_TYPE_STATIC")==0)
return "<num>0";
else if(sline.compare("SPRITE_TYPE_KINEMATIC")==0)

View File

@@ -1577,8 +1577,6 @@ bool rc_free_type(rc_usrId* parent)
rc_usrId* p_obj;
uint64_t field_size = 0;
for(uint64_t i = 0; i < dim_size; i++)
{
p_obj = &parent->uid_value[i];
@@ -1968,7 +1966,7 @@ void for_117(uint64_t nid, int n1, int n2, int n3)
//These 3 lines reads the line value passed by the compiler
//This line value is the address of the end of the loop
unsigned rcbasic_cmd = segment[current_segment][current_address];
//unsigned rcbasic_cmd = segment[current_segment][current_address];
current_address++;
uint64_t for_end_addr = readInt();
@@ -2273,8 +2271,6 @@ void rc_type_array_copy(rc_usrId* src, rc_usrId* dst)
rc_usrId* p_obj;
uint64_t field_size = 0;
rc_usrId* s_obj;
//cout << "starting field: " << endl;
@@ -3137,7 +3133,7 @@ void obj_usr_init1_185(int u1, int n1)
void obj_usr_init2_186(int u1, int n1, int n2)
{
uint64_t d[3];
//uint64_t d[3];
//cout << "obj_usr_init2: u" << u1 << " --dim=[" << d[0] << ", " << d[1] << ", " << d[2] << "]" << endl;
usr_object.index = (uint64_t)vm_n[n1].value * vm_u[u1].dim[1] + (uint64_t)vm_n[n2].value;
usr_object.obj_ref = &vm_u[u1].var_ref->uid_value[usr_object.index];
@@ -3161,7 +3157,6 @@ bool rc_preset_type(rc_usrId* parent)
rc_usrId* p_obj;
uint64_t field_size = 0;
for(uint64_t i = 0; i < dim_size; i++)
{

View File

@@ -1371,7 +1371,7 @@ case FN_ReadInput_ToggleBackspace: //Sub Procedure
rc_readInput_ToggleBackspace( READINPUT_TOGGLEBACKSPACE_FLAG );
break;
case FN_CreateSprite: //Number Function
rc_push_num(rc_createSprite( CREATESPRITE_IMG ));
rc_push_num(rc_createSprite( CREATESPRITE_IMG, 0, 0 ));
break;
case FN_DeleteSprite: //Sub Procedure
rc_deleteSprite( DELETESPRITE_SPRITE );

View File

@@ -26,6 +26,7 @@
#include "rc_utf8.h"
#include <box2d/box2d.h>
#include "rc_sprite2D.h"
#include "rc_spritelib.h"
#include <irrtheora.h>
using namespace irr;
@@ -913,12 +914,14 @@ int rc_canvasOpen(int w, int h, int vx, int vy, int vw, int vh, int mode, int ca
canvas.physics2D.world = NULL;
if(canvas_type == RC_CANVAS_TYPE_SPRITE)
{
b2Vec2 gravity(0, -9.8);
b2Vec2 gravity(0, 0);
canvas.physics2D.world = new b2World(gravity);
canvas.physics2D.timeStep = 1/20.0; //the length of time passed to simulate (seconds)
canvas.physics2D.timeStep = 1/60.0; //the length of time passed to simulate (seconds)
canvas.physics2D.velocityIterations = 8; //how strongly to correct velocity
canvas.physics2D.positionIterations = 3; //how strongly to correct position
canvas.physics2D.enabled = true;
canvas.physics2D.contact_listener = new rc_contactListener_obj();
canvas.physics2D.world->SetContactListener(canvas.physics2D.contact_listener);
}
switch(mode)
@@ -1309,13 +1312,33 @@ int rc_cloneCanvas(int origin_canvas_id, int mode)
return canvas_id;
}
void rc_getWorldToViewportPosition(double x, double y, double z, double* vx, double* vy)
{
if(!VideoDriver)
return;
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
if(!rc_canvas[rc_active_canvas].texture)
return;
if(!rc_canvas[rc_active_canvas].camera.camera)
return;
irr::scene::ISceneCollisionManager* collman = SceneManager->getSceneCollisionManager();
irr::core::vector2di vpos = collman->getScreenCoordinatesFrom3DPosition(irr::core::vector3df(x, y, z), rc_canvas[rc_active_canvas].camera.camera);
*vx = vpos.X;
*vy = vpos.Y;
}
void rc_setClearColor(Uint32 color)
{
rc_clear_color.set(color);
}
Uint32 rc_rgba(Uint32 r, Uint32 g, Uint32 b, Uint32 a)
{
irr::video::SColor color(a, r, g, b);
@@ -1364,7 +1387,7 @@ Uint32 rc_getPixel(int x, int y)
irr::video::SColor * texel = (SColor *)(texels + ((y * pitch) + (x * sizeof(SColor))));
irr::video::SColor c = texel[0];
//irr::video::SColor c = texel[0];
texture->unlock();
@@ -2137,18 +2160,6 @@ void rc_readInput_ToggleBackspace(bool flag)
}
struct rc_image_obj
{
irr::video::ITexture* image;
Uint8 alpha = 255;
irr::video::SColor color_mod = irr::video::SColor(255,255,255,255);
};
irr::core::array<rc_image_obj> rc_image;
irr::video::E_BLEND_OPERATION rc_blend_mode = irr::video::EBO_ADD;
bool rc_bilinear_filter = false;
int rc_loadImageEx(std::string img_file, Uint32 color_key = 0, bool use_color_key = true)
{
rc_image_obj img;
@@ -2334,187 +2345,6 @@ int rc_getBlendMode()
return (int)rc_blend_mode;
}
void draw2DImage(irr::video::IVideoDriver *driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::position2d<irr::s32> position, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, irr::core::vector2df scale, bool useAlphaChannel, irr::video::SColor color, irr::core::vector2d<irr::f32> screenSize)
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
// Store and clear the projection matrix
irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
// Store and clear the view matrix
irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
// Store and clear the world matrix
irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
// Find horizontal and vertical axes after rotation
irr::f32 c = cos(-rotation*irr::core::DEGTORAD);
irr::f32 s = sin(-rotation*irr::core::DEGTORAD);
irr::core::vector2df horizontalAxis(c,s);
irr::core::vector2df verticalAxis(s,-c);
// First, we'll find the offset of the center and then where the center would be after rotation
irr::core::vector2df centerOffset(position.X+sourceRect.getWidth()/2.0f*scale.X-rotationPoint.X,position.Y+sourceRect.getHeight()/2.0f*scale.Y-rotationPoint.Y);
irr::core::vector2df center = centerOffset.X*horizontalAxis - centerOffset.Y*verticalAxis;
center.X += rotationPoint.X;
center.Y += rotationPoint.Y;
// Now find the corners based off the center
irr::core::vector2df cornerOffset(sourceRect.getWidth()*scale.X/2.0f,sourceRect.getHeight()*scale.Y/2.0f);
verticalAxis *= cornerOffset.Y;
horizontalAxis *= cornerOffset.X;
irr::core::vector2df corner[4];
corner[0] = center + verticalAxis - horizontalAxis;
corner[1] = center + verticalAxis + horizontalAxis;
corner[2] = center - verticalAxis - horizontalAxis;
corner[3] = center - verticalAxis + horizontalAxis;
// Find the uv coordinates of the sourceRect
irr::core::vector2df textureSize(texture->getSize().Width, texture->getSize().Height);
irr::core::vector2df uvCorner[4];
uvCorner[0] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[1] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[2] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.LowerRightCorner.Y);
uvCorner[3] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.LowerRightCorner.Y);
for (irr::s32 i = 0; i < 4; i++)
uvCorner[i] /= textureSize;
// Vertices for the image
irr::video::S3DVertex vertices[4];
irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
// Convert pixels to world coordinates
//irr::core::vector2df screenSize(rc_canvas[rc_active_canvas].dimension.Width, rc_canvas[rc_active_canvas].dimension.Height);
for (irr::s32 i = 0; i < 4; i++) {
vertices[i].Pos = irr::core::vector3df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
vertices[i].TCoords = uvCorner[i];
vertices[i].Color = color;
}
// Create the material
// IMPORTANT: For irrlicht 1.8 and above you MUST ADD THIS LINE:
// material.BlendOperation = irr::video::EBO_ADD;
irr::video::SMaterial material;
material.Lighting = false;
material.ZWriteEnable = irr::video::EZW_OFF;
material.ZBuffer = false;
material.BackfaceCulling = false;
material.TextureLayer[0].Texture = texture;
material.TextureLayer[0].BilinearFilter = rc_bilinear_filter;
material.MaterialTypeParam = irr::video::pack_textureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR);
material.BlendOperation = rc_blend_mode;
//material.BlendOperation = irr::video::EBO_ADD;
if (useAlphaChannel)
material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
else
material.MaterialType = irr::video::EMT_SOLID;
driver->setMaterial(material);
driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
// Restore projection, world, and view matrices
driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
void draw2DImage2(irr::video::IVideoDriver *driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::rect<irr::s32> destRect, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, bool useAlphaChannel, irr::video::SColor color, irr::core::vector2d<irr::f32> screenSize )
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
// Store and clear the projection matrix
irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
// Store and clear the view matrix
irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
// Store and clear the world matrix
irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
// Find horizontal and vertical axes after rotation
irr::f32 c = cos(-rotation*irr::core::DEGTORAD);
irr::f32 s = sin(-rotation*irr::core::DEGTORAD);
irr::core::vector2df horizontalAxis(c,s);
irr::core::vector2df verticalAxis(s,-c);
// First, we'll find the offset of the center and then where the center would be after rotation
irr::core::vector2df centerOffset(destRect.UpperLeftCorner.X+destRect.getWidth()/2.0f-rotationPoint.X,destRect.UpperLeftCorner.Y+destRect.getHeight()/2.0f-rotationPoint.Y);
irr::core::vector2df center = centerOffset.X*horizontalAxis - centerOffset.Y*verticalAxis;
center.X += rotationPoint.X;
center.Y += rotationPoint.Y;
// Now find the corners based off the center
irr::core::vector2df cornerOffset(destRect.getWidth()/2.0f,destRect.getHeight()/2.0f);
verticalAxis *= cornerOffset.Y;
horizontalAxis *= cornerOffset.X;
irr::core::vector2df corner[4];
corner[0] = center + verticalAxis - horizontalAxis;
corner[1] = center + verticalAxis + horizontalAxis;
corner[2] = center - verticalAxis - horizontalAxis;
corner[3] = center - verticalAxis + horizontalAxis;
// Find the uv coordinates of the sourceRect
irr::core::vector2df textureSize(texture->getSize().Width, texture->getSize().Height);
irr::core::vector2df uvCorner[4];
uvCorner[0] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[1] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[2] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.LowerRightCorner.Y);
uvCorner[3] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.LowerRightCorner.Y);
for (irr::s32 i = 0; i < 4; i++)
uvCorner[i] /= textureSize;
// Vertices for the image
irr::video::S3DVertex vertices[4];
irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
// Convert pixels to world coordinates
//irr::core::vector2df screenSize(rc_canvas[rc_active_canvas].dimension.Width, rc_canvas[rc_active_canvas].dimension.Height);
for (irr::s32 i = 0; i < 4; i++) {
vertices[i].Pos = irr::core::vector3df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
vertices[i].TCoords = uvCorner[i];
vertices[i].Color = color;
}
// Create the material
// IMPORTANT: For irrlicht 1.8 and above you MUST ADD THIS LINE:
// material.BlendOperation = irr::video::EBO_ADD;
irr::video::SMaterial material;
material.Lighting = false;
material.ZWriteEnable = irr::video::EZW_OFF;
material.ZBuffer = false;
material.BackfaceCulling = false;
material.TextureLayer[0].Texture = texture;
material.TextureLayer[0].BilinearFilter = rc_bilinear_filter; //TODO: Add option to switch this on/off
material.BlendOperation = rc_blend_mode;
material.MaterialTypeParam = irr::video::pack_textureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR);
//material.AntiAliasing = irr::video::EAAM_OFF;
if (useAlphaChannel)
material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
else
material.MaterialType = irr::video::EMT_SOLID;
driver->setMaterial(material);
driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
// Restore projection, world, and view matrices
driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
void rc_drawImage(int img_id, int x, int y)
{
if(img_id < 0 || img_id >= rc_image.size())
@@ -3168,196 +2998,6 @@ int rc_canvasClip(int x, int y, int w, int h)
//------------------------------SPRITES-------------------------------------------------------
int rc_createSprite(int img_id)
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return -1;
if(rc_canvas[rc_active_canvas].type != RC_CANVAS_TYPE_SPRITE)
return -1;
//std::cout << "debug 1" << std::endl;
int spr_id = -1;
for(int i = 0; i < rc_sprite.size(); i++)
{
if(!rc_sprite[i].active)
{
spr_id = i;
break;
}
}
if(spr_id < 0)
{
spr_id = rc_sprite.size();
rc_sprite2D_obj sprite;
rc_sprite.push_back(sprite);
}
rc_sprite[spr_id].active = true;
rc_sprite[spr_id].image_id = img_id;
b2BodyDef sprBodyDef;
sprBodyDef.type = b2_staticBody;
sprBodyDef.position.Set(0, 0);
sprBodyDef.angle = 0;
rc_sprite[spr_id].physics.body = rc_canvas[rc_active_canvas].physics2D.world->CreateBody(&sprBodyDef);
rc_sprite[spr_id].physics_enabled = false;
rc_sprite[spr_id].visible = true;
rc_sprite[spr_id].scale.set(1.0, 1.0);
rc_sprite[spr_id].position.set(0, 0);
rc_sprite[spr_id].alpha = 255;
rc_sprite[spr_id].rotation = 0;
rc_sprite[spr_id].z = 0;
rc_sprite[spr_id].color_mod.set(255,255,255,255);
rc_sprite[spr_id].parent_canvas = rc_active_canvas;
rc_canvas[rc_active_canvas].sprite.push_back(&rc_sprite[spr_id]);
return spr_id;
}
void rc_deleteSprite(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(rc_sprite[spr_id].physics.body)
{
if(rc_sprite[spr_id].parent_canvas >= 0 && rc_sprite[spr_id].parent_canvas < rc_canvas.size())
{
if(rc_canvas[rc_sprite[spr_id].parent_canvas].physics2D.world)
rc_canvas[rc_sprite[spr_id].parent_canvas].physics2D.world->DestroyBody(rc_sprite[spr_id].physics.body);
}
rc_sprite[spr_id].physics.body = NULL;
}
rc_sprite[spr_id].active = false;
rc_sprite[spr_id].parent_canvas = -1;
for(int i = 0; i < rc_canvas[rc_active_canvas].sprite.size(); i++)
{
rc_sprite2D_obj* canvas_sprite = rc_canvas[rc_active_canvas].sprite[i];
rc_sprite2D_obj* global_sprite = &rc_sprite[spr_id];
if(canvas_sprite == global_sprite)
{
rc_canvas[rc_active_canvas].sprite.erase(i);
break;
}
}
}
void rc_setSpriteType(int spr_id, int body_type)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].physics.body->SetType((b2BodyType) body_type);
}
void rc_setSpritePosition(int spr_id, double x, double y)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
float current_angle = rc_sprite[spr_id].physics.body->GetAngle();
rc_sprite[spr_id].physics.body->SetTransform(b2Vec2(x, y), current_angle);
}
//This function is called on each canvas on update
void drawSprites(int canvas_id)
{
float step = rc_canvas[canvas_id].physics2D.timeStep;
int32 velocityIterations = rc_canvas[canvas_id].physics2D.velocityIterations;
int32 positionIterations = rc_canvas[canvas_id].physics2D.positionIterations;
if(rc_canvas[canvas_id].physics2D.enabled)
rc_canvas[canvas_id].physics2D.world->Step(step, velocityIterations, positionIterations);
//Setting the render target to the current canvas. NOTE: I might change this target to a separate sprite layer later.
VideoDriver->setRenderTarget(rc_canvas[canvas_id].texture, false, false);
irr::core::dimension2d<irr::u32> src_size;
irr::core::rect<irr::s32> sourceRect;
irr::core::position2d<irr::s32> position;
irr::core::position2d<irr::s32> rotationPoint;
irr::f32 rotation = 0;
irr::core::vector2df scale(1.0, 1.0);
bool useAlphaChannel = true;
irr::video::SColor color;
//irr::core::rect<irr::s32> dest( irr::core::vector2d(x, y), irr::core::dimension2d(src_w, src_h));;
irr::core::vector2df screenSize(rc_canvas[canvas_id].dimension.Width, rc_canvas[canvas_id].dimension.Height);
int x = 0;
int y = 0;
b2Vec2 physics_pos;
irr::f32 RAD_TO_DEG = 180.0/3.141592653589793238463;
for(int spr_index = 0; spr_index < rc_canvas[canvas_id].sprite.size(); spr_index++)
{
rc_sprite2D_obj* sprite = rc_canvas[canvas_id].sprite[spr_index];
if(!sprite->visible)
continue;
int img_id = sprite->image_id;
if(img_id < 0 || img_id >= rc_image.size())
continue;
src_size = rc_image[img_id].image->getSize();
sourceRect = irr::core::rect<irr::s32>( irr::core::vector2d<irr::s32>(0, 0), src_size);
physics_pos = sprite->physics.body->GetPosition();
x = (int)physics_pos.x;
y = (int)physics_pos.y;
position.set(x, y);
rotationPoint.set(x + (src_size.Width/2), y + (src_size.Height/2));
rotation = -1 * (sprite->physics.body->GetAngle() * RAD_TO_DEG); //convert Box2D radians to degrees
scale.set(sprite->scale.X, sprite->scale.Y);
color.set(sprite->alpha,
sprite->color_mod.getRed(),
sprite->color_mod.getGreen(),
sprite->color_mod.getBlue());
draw2DImage(VideoDriver, rc_image[img_id].image, sourceRect, position, rotationPoint, rotation, scale, useAlphaChannel, color, screenSize);
}
//Must set back to canvas 0 (the backbuffer) before returning
VideoDriver->setRenderTarget(rc_canvas[0].texture, false, false);
}
//NOTE TO TBIRD
// 1. Each sprite has a Box2D body. You can look in "rc_sprite2D.h" to see how a sprite is structured.
// 2. A box2D world is setup for each canvas. So a sprite will be attached to the canvas thats active when its created. When that canvas is destroyed, so is the sprite.
// 3. By default, I have the sprite.physics_enabled attribute set to false. I feel like it makes sense to have a user intentionally enable physics since a user may not want physics for every sprite.
// 4. The sprite.visible attribute only determines whether to draw the sprite. The physics simulation will still happen each frame unless physics are disabled.
// 5. Don't change the value of sprite.active. Its used to check whether a sprite exists or not. I have an array of sprites in rc_sprite2D.h and if the active attribute is set to false, I reuse that slot to create a new sprite. If there is no inactive sprites in the array then I add a new sprite index to the array.
// 6. The time step, velocity Iterations, and position iterations are part of the canvas.physics2D attribute. You will need to make functions to allow the user to change those.
// 7. If you want to modify how sprites are rendered then you can just change the drawSprites() function above these notes.
//-----------------------------END OF SPRITE STUFF------------------------------------------------------------------------------
bool rc_update()
{

View File

@@ -2861,6 +2861,8 @@ double rc_computeActorImpulseDenominator(int actor, double pos_x, double pos_y,
{
return rc_actor[actor].physics.rigid_body->computeImpulseDenominator(irr::core::vector3df(pos_x, pos_y, pos_z), irr::core::vector3df(normal_x, normal_y, normal_z));
}
return 0;
}
double rc_computeActorAngularImpulseDenominator(int actor, double x, double y, double z)
@@ -2872,6 +2874,8 @@ double rc_computeActorAngularImpulseDenominator(int actor, double x, double y, d
{
return rc_actor[actor].physics.rigid_body->computeAngularImpulseDenominator(irr::core::vector3df(x, y, z));
}
return 0;
}
void rc_setActorAngularFactor(int actor, double x, double y, double z)
@@ -3016,6 +3020,8 @@ int rc_createPointConstraintEx(int actorA, int actorB, double pxA, double pyA, d
rc_physics3D.constraints[constraint_id] = p2p;
return constraint_id;
}
return -1;
}
void rc_setPointPivotA(int constraint_id, double x, double y, double z)
@@ -3062,6 +3068,8 @@ int rc_createHingeConstraint(int actorA, int frameInA_matrix, bool useReferenceF
rc_physics3D.constraints[constraint_id] = hinge;
return constraint_id;
}
return -1;
}
@@ -3088,6 +3096,8 @@ int rc_createHingeConstraintEx(int actorA, int actorB, int frameInA_matrix, int
rc_physics3D.constraints[constraint_id] = hinge;
return constraint_id;
}
return -1;
}
int rc_createSlideConstraint(int actorA, int frameInB_matrix, bool useLinearReferenceFrameA)
@@ -3110,6 +3120,8 @@ int rc_createSlideConstraint(int actorA, int frameInB_matrix, bool useLinearRefe
rc_physics3D.constraints[constraint_id] = slide;
return constraint_id;
}
return -1;
}
int rc_createSlideConstraintEx(int actorA, int actorB, int frameInA_matrix, int frameInB_matrix, bool useLinearReferenceFrameA)
@@ -3135,6 +3147,8 @@ int rc_createSlideConstraintEx(int actorA, int actorB, int frameInA_matrix, int
rc_physics3D.constraints[constraint_id] = slide;
return constraint_id;
}
return -1;
}
@@ -3159,6 +3173,8 @@ int rc_createConeConstraint(int actorA, int rbAFrame_matrix)
rc_physics3D.constraints[constraint_id] = cone;
return constraint_id;
}
return -1;
}
int rc_createConeConstraintEx(int actorA, int actorB, int rbAFrame_matrix, int rbBFrame_matrix)
@@ -3184,6 +3200,8 @@ int rc_createConeConstraintEx(int actorA, int actorB, int rbAFrame_matrix, int r
rc_physics3D.constraints[constraint_id] = cone;
return constraint_id;
}
return -1;
}
void rc_deleteConstraint(int constraint_id)
@@ -5069,7 +5087,7 @@ void rc_setActorFrame(int actor, int frame)
void rc_setActorAutoCulling(int actor, int cull_type)
{
if(actor < 0 || actor >= rc_actor.size())
return;
return;
rc_actor[actor].mesh_node->setAutomaticCulling((irr::scene::E_CULLING_TYPE) cull_type);
}
@@ -5089,7 +5107,7 @@ int rc_getActorAutoCulling(int actor)
void rc_addActorShadow(int actor)
{
if(actor < 0 || actor >= rc_actor.size())
return;
return;
if(rc_actor[actor].shadow)
return;
@@ -6699,6 +6717,37 @@ double rc_getCameraNearValue()
return rc_canvas[rc_active_canvas].camera.camera->getNearValue();
}
void rc_setCameraProjectionMatrix(int proj_matrix, int proj_type)
{
if(!(rc_active_canvas > 0 && rc_active_canvas < rc_canvas.size()))
return;
if(proj_matrix < 0 || proj_matrix >= rc_matrix.size())
return;
if(!rc_matrix[proj_matrix].active)
return;
irr::core::matrix4 irr_mat = rc_convertToIrrMatrix(proj_matrix);
bool isOrtho = (proj_type == RC_PROJECTION_TYPE_ORTHOGRAPHIC);
rc_canvas[rc_active_canvas].camera.camera->setProjectionMatrix(irr_mat, isOrtho);
}
void rc_getCameraProjectionMatrix(int proj_matrix)
{
if(!(rc_active_canvas > 0 && rc_active_canvas < rc_canvas.size()))
return;
if(proj_matrix < 0 || proj_matrix >= rc_matrix.size())
return;
if(!rc_matrix[proj_matrix].active)
return;
irr::core::matrix4 pmat = rc_canvas[rc_active_canvas].camera.camera->getProjectionMatrix();
rc_convertFromIrrMatrix(pmat, proj_matrix);
}
void rc_addSceneSkyBox(int img_top, int img_bottom, int img_left, int img_right, int img_front, int img_back)
{

View File

@@ -283,10 +283,30 @@ struct rc_physicsWorld3D_obj
rc_physicsWorld3D_obj rc_physics3D;
//Canvases
class rc_contactListener_obj : public b2ContactListener
{
void BeginContact(b2Contact* contact)
{
rc_sprite2D_obj* spriteA = (rc_sprite2D_obj*) contact->GetFixtureA()->GetBody()->GetUserData().pointer;
rc_sprite2D_obj* spriteB = (rc_sprite2D_obj*) contact->GetFixtureB()->GetBody()->GetUserData().pointer;
//std::cout << "sprite[" << spriteA->id << "] collide with sprite[" << spriteB->id << "]" << std::endl;
}
void EndContact(b2Contact* contact)
{
}
};
struct rc_physicsWorld2D_obj
{
bool enabled = false;
b2World* world;
rc_contactListener_obj* contact_listener;
float timeStep = 1/20.0; //the length of time passed to simulate (seconds)
int velocityIterations = 8; //how strongly to correct velocity
int positionIterations = 3; //how strongly to correct position
@@ -296,6 +316,9 @@ struct rc_physicsWorld2D_obj
#define RC_CANVAS_TYPE_3D 1
#define RC_CANVAS_TYPE_SPRITE 2
#define RC_PROJECTION_TYPE_ORTHOGRAPHIC 0
#define RC_PROJECTION_TYPE_PERSPECTIVE 1
struct rc_canvas_obj
{
irr::video::ITexture* texture;
@@ -618,4 +641,199 @@ void printIrrMatrix(irr::core::matrix4 m)
std::cout << "[ " << m[i*4] << ", " << m[i*4+1] << ", " << m[i*4+2] << ", " << m[i*4+3] << " ]" << std::endl;
}
struct rc_image_obj
{
irr::video::ITexture* image;
Uint8 alpha = 255;
irr::video::SColor color_mod = irr::video::SColor(255,255,255,255);
};
irr::core::array<rc_image_obj> rc_image;
irr::video::E_BLEND_OPERATION rc_blend_mode = irr::video::EBO_ADD;
bool rc_bilinear_filter = false;
void draw2DImage(irr::video::IVideoDriver *driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::position2d<irr::s32> position, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, irr::core::vector2df scale, bool useAlphaChannel, irr::video::SColor color, irr::core::vector2d<irr::f32> screenSize)
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
// Store and clear the projection matrix
irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
// Store and clear the view matrix
irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
// Store and clear the world matrix
irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
// Find horizontal and vertical axes after rotation
irr::f32 c = cos(-rotation*irr::core::DEGTORAD);
irr::f32 s = sin(-rotation*irr::core::DEGTORAD);
irr::core::vector2df horizontalAxis(c,s);
irr::core::vector2df verticalAxis(s,-c);
// First, we'll find the offset of the center and then where the center would be after rotation
irr::core::vector2df centerOffset(position.X+sourceRect.getWidth()/2.0f*scale.X-rotationPoint.X,position.Y+sourceRect.getHeight()/2.0f*scale.Y-rotationPoint.Y);
irr::core::vector2df center = centerOffset.X*horizontalAxis - centerOffset.Y*verticalAxis;
center.X += rotationPoint.X;
center.Y += rotationPoint.Y;
// Now find the corners based off the center
irr::core::vector2df cornerOffset(sourceRect.getWidth()*scale.X/2.0f,sourceRect.getHeight()*scale.Y/2.0f);
verticalAxis *= cornerOffset.Y;
horizontalAxis *= cornerOffset.X;
irr::core::vector2df corner[4];
corner[0] = center + verticalAxis - horizontalAxis;
corner[1] = center + verticalAxis + horizontalAxis;
corner[2] = center - verticalAxis - horizontalAxis;
corner[3] = center - verticalAxis + horizontalAxis;
// Find the uv coordinates of the sourceRect
irr::core::vector2df textureSize(texture->getSize().Width, texture->getSize().Height);
irr::core::vector2df uvCorner[4];
uvCorner[0] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[1] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[2] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.LowerRightCorner.Y);
uvCorner[3] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.LowerRightCorner.Y);
for (irr::s32 i = 0; i < 4; i++)
uvCorner[i] /= textureSize;
// Vertices for the image
irr::video::S3DVertex vertices[4];
irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
// Convert pixels to world coordinates
//irr::core::vector2df screenSize(rc_canvas[rc_active_canvas].dimension.Width, rc_canvas[rc_active_canvas].dimension.Height);
for (irr::s32 i = 0; i < 4; i++) {
vertices[i].Pos = irr::core::vector3df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
vertices[i].TCoords = uvCorner[i];
vertices[i].Color = color;
}
// Create the material
// IMPORTANT: For irrlicht 1.8 and above you MUST ADD THIS LINE:
// material.BlendOperation = irr::video::EBO_ADD;
irr::video::SMaterial material;
material.Lighting = false;
material.ZWriteEnable = irr::video::EZW_OFF;
material.ZBuffer = false;
material.BackfaceCulling = false;
material.TextureLayer[0].Texture = texture;
material.TextureLayer[0].BilinearFilter = rc_bilinear_filter;
material.MaterialTypeParam = irr::video::pack_textureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR);
material.BlendOperation = rc_blend_mode;
//material.BlendOperation = irr::video::EBO_ADD;
if (useAlphaChannel)
material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
else
material.MaterialType = irr::video::EMT_SOLID;
driver->setMaterial(material);
driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
// Restore projection, world, and view matrices
driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
void draw2DImage2(irr::video::IVideoDriver *driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::rect<irr::s32> destRect, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, bool useAlphaChannel, irr::video::SColor color, irr::core::vector2d<irr::f32> screenSize )
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
// Store and clear the projection matrix
irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
// Store and clear the view matrix
irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
// Store and clear the world matrix
irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
// Find horizontal and vertical axes after rotation
irr::f32 c = cos(-rotation*irr::core::DEGTORAD);
irr::f32 s = sin(-rotation*irr::core::DEGTORAD);
irr::core::vector2df horizontalAxis(c,s);
irr::core::vector2df verticalAxis(s,-c);
// First, we'll find the offset of the center and then where the center would be after rotation
irr::core::vector2df centerOffset(destRect.UpperLeftCorner.X+destRect.getWidth()/2.0f-rotationPoint.X,destRect.UpperLeftCorner.Y+destRect.getHeight()/2.0f-rotationPoint.Y);
irr::core::vector2df center = centerOffset.X*horizontalAxis - centerOffset.Y*verticalAxis;
center.X += rotationPoint.X;
center.Y += rotationPoint.Y;
// Now find the corners based off the center
irr::core::vector2df cornerOffset(destRect.getWidth()/2.0f,destRect.getHeight()/2.0f);
verticalAxis *= cornerOffset.Y;
horizontalAxis *= cornerOffset.X;
irr::core::vector2df corner[4];
corner[0] = center + verticalAxis - horizontalAxis;
corner[1] = center + verticalAxis + horizontalAxis;
corner[2] = center - verticalAxis - horizontalAxis;
corner[3] = center - verticalAxis + horizontalAxis;
// Find the uv coordinates of the sourceRect
irr::core::vector2df textureSize(texture->getSize().Width, texture->getSize().Height);
irr::core::vector2df uvCorner[4];
uvCorner[0] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[1] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.UpperLeftCorner.Y);
uvCorner[2] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.LowerRightCorner.Y);
uvCorner[3] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.LowerRightCorner.Y);
for (irr::s32 i = 0; i < 4; i++)
uvCorner[i] /= textureSize;
// Vertices for the image
irr::video::S3DVertex vertices[4];
irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
// Convert pixels to world coordinates
//irr::core::vector2df screenSize(rc_canvas[rc_active_canvas].dimension.Width, rc_canvas[rc_active_canvas].dimension.Height);
for (irr::s32 i = 0; i < 4; i++) {
vertices[i].Pos = irr::core::vector3df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
vertices[i].TCoords = uvCorner[i];
vertices[i].Color = color;
}
// Create the material
// IMPORTANT: For irrlicht 1.8 and above you MUST ADD THIS LINE:
// material.BlendOperation = irr::video::EBO_ADD;
irr::video::SMaterial material;
material.Lighting = false;
material.ZWriteEnable = irr::video::EZW_OFF;
material.ZBuffer = false;
material.BackfaceCulling = false;
material.TextureLayer[0].Texture = texture;
material.TextureLayer[0].BilinearFilter = rc_bilinear_filter; //TODO: Add option to switch this on/off
material.BlendOperation = rc_blend_mode;
material.MaterialTypeParam = irr::video::pack_textureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR);
//material.AntiAliasing = irr::video::EAAM_OFF;
if (useAlphaChannel)
material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
else
material.MaterialType = irr::video::EMT_SOLID;
driver->setMaterial(material);
driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
// Restore projection, world, and view matrices
driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
#endif // RC_GFX_CORE_H_INCLUDED

View File

@@ -901,7 +901,6 @@ bool rc_scalarMatrixColumns(uint32_t mA, uint32_t mB, uint32_t c, uint32_t num_c
rc_copyMatrix(mA, mB);
int row_offset = 0;
int b_offset = 0;
for(int row = 0; row < rc_matrix[mB].r; row++)
{
row_offset = row * rc_matrix[mB].c;

View File

@@ -7,24 +7,52 @@
struct rc_sprite2D_physics_obj
{
b2Body* body;
b2Fixture* fixture;
b2Shape* shape;
int offset_x;
int offset_y;
};
struct rc_sprite2D_animation_obj
{
irr::core::array<int> frames;
int num_frames;
int current_frame;
double fps;
double frame_start_time;
double frame_swap_time;
};
struct rc_sprite2D_obj
{
int id; //This is needed to reference this sprite in the contact listener
bool active = false;
int image_id;
irr::core::vector2d<irr::f64> position;
irr::f64 rotation;
int sheet_numFrames;
int frames_per_row;
irr::core::vector2d<irr::f64> scale;
irr::core::dimension2d<irr::f64> frame_size;
bool visible = true;
Uint8 alpha;
irr::video::SColor color_mod;
bool physics_enabled = false;
bool isSolid = false;
rc_sprite2D_physics_obj physics;
int current_animation;
int num_animation_loops;
int current_animation_loop;
bool isPlaying;
irr::core::array<rc_sprite2D_animation_obj> animation;
int parent_canvas = -1;
double z;

View File

@@ -0,0 +1,864 @@
#ifndef RC_SPRITELIB_H_INCLUDED
#define RC_SPRITELIB_H_INCLUDED
#ifdef RC_ANDROID
#include "SDL.h"
#else
#include <SDL2/SDL.h>
#endif // _IRR_ANDROID_PLATFORM_
#include "rc_sprite2D.h"
#include "rc_gfx_core.h"
#define RC_SPRITE_BASE_ANIMATION 0
int rc_createSpriteAnimation(int spr_id, int anim_length, double fps)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
if(anim_length <= 0)
anim_length = 1;
rc_sprite2D_animation_obj animation;
animation.current_frame = 0;
animation.fps = fps;
animation.frame_swap_time = 1000/fps;
animation.num_frames = anim_length;
for(int i = 0; i < anim_length; i++)
animation.frames.push_back(0);
int animation_id = rc_sprite[spr_id].animation.size();
rc_sprite[spr_id].animation.push_back(animation);
return animation_id;
}
void rc_setSpriteFrame(int spr_id, int frame)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(frame < 0 || frame >= rc_sprite[spr_id].sheet_numFrames)
return;
rc_sprite[spr_id].current_animation = RC_SPRITE_BASE_ANIMATION;
rc_sprite[spr_id].animation[RC_SPRITE_BASE_ANIMATION].current_frame = 0;
rc_sprite[spr_id].animation[RC_SPRITE_BASE_ANIMATION].frames[0] = frame;
}
int rc_getSpriteFrame(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
int current_animation = rc_sprite[spr_id].current_animation;
int current_frame = rc_sprite[spr_id].animation[current_animation].current_frame;
return rc_sprite[spr_id].animation[current_animation].frames[current_frame];
}
void rc_setSpriteAnimationFrame(int spr_id, int spr_animation, int anim_frame, int frame)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(anim_frame < 0 || anim_frame >= rc_sprite[spr_id].animation[spr_animation].num_frames)
return;
if(frame < 0 || frame >= rc_sprite[spr_id].sheet_numFrames)
return;
rc_sprite[spr_id].animation[spr_animation].frames[anim_frame] = frame;
}
int rc_getSpriteAnimationFrame(int spr_id, int spr_animation, int anim_frame)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
if(anim_frame < 0 || anim_frame >= rc_sprite[spr_id].animation[spr_animation].num_frames)
return -1;
return rc_sprite[spr_id].animation[spr_animation].frames[anim_frame];
}
void rc_setSpriteAnimationLength(int spr_id, int animation, int num_frames)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
// I intentionally checked for less than or equal to 0 because 0 is the base animation and should not be changed
if(animation <= 0 || animation >= rc_sprite[spr_id].animation.size())
return;
if(num_frames <= 0)
num_frames = 1;
if(num_frames > rc_sprite[spr_id].animation[animation].num_frames)
{
for(int i = rc_sprite[spr_id].animation[animation].num_frames; i < rc_sprite[spr_id].animation[animation].frames.size(); i++)
rc_sprite[spr_id].animation[animation].frames[i] = 0;
}
rc_sprite[spr_id].animation[animation].num_frames = num_frames;
if(num_frames > rc_sprite[spr_id].animation[animation].frames.size())
{
while(num_frames > rc_sprite[spr_id].animation[animation].frames.size())
rc_sprite[spr_id].animation[animation].frames.push_back(0);
}
if(num_frames < rc_sprite[spr_id].animation[animation].frames.size())
{
if(rc_sprite[spr_id].animation[animation].current_frame >= num_frames)
rc_sprite[spr_id].animation[animation].current_frame = num_frames - 1;
}
}
int rc_getSpriteAnimationLength(int spr_id, int animation)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
if(animation < 0 || animation >= rc_sprite[spr_id].animation.size())
return 0;
return rc_sprite[spr_id].animation[animation].num_frames;
}
void rc_setSpriteAnimationSpeed(int spr_id, int animation, double fps)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(animation < 0 || animation >= rc_sprite[spr_id].animation.size())
return;
rc_sprite[spr_id].animation[animation].fps = fps;
rc_sprite[spr_id].animation[animation].frame_swap_time = 1000/fps;
}
double rc_getSpriteAnimationSpeed(int spr_id, int animation)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
if(animation < 0 || animation >= rc_sprite[spr_id].animation.size())
return 0;
return rc_sprite[spr_id].animation[animation].fps;
}
void rc_setSpriteAnimation(int spr_id, int animation)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(animation < 0 || animation >= rc_sprite[spr_id].animation.size())
return;
rc_sprite[spr_id].current_animation = animation;
rc_sprite[spr_id].animation[animation].current_frame = 0;
rc_sprite[spr_id].isPlaying = true;
rc_sprite[spr_id].animation[animation].frame_start_time = SDL_GetTicks();
}
int rc_getSpriteAnimation(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
return rc_sprite[spr_id].current_animation;
}
int rc_getSpriteCurrentAnimationFrame(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
int current_animation = rc_sprite[spr_id].current_animation;
return rc_sprite[spr_id].animation[current_animation].current_frame;
}
void rc_setSpriteAnimationLoops(int spr_id, int num_loops)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].num_animation_loops = num_loops;
}
int rc_numSpriteAnimationLoops(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return rc_sprite[spr_id].num_animation_loops;
}
//------------------------------SPRITES-------------------------------------------------------
//Larger z gets drawn first
void sortSpriteZ(int canvas_id)
{
if(canvas_id < 0 || canvas_id >= rc_canvas.size())
return;
if(!rc_canvas[canvas_id].texture)
return;
for(int i = 0; i < rc_canvas[canvas_id].sprite.size(); i++)
{
rc_sprite2D_obj* spriteA = rc_canvas[canvas_id].sprite[i];
for(int j = i+1; j < rc_canvas[canvas_id].sprite.size(); j++)
{
rc_sprite2D_obj* spriteB = rc_canvas[canvas_id].sprite[j];
if(spriteB->z > spriteA->z)
{
rc_canvas[canvas_id].sprite[j] = NULL;
rc_canvas[canvas_id].sprite.erase(j);
rc_canvas[canvas_id].sprite.insert(spriteB, i);
}
}
}
}
int rc_createSprite(int img_id, double w, double h)
{
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return -1;
if(rc_canvas[rc_active_canvas].type != RC_CANVAS_TYPE_SPRITE)
return -1;
//std::cout << "debug 1" << std::endl;
int spr_id = -1;
for(int i = 0; i < rc_sprite.size(); i++)
{
if(!rc_sprite[i].active)
{
spr_id = i;
break;
}
}
if(spr_id < 0)
{
spr_id = rc_sprite.size();
rc_sprite2D_obj sprite;
rc_sprite.push_back(sprite);
}
rc_sprite[spr_id].active = true;
rc_sprite[spr_id].id = spr_id;
rc_sprite[spr_id].image_id = img_id;
rc_sprite[spr_id].frame_size.set(w, h);
if(img_id >= 0 && img_id < rc_image.size())
{
if(rc_image[img_id].image)
{
int img_w = rc_image[img_id].image->getSize().Width;
int img_h = rc_image[img_id].image->getSize().Height;
rc_sprite[spr_id].frames_per_row = (int)(img_w / w);
rc_sprite[spr_id].sheet_numFrames = ((int)(img_h / h)) * rc_sprite[spr_id].frames_per_row;
}
else
rc_sprite[spr_id].image_id = -1;
}
else
rc_sprite[spr_id].image_id = -1;
b2BodyDef sprBodyDef;
sprBodyDef.type = b2_dynamicBody;
sprBodyDef.position.Set(0, 0);
sprBodyDef.angle = 0;
sprBodyDef.userData.pointer = (uintptr_t)&rc_sprite[spr_id];
rc_sprite[spr_id].physics.body = rc_canvas[rc_active_canvas].physics2D.world->CreateBody(&sprBodyDef);
b2FixtureDef sprFixtureDef;
rc_sprite[spr_id].physics.shape = new b2PolygonShape();
b2PolygonShape* fix_shape = (b2PolygonShape*)rc_sprite[spr_id].physics.shape;
fix_shape->SetAsBox(w/2, h/2);
sprFixtureDef.shape = rc_sprite[spr_id].physics.shape;
sprFixtureDef.isSensor = true;
sprFixtureDef.density = 1;
rc_sprite[spr_id].physics.fixture = rc_sprite[spr_id].physics.body->CreateFixture(&sprFixtureDef);
rc_sprite[spr_id].physics.offset_x = 0;
rc_sprite[spr_id].physics.offset_y = 0;
rc_sprite[spr_id].isSolid = false;
if(rc_sprite[spr_id].image_id < 0)
rc_sprite[spr_id].visible =false;
else
rc_sprite[spr_id].visible = true;
rc_sprite[spr_id].scale.set(1.0, 1.0);
rc_sprite[spr_id].alpha = 255;
rc_sprite[spr_id].z = 0;
rc_sprite[spr_id].color_mod.set(255,255,255,255);
rc_sprite[spr_id].parent_canvas = rc_active_canvas;
rc_sprite[spr_id].current_animation = RC_SPRITE_BASE_ANIMATION;
rc_sprite[spr_id].num_animation_loops = 0;
rc_sprite[spr_id].current_animation_loop = 0;
rc_sprite[spr_id].isPlaying = false;
rc_sprite[spr_id].animation.clear();
rc_createSpriteAnimation(spr_id, 1, 0);
rc_canvas[rc_active_canvas].sprite.push_back(&rc_sprite[spr_id]);
sortSpriteZ(rc_active_canvas);
return spr_id;
}
void rc_deleteSprite(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(rc_sprite[spr_id].physics.body)
{
if(rc_sprite[spr_id].parent_canvas >= 0 && rc_sprite[spr_id].parent_canvas < rc_canvas.size())
{
if(rc_canvas[rc_sprite[spr_id].parent_canvas].physics2D.world)
rc_canvas[rc_sprite[spr_id].parent_canvas].physics2D.world->DestroyBody(rc_sprite[spr_id].physics.body);
}
rc_sprite[spr_id].physics.body = NULL;
}
rc_sprite[spr_id].active = false;
rc_sprite[spr_id].parent_canvas = -1;
rc_sprite[spr_id].animation.clear();
for(int i = 0; i < rc_canvas[rc_active_canvas].sprite.size(); i++)
{
rc_sprite2D_obj* canvas_sprite = rc_canvas[rc_active_canvas].sprite[i];
rc_sprite2D_obj* global_sprite = &rc_sprite[spr_id];
if(canvas_sprite == global_sprite)
{
rc_canvas[rc_active_canvas].sprite.erase(i);
break;
}
}
}
void rc_setSpriteSource(int spr_id, int img_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(img_id < 0)
{
rc_sprite[spr_id].image_id = -1;
return;
}
if(img_id >= rc_image.size())
return;
if(!rc_image[img_id].image)
return;
rc_sprite[spr_id].image_id = img_id;
}
int rc_getSpriteSource(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
return rc_sprite[spr_id].image_id;
}
void rc_setSpriteType(int spr_id, int body_type)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].physics.body->SetType((b2BodyType) body_type);
}
int rc_getSpriteType(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return -1;
if(!rc_sprite[spr_id].active)
return -1;
return (int)rc_sprite[spr_id].physics.body->GetType();
}
void rc_setSpriteSolid(int spr_id, bool flag)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].isSolid = flag;
rc_sprite[spr_id].physics.fixture->SetSensor(!flag);
}
bool rc_spriteIsSolid(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return false;
if(!rc_sprite[spr_id].active)
return false;
return rc_sprite[spr_id].isSolid;
}
void rc_setSpritePosition(int spr_id, double x, double y)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
float current_angle = rc_sprite[spr_id].physics.body->GetAngle();
rc_sprite[spr_id].physics.body->SetTransform(b2Vec2(x, y), current_angle);
}
void rc_translateSprite(int spr_id, double x, double y)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
float current_angle = rc_sprite[spr_id].physics.body->GetAngle();
double spr_x = rc_sprite[spr_id].physics.body->GetPosition().x + x;
double spr_y = rc_sprite[spr_id].physics.body->GetPosition().y + y;
rc_sprite[spr_id].physics.body->SetTransform(b2Vec2(spr_x, spr_y), current_angle);
}
void rc_getSpritePosition(int spr_id, double* x, double* y)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
*x = (double)rc_sprite[spr_id].physics.body->GetPosition().x;
*y = (double)rc_sprite[spr_id].physics.body->GetPosition().y;
}
double rc_spriteX(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return (double)rc_sprite[spr_id].physics.body->GetPosition().x;
}
double rc_spriteY(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return (double)rc_sprite[spr_id].physics.body->GetPosition().y;
}
void rc_setSpriteRotation(int spr_id, double angle)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].physics.body->SetTransform(rc_sprite[spr_id].physics.body->GetPosition(), angle);
}
void rc_rotateSprite(int spr_id, double angle)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
float new_angle = rc_sprite[spr_id].physics.body->GetAngle() + angle;
rc_sprite[spr_id].physics.body->SetTransform(rc_sprite[spr_id].physics.body->GetPosition(), new_angle);
}
double rc_getSpriteRotation(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return rc_sprite[spr_id].physics.body->GetAngle();
}
void rc_setSpriteScale(int spr_id, double x, double y)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].scale.set(x, y);
if(rc_sprite[spr_id].isSolid)
{
if(rc_sprite[spr_id].physics.fixture)
{
b2FixtureDef fixdef;
fixdef.density = rc_sprite[spr_id].physics.fixture->GetDensity();
fixdef.friction = rc_sprite[spr_id].physics.fixture->GetFriction();
fixdef.restitution = rc_sprite[spr_id].physics.fixture->GetRestitution();
fixdef.restitutionThreshold = rc_sprite[spr_id].physics.fixture->GetRestitutionThreshold();
fixdef.shape = rc_sprite[spr_id].physics.shape;
fixdef.isSensor = !(rc_sprite[spr_id].isSolid);
switch(fixdef.shape->GetType())
{
case b2Shape::e_circle:
{
b2CircleShape* shape = (b2CircleShape*)fixdef.shape;
shape->m_radius = (x+y)/2;
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* shape = (b2PolygonShape*)fixdef.shape;
for(int i = 0; i < shape->m_count; i++)
{
shape->m_vertices[i].x *= x;
shape->m_vertices[i].y *= y;
}
}
break;
case b2Shape::e_chain:
{
b2ChainShape* shape = (b2ChainShape*)fixdef.shape;
for(int i = 0; i < shape->m_count; i++)
{
shape->m_vertices[i].x *= x;
shape->m_vertices[i].y *= y;
}
}
break;
case b2Shape::e_edge:
{
b2EdgeShape* shape = (b2EdgeShape*)fixdef.shape;
shape->m_vertex0.x *= x;
shape->m_vertex0.y *= y;
shape->m_vertex1.x *= x;
shape->m_vertex1.y *= y;
shape->m_vertex2.x *= x;
shape->m_vertex2.y *= y;
shape->m_vertex3.x *= x;
shape->m_vertex3.y *= y;
}
break;
}
rc_sprite[spr_id].physics.body->DestroyFixture(rc_sprite[spr_id].physics.fixture);
rc_sprite[spr_id].physics.fixture = rc_sprite[spr_id].physics.body->CreateFixture(&fixdef);
}
}
}
void rc_scaleSprite(int spr_id, double x, double y)
{
double scale_x = rc_sprite[spr_id].scale.X * x;
double scale_y = rc_sprite[spr_id].scale.Y * y;
rc_setSpriteScale(spr_id, scale_x, scale_y);
}
double rc_spriteWidth(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return rc_sprite[spr_id].frame_size.Width;
}
double rc_spriteHeight(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return rc_sprite[spr_id].frame_size.Height;
}
void rc_getSpriteSize(int spr_id, double* w, double* h)
{
*w = 0;
*h = 0;
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
*w = rc_sprite[spr_id].frame_size.Width;
*h = rc_sprite[spr_id].frame_size.Height;
}
void rc_setSpriteZ(int spr_id, double z)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].z = z;
sortSpriteZ(rc_sprite[spr_id].parent_canvas);
}
double rc_spriteZ(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return 0;
if(!rc_sprite[spr_id].active)
return 0;
return rc_sprite[spr_id].z;
}
void rc_setSpriteVisible(int spr_id, bool flag)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return;
if(!rc_sprite[spr_id].active)
return;
if(rc_sprite[spr_id].image_id)
rc_sprite[spr_id].visible = flag;
else
rc_sprite[spr_id].visible = false;
}
bool rc_spriteIsVisible(int spr_id)
{
if(spr_id < 0 || spr_id >= rc_sprite.size())
return false;
if(!rc_sprite[spr_id].active)
return false;
return rc_sprite[spr_id].visible;
}
//-----------------------------------PHYSICS----------------------------------------------------------------------------------
//This function is called on each canvas on update
void drawSprites(int canvas_id)
{
float step = rc_canvas[canvas_id].physics2D.timeStep;
int32 velocityIterations = rc_canvas[canvas_id].physics2D.velocityIterations;
int32 positionIterations = rc_canvas[canvas_id].physics2D.positionIterations;
if(rc_canvas[canvas_id].physics2D.enabled)
rc_canvas[canvas_id].physics2D.world->Step(step, velocityIterations, positionIterations);
//Setting the render target to the current canvas. NOTE: I might change this target to a separate sprite layer later.
VideoDriver->setRenderTarget(rc_canvas[canvas_id].texture, true, false);
irr::core::dimension2d<irr::u32> src_size;
irr::core::rect<irr::s32> sourceRect;
irr::core::position2d<irr::s32> position;
irr::core::position2d<irr::s32> rotationPoint;
irr::f32 rotation = 0;
irr::core::vector2df scale(1.0, 1.0);
bool useAlphaChannel = true;
irr::video::SColor color;
//irr::core::rect<irr::s32> dest( irr::core::vector2d(x, y), irr::core::dimension2d(src_w, src_h));;
irr::core::vector2df screenSize(rc_canvas[canvas_id].dimension.Width, rc_canvas[canvas_id].dimension.Height);
int x = 0;
int y = 0;
b2Vec2 physics_pos;
irr::f32 RAD_TO_DEG = 180.0/3.141592653589793238463;
double spr_timer = SDL_GetTicks();
for(int spr_index = 0; spr_index < rc_canvas[canvas_id].sprite.size(); spr_index++)
{
rc_sprite2D_obj* sprite = rc_canvas[canvas_id].sprite[spr_index];
if(!sprite->visible)
continue;
int img_id = sprite->image_id;
if(img_id < 0 || img_id >= rc_image.size())
continue;
//src_size = rc_image[img_id].image->getSize();
int current_animation = sprite->current_animation;
if((spr_timer - sprite->animation[current_animation].frame_start_time) >= sprite->animation[current_animation].frame_swap_time)
{
sprite->animation[current_animation].current_frame++;
if(sprite->animation[current_animation].current_frame >= sprite->animation[current_animation].num_frames)
{
sprite->animation[current_animation].current_frame = 0;
sprite->current_animation_loop++;
if(sprite->current_animation_loop >= sprite->num_animation_loops)
{
if(sprite->num_animation_loops < 0)
sprite->isPlaying = true;
else
sprite->isPlaying = false;
sprite->current_animation_loop = 0;
}
}
if(!sprite->isPlaying)
sprite->animation[current_animation].current_frame = 0;
sprite->animation[current_animation].frame_start_time = spr_timer;
}
int current_animation_frame = sprite->animation[current_animation].current_frame;
int frame_x = (int)(sprite->animation[current_animation].frames[current_animation_frame]%sprite->frames_per_row)*sprite->frame_size.Width;
int frame_y = (int)(sprite->animation[current_animation].frames[current_animation_frame]/sprite->frames_per_row)*sprite->frame_size.Height;
irr::core::vector2d<irr::s32> frame_pos(frame_x, frame_y);
src_size = sprite->frame_size;
sourceRect = irr::core::rect<irr::s32>( frame_pos, src_size);
//sourceRect = irr::core::rect<irr::s32>( irr::core::vector2d<irr::s32>(0, 0), src_size);
physics_pos = sprite->physics.body->GetPosition();
x = (int)physics_pos.x;
y = (int)physics_pos.y;
position.set(x, y);
rotationPoint.set(x + (src_size.Width/2), y + (src_size.Height/2)); //TODO: need to account for offset once that is implemented
rotation = -1 * (sprite->physics.body->GetAngle() * RAD_TO_DEG); //convert Box2D radians to degrees
scale.set(sprite->scale.X, sprite->scale.Y);
color.set(sprite->alpha,
sprite->color_mod.getRed(),
sprite->color_mod.getGreen(),
sprite->color_mod.getBlue());
//I don't want to draw an image that doesn't exists. Thats just crazy.
draw2DImage(VideoDriver, rc_image[img_id].image, sourceRect, position, rotationPoint, rotation, scale, useAlphaChannel, color, screenSize);
}
//Must set back to canvas 0 (the backbuffer) before returning
VideoDriver->setRenderTarget(rc_canvas[0].texture, false, false);
}
//NOTE TO TBIRD
// 1. Each sprite has a Box2D body. You can look in "rc_sprite2D.h" to see how a sprite is structured.
// 2. A box2D world is setup for each canvas. So a sprite will be attached to the canvas thats active when its created. When that canvas is destroyed, so is the sprite.
// 3. By default, I have the sprite.physics_enabled attribute set to false. I feel like it makes sense to have a user intentionally enable physics since a user may not want physics for every sprite.
// 4. The sprite.visible attribute only determines whether to draw the sprite. The physics simulation will still happen each frame unless physics are disabled.
// 5. Don't change the value of sprite.active. Its used to check whether a sprite exists or not. I have an array of sprites in rc_sprite2D.h and if the active attribute is set to false, I reuse that slot to create a new sprite. If there is no inactive sprites in the array then I add a new sprite index to the array.
// 6. The time step, velocity Iterations, and position iterations are part of the canvas.physics2D attribute. You will need to make functions to allow the user to change those.
// 7. If you want to modify how sprites are rendered then you can just change the drawSprites() function above these notes.
//-----------------------------END OF SPRITE STUFF------------------------------------------------------------------------------
#endif // RC_SPRITELIB_H_INCLUDED