Fixed sprite allocation bugs

* Fixed bug that would cause the renderer for sprites to be corrupted on when the sprite vector is resized
* Changed deleted_sprites variable to deleted_animation in sprite object
* Changed sprite pointer vector to sprite id vector in canvas object
* Changed the value stored in Fixture UserData pointer to sprite id rather than sprite pointer because pointer would change on resize anyway
This commit is contained in:
n00b
2024-12-22 13:05:23 -05:00
parent ac2cb91b18
commit 0ef552910a
9 changed files with 85 additions and 54 deletions

View File

@@ -920,7 +920,7 @@ int main(int argc, char * argv[])
//DEBUG START
//rc_filename = "/home/n00b/projects/bu/constraint_demo/main.bas";
//rc_filename = "/home/n00b/Music/Simple 3D Platformer/main.bas";
rc_filename = "/home/n00b/Downloads/Tile Scrolling/main.bas";
//rc_filename = "/home/n00b/Programs/RCBasic_v400_Linux64/examples/Constraint/main.bas";
//DEBUG END

Binary file not shown.

View File

@@ -1055,6 +1055,7 @@ int rc_canvasOpen(int w, int h, int vx, int vy, int vw, int vh, int mode, int ca
canvas.physics2D.enabled = true;
canvas.physics2D.contact_listener = new rc_contactListener_obj();
canvas.physics2D.world->SetContactListener(canvas.physics2D.contact_listener);
canvas.sprite_id.clear();
}
switch(mode)
@@ -1133,13 +1134,14 @@ void rc_canvasClose(int canvas_id)
}
//sprites are destroyed when the world is deleted so I just to set the active attribute to false and set the body to NULL
for(int i = 0; i < rc_canvas[canvas_id].sprite.size(); i++)
for(int i = 0; i < rc_canvas[canvas_id].sprite_id.size(); i++)
{
rc_canvas[canvas_id].sprite[i]->active = false;
rc_canvas[canvas_id].sprite[i]->physics.body = NULL;
int spr_id = rc_canvas[canvas_id].sprite_id[i];
rc_sprite[spr_id].active = false;
rc_sprite[spr_id].physics.body = NULL;
}
rc_canvas[canvas_id].sprite.clear();
rc_canvas[canvas_id].sprite_id.clear();
if(rc_active_canvas == canvas_id)
rc_active_canvas = -1;
@@ -1177,25 +1179,6 @@ void rc_setCanvasPhysics2D(int canvas_id, bool flag)
rc_canvas[canvas_id].physics2D.enabled = flag;
}
void rc_clearCanvas()
{
if(rc_active_canvas >= 0 && rc_active_canvas < rc_canvas.size())
{
if(rc_canvas[rc_active_canvas].texture)
switch(rc_canvas[rc_active_canvas].type)
{
case RC_CANVAS_TYPE_2D:
VideoDriver->clearBuffers(true, true, true, rc_clear_color);
break;
default:
VideoDriver->clearBuffers(true, true, true, rc_clear_color);
break;
}
}
}
void rc_setCanvasVisible(int canvas_id, bool flag)
{
if(canvas_id <= 0 || canvas_id >= rc_canvas.size()) //canvas 0 is being excluded because its the back buffer

View File

@@ -298,9 +298,9 @@ 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* spriteA = &rc_sprite[contact->GetFixtureA()->GetBody()->GetUserData().pointer];
rc_sprite2D_obj* spriteB = (rc_sprite2D_obj*) contact->GetFixtureB()->GetBody()->GetUserData().pointer;
rc_sprite2D_obj* spriteB = &rc_sprite[contact->GetFixtureB()->GetBody()->GetUserData().pointer];
//std::cout << "sprite[" << spriteA->id << "] collide with sprite[" << spriteB->id << "]" << std::endl;
@@ -361,7 +361,7 @@ struct rc_canvas_obj
irr::u32 color_mod;
rc_physicsWorld2D_obj physics2D;
irr::core::array<rc_sprite2D_obj*> sprite;
irr::core::array<irr::s32> sprite_id;
};
irr::core::array<rc_canvas_obj> rc_canvas;

View File

@@ -2,7 +2,7 @@
#define RC_OS_DEFINES_H_INCLUDED
//USED FOR TESTING ONLY
//#define RC_TESTING
#define RC_TESTING
//I am checking Android first since I think it also defines __linux__

View File

@@ -51,7 +51,7 @@ struct rc_sprite2D_obj
int num_animation_loops;
int current_animation_loop;
bool isPlaying;
irr::core::array<int> deleted_sprites;
irr::core::array<int> deleted_animation;
irr::core::array<rc_sprite2D_animation_obj> animation;
int parent_canvas = -1;

View File

@@ -623,8 +623,8 @@ int rc_castRay2D_All(double from_x, double from_y, double to_x, double to_y)
{
rc_rayHit2D.clear();
RayCastCallback callback;
const b2Vec2 point1(from_x, from_y);
const b2Vec2 point2(to_x, to_y);
b2Vec2 point1(from_x, from_y);
b2Vec2 point2(to_x, to_y);
rc_canvas[rc_active_canvas].physics2D.world->RayCast(&callback, point1, point2);
@@ -633,7 +633,7 @@ int rc_castRay2D_All(double from_x, double from_y, double to_x, double to_y)
for(int i = 0; i < cb_hits.size(); i++)
{
rc_rayHit2D_obj hit;
rc_sprite2D_obj* h_sprite = (rc_sprite2D_obj*)cb_hits[i].fixture->GetBody()->GetUserData().pointer;
rc_sprite2D_obj* h_sprite = &rc_sprite[cb_hits[i].fixture->GetBody()->GetUserData().pointer];
hit.sprite_id = h_sprite->id;
hit.hit_point = cb_hits[i].point;
hit.hit_normal = cb_hits[i].normal;
@@ -661,7 +661,7 @@ int rc_castRay2D(double from_x, double from_y, double to_x, double to_y)
for(int i = 0; i < cb_hits.size(); i++)
{
rc_rayHit2D_obj hit;
rc_sprite2D_obj* h_sprite = (rc_sprite2D_obj*)cb_hits[i].fixture->GetBody()->GetUserData().pointer;
rc_sprite2D_obj* h_sprite = &rc_sprite[cb_hits[i].fixture->GetBody()->GetUserData().pointer];
hit.sprite_id = h_sprite->id;
hit.hit_point = cb_hits[i].point;
hit.hit_normal = cb_hits[i].normal;

View File

@@ -35,10 +35,10 @@ int rc_createSpriteAnimation(int spr_id, int anim_length, double fps)
animation.frames.push_back(0);
int animation_id = rc_sprite[spr_id].animation.size();
if(rc_sprite[spr_id].deleted_sprites.size() > 0)
if(rc_sprite[spr_id].deleted_animation.size() > 0)
{
animation_id = rc_sprite[spr_id].deleted_sprites[0];
rc_sprite[spr_id].deleted_sprites.erase(0);
animation_id = rc_sprite[spr_id].deleted_animation[0];
rc_sprite[spr_id].deleted_animation.erase(0);
rc_sprite[spr_id].animation[animation_id] = animation;
}
else
@@ -55,7 +55,13 @@ void rc_deleteSpriteAnimation(int spr_id, int animation)
if(!rc_sprite[spr_id].active)
return;
rc_sprite[spr_id].deleted_sprites.push_back(animation);
for(int i = 0; i < rc_sprite[spr_id].deleted_animation.size(); i++)
{
if(rc_sprite[spr_id].deleted_animation[i] == animation)
return;
}
rc_sprite[spr_id].deleted_animation.push_back(animation);
}
void rc_setSpriteFrame(int spr_id, int frame)
@@ -281,19 +287,18 @@ void sortSpriteZ(int canvas_id)
if(!rc_canvas[canvas_id].texture)
return;
for(int i = 0; i < rc_canvas[canvas_id].sprite.size(); i++)
for(int i = 0; i < rc_canvas[canvas_id].sprite_id.size(); i++)
{
rc_sprite2D_obj* spriteA = rc_canvas[canvas_id].sprite[i];
int spriteA = rc_canvas[canvas_id].sprite_id[i];
for(int j = i+1; j < rc_canvas[canvas_id].sprite.size(); j++)
for(int j = i+1; j < rc_canvas[canvas_id].sprite_id.size(); j++)
{
rc_sprite2D_obj* spriteB = rc_canvas[canvas_id].sprite[j];
int spriteB = rc_canvas[canvas_id].sprite_id[j];
if(spriteB->z > spriteA->z)
if(rc_sprite[spriteB].z > rc_sprite[spriteA].z)
{
rc_canvas[canvas_id].sprite[j] = NULL;
rc_canvas[canvas_id].sprite.erase(j);
rc_canvas[canvas_id].sprite.insert(spriteB, i);
rc_canvas[canvas_id].sprite_id.erase(j);
rc_canvas[canvas_id].sprite_id.insert(spriteB, i);
}
}
}
@@ -352,7 +357,7 @@ int rc_createSprite(int img_id, double w, double h)
sprBodyDef.type = b2_dynamicBody;
sprBodyDef.position.Set(w/2, h/2);
sprBodyDef.angle = 0;
sprBodyDef.userData.pointer = (uintptr_t)&rc_sprite[spr_id];
sprBodyDef.userData.pointer = spr_id;
rc_sprite[spr_id].physics.body = rc_canvas[rc_active_canvas].physics2D.world->CreateBody(&sprBodyDef);
b2FixtureDef sprFixtureDef;
@@ -386,7 +391,10 @@ int rc_createSprite(int img_id, double w, double h)
rc_sprite[spr_id].animation.clear();
rc_createSpriteAnimation(spr_id, 1, 0);
rc_canvas[rc_active_canvas].sprite.push_back(&rc_sprite[spr_id]);
int i = rc_canvas[rc_active_canvas].sprite_id.size();
rc_canvas[rc_active_canvas].sprite_id.push_back(spr_id);
//std::cout << "Create Debug: [" << rc_active_canvas << "] index = " << i << " spr_id = " << rc_canvas[rc_active_canvas].sprite[i]->id << std::endl;
sortSpriteZ(rc_active_canvas);
@@ -412,13 +420,13 @@ void rc_deleteSprite(int spr_id)
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++)
for(int i = 0; i < rc_canvas[rc_active_canvas].sprite_id.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)
int canvas_sprite = rc_canvas[rc_active_canvas].sprite_id[i];
if(canvas_sprite == spr_id)
{
rc_canvas[rc_active_canvas].sprite.erase(i);
rc_canvas[rc_active_canvas].sprite_id.erase(i);
break;
}
}
@@ -846,9 +854,11 @@ void drawSprites(int canvas_id)
int offset_x = rc_canvas[canvas_id].offset.X;
int offset_y = rc_canvas[canvas_id].offset.Y;
for(int spr_index = 0; spr_index < rc_canvas[canvas_id].sprite.size(); spr_index++)
for(int spr_index = 0; spr_index < rc_canvas[canvas_id].sprite_id.size(); spr_index++)
{
rc_sprite2D_obj* sprite = rc_canvas[canvas_id].sprite[spr_index];
int spr_id = rc_canvas[canvas_id].sprite_id[spr_index];
rc_sprite2D_obj* sprite = &rc_sprite[spr_id];
//std::cout << "debug info: " << canvas_id << " --> " << spr_index << " id = " << sprite->id << " anim_size = " << sprite->animation.size() << std::endl; continue;
if(!sprite->visible)
continue;

View File

@@ -1,6 +1,44 @@
#ifndef RC_WINDOWCLOSE_H_INCLUDED
#define RC_WINDOWCLOSE_H_INCLUDED
void rc_clearCanvas()
{
if(rc_active_canvas >= 0 && rc_active_canvas < rc_canvas.size())
{
if(rc_canvas[rc_active_canvas].texture)
switch(rc_canvas[rc_active_canvas].type)
{
case RC_CANVAS_TYPE_2D:
VideoDriver->clearBuffers(true, true, true, rc_clear_color);
break;
case RC_CANVAS_TYPE_SPRITE:
VideoDriver->clearBuffers(true, true, true, rc_clear_color);
for(int i = 0; i < rc_joint.size(); i++)
{
if(rc_joint[i].canvas == rc_active_canvas)
{
rc_deleteJoint(i);
}
}
for(int i = 0; i < rc_sprite.size(); i++)
{
if(rc_sprite[i].parent_canvas == rc_active_canvas)
{
rc_deleteSprite(i);
}
}
break;
default:
VideoDriver->clearBuffers(true, true, true, rc_clear_color);
break;
}
}
}
void rc_closeWindow_hw()
{
irrtheora::stopVideo();