From 04d928c97f3f6298cf64b6bb8a1aee5bbadcace1 Mon Sep 17 00:00:00 2001 From: En Yi Date: Sat, 21 Dec 2024 14:37:18 +0800 Subject: [PATCH] Add a rendering queue for sprite Only applies for editor scene as a test --- engine/CMakeLists.txt | 1 + engine/engine.h | 1 + engine/engine_conf.h | 1 + engine/render_queue.c | 42 +++++++++++ engine/render_queue.h | 29 ++++++++ scenes/components.h | 9 ++- scenes/editor_scene.c | 160 +++++++++++++++++++++++++---------------- scenes/game_scene.c | 14 ++-- scenes/game_systems.c | 2 +- scenes/items_ent.c | 21 ++++++ scenes/player_ent.c | 18 ++++- scenes/scene_impl.h | 1 + scenes/scene_systems.c | 3 + water_test.c | 2 +- 14 files changed, 226 insertions(+), 78 deletions(-) create mode 100644 engine/render_queue.c create mode 100644 engine/render_queue.h diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index db246f7..695424f 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(lib_engine OBJECT collisions.c mempool.c entManager.c + render_queue.c ) target_link_libraries(lib_engine PUBLIC diff --git a/engine/engine.h b/engine/engine.h index 4045a54..14bbeed 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -6,6 +6,7 @@ #include "sc/heap/sc_heap.h" #include "assets.h" #include "particle_sys.h" +#include "render_queue.h" typedef struct Scene Scene_t; diff --git a/engine/engine_conf.h b/engine/engine_conf.h index 5a2569c..a991d67 100644 --- a/engine/engine_conf.h +++ b/engine/engine_conf.h @@ -5,6 +5,7 @@ // if memory used too high #define MAX_SCENES_TO_RENDER 8 #define MAX_RENDER_LAYERS 4 +#define MAX_RENDERMANAGER_DEPTH 4 #define MAX_ENTITIES 2047 #define MAX_TEXTURES 16 #define MAX_SPRITES 127 diff --git a/engine/render_queue.c b/engine/render_queue.c new file mode 100644 index 0000000..f4ac3cf --- /dev/null +++ b/engine/render_queue.c @@ -0,0 +1,42 @@ +#include "render_queue.h" +#include "raylib.h" + +void init_render_manager(RenderManager *manager) +{ + memset(manager, 0, sizeof(*manager)); +} + +bool add_render_node(RenderManager *manager, RenderInfoNode *node, uint8_t layer_num) +{ + if (node->next != NULL) + { + return false; + } + if (node->spr == NULL) { + return false; + } + layer_num = (layer_num >= MAX_RENDERMANAGER_DEPTH) ? MAX_RENDERMANAGER_DEPTH - 1 : layer_num; + + node->next = manager->layers[layer_num]; + manager->layers[layer_num] = node; + return true; +} + +void execute_render(RenderManager *manager) { + for (uint8_t depth = 0; depth < MAX_RENDERMANAGER_DEPTH; ++depth) + { + RenderInfoNode* curr = manager->layers[depth]; + while (curr != NULL) + { + draw_sprite_pro( + curr->spr, curr->frame_num, curr->pos, + curr->rotation, curr->flip, curr->scale, + curr->colour + ); + RenderInfoNode* next = curr->next; + curr->next = NULL; + curr = next; + } + } + reset_render_manager(manager); +} diff --git a/engine/render_queue.h b/engine/render_queue.h new file mode 100644 index 0000000..b9a9fc6 --- /dev/null +++ b/engine/render_queue.h @@ -0,0 +1,29 @@ +#ifndef RENDER_QUEUE_H +#define RENDER_QUEUE_H +#include "assets.h" +#include "engine_conf.h" + +typedef struct RenderInfoNode RenderInfoNode; +struct RenderInfoNode { + // Intrusive Linked-list Node + RenderInfoNode* next; + + Sprite_t* spr; + Vector2 pos; + int frame_num; + float rotation; + Vector2 scale; + Color colour; + uint8_t flip; +}; + +typedef struct RenderManager { + RenderInfoNode* layers[MAX_RENDERMANAGER_DEPTH]; +} RenderManager; + +void init_render_manager(RenderManager* manager); +#define reset_render_manager init_render_manager + +bool add_render_node(RenderManager* manager, RenderInfoNode* node, uint8_t layer_num); +void execute_render(RenderManager* manager); +#endif diff --git a/scenes/components.h b/scenes/components.h index 58b72b2..b34d174 100644 --- a/scenes/components.h +++ b/scenes/components.h @@ -1,4 +1,5 @@ #include "EC.h" +#include "render_queue.h" #include "particle_sys.h" // includes assets enum ComponentEnum { @@ -145,19 +146,17 @@ typedef struct _SpriteRenderInfo } SpriteRenderInfo_t; typedef struct _CSprite_t { + RenderInfoNode node; SpriteRenderInfo_t* sprites; sprite_transition_func_t transition_func; unsigned int current_idx; - bool flip_x; - bool flip_y; - bool pause; int current_frame; float fractional; - float rotation; // Degree float rotation_speed; // Degree / s int elapsed; Vector2 offset; - Color colour; + uint8_t depth; + bool pause; } CSprite_t; typedef struct _CMoveable_t { diff --git a/scenes/editor_scene.c b/scenes/editor_scene.c index d5ba5a9..fbb67c1 100644 --- a/scenes/editor_scene.c +++ b/scenes/editor_scene.c @@ -302,6 +302,92 @@ static void render_editor_game_scene(Scene_t* scene) max.x = (int)fmin(tilemap.width, max.x + 1); max.y = (int)fmin(tilemap.height, max.y + 1); + // Queue Sprite rendering + sc_map_foreach_value(&scene->ent_manager.entities, p_ent) + { + if (!p_ent->m_alive) continue; + + CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T); + if (p_cspr == NULL) continue; + + if (p_ent->m_tag == LEVEL_END_TAG) + { + if (p_cspr != NULL) + { + const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx]; + if (spr.sprite != NULL) + { + Vector2 pos = p_ent->position; + pos = Vector2Subtract( + pos, + get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->node.flip & 1) + ); + + Vector2 offset = spr.offset; + if (p_cspr->node.flip & 1) offset.x *= -1; + + pos = Vector2Add(pos, offset); + + p_cspr->node.spr = spr.sprite; + p_cspr->node.frame_num = + 2 * data->selected_solid_tilemap + ( + (data->coins.current < data->coins.total) ? 0 : 1 + ); + p_cspr->node.pos = pos; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + add_render_node(&data->render_manager, &p_cspr->node, p_cspr->depth); + } + } + continue; + } + + CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T); + + // Entity culling + Vector2 box_size = {0}; + if (p_bbox != NULL) box_size = p_bbox->size; + if ( + p_ent->position.x + box_size.x < min.x * tilemap.tile_size + || p_ent->position.x > max.x * tilemap.tile_size + || p_ent->position.y + box_size.y < min.y * tilemap.tile_size + || p_ent->position.y > max.y * tilemap.tile_size + ) + { + continue; + } + + if (p_cspr != NULL) + { + const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx]; + if (spr.sprite != NULL) + { + Vector2 pos = p_ent->position; + if (p_bbox != NULL) + { + pos = Vector2Add( + pos, + get_anchor_offset(p_bbox->size, spr.dest_anchor, p_cspr->node.flip & 1) + ); + } + pos = Vector2Subtract( + pos, + get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->node.flip & 1) + ); + + Vector2 offset = spr.offset; + if (p_cspr->node.flip & 1) offset.x *= -1; + + pos = Vector2Add(pos, offset); + + p_cspr->node.spr = spr.sprite; + p_cspr->node.frame_num = p_cspr->current_frame; + p_cspr->node.pos = pos; + add_render_node(&data->render_manager, &p_cspr->node, p_cspr->depth); + } + } + } + Texture2D* bg = get_texture(&scene->engine->assets, "bg_tex"); BeginTextureMode(scene->layers.render_layers[GAME_LAYER].layer_tex); ClearBackground(WHITE); @@ -342,43 +428,18 @@ static void render_editor_game_scene(Scene_t* scene) } } - sc_map_foreach_value(&scene->ent_manager.entities_map[LEVEL_END_TAG], p_ent) - { - CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T); - if (p_cspr != NULL) - { - const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx]; - if (spr.sprite != NULL) - { - Vector2 pos = p_ent->position; - pos = Vector2Subtract( - pos, - get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->flip_x) - ); - - Vector2 offset = spr.offset; - if (p_cspr->flip_x) offset.x *= -1; - - pos = Vector2Add(pos, offset); - draw_sprite( - spr.sprite, - 2 * data->selected_solid_tilemap + ( - (data->coins.current < data->coins.total) ? 0 : 1 - ), - pos, 0.0f, p_cspr->flip_x - ); - } - } - else - { - DrawCircleV(p_ent->position, tilemap.tile_size >> 1, (data->coins.current < data->coins.total)? RED : GREEN); - } - } - char buffer[64] = {0}; sc_map_foreach_value(&scene->ent_manager.entities, p_ent) { - if (p_ent->m_tag == LEVEL_END_TAG) continue; + if (p_ent->m_tag == LEVEL_END_TAG && data->show_grid) + { + CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T); + if (p_cspr == NULL) + { + DrawCircleV(p_ent->position, tilemap.tile_size >> 1, (data->coins.current < data->coins.total)? RED : GREEN); + } + continue; + } CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T); @@ -508,35 +569,10 @@ static void render_editor_game_scene(Scene_t* scene) DrawRectangleLinesEx(rec, 1.5, PURPLE); } } - - CSprite_t* p_cspr = get_component(p_ent, CSPRITE_T); - if (p_cspr != NULL) - { - const SpriteRenderInfo_t spr = p_cspr->sprites[p_cspr->current_idx]; - if (spr.sprite != NULL) - { - Vector2 pos = p_ent->position; - if (p_bbox != NULL) - { - pos = Vector2Add( - pos, - get_anchor_offset(p_bbox->size, spr.dest_anchor, p_cspr->flip_x) - ); - } - pos = Vector2Subtract( - pos, - get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->flip_x) - ); - - Vector2 offset = spr.offset; - if (p_cspr->flip_x) offset.x *= -1; - - pos = Vector2Add(pos, offset); - draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x); - } - } } + execute_render(&data->render_manager); + for (int tile_y = min.y; tile_y < max.y; tile_y++) { for (int tile_x = min.x; tile_x < max.x; tile_x++) @@ -1321,7 +1357,7 @@ void init_sandbox_scene(LevelScene_t* scene) { Entity_t* p_player = create_player(&scene->scene.ent_manager); CSprite_t* p_cspr = get_component(p_player, CSPRITE_T); - p_cspr->flip_x = true; + p_cspr->node.flip |= 1; p_player->position.x = 100; p_player->position.y = (scene->data.tilemap.height - 1) * scene->data.tilemap.tile_size - PLAYER_HEIGHT; diff --git a/scenes/game_scene.c b/scenes/game_scene.c index 0e5f301..f4235a3 100644 --- a/scenes/game_scene.c +++ b/scenes/game_scene.c @@ -208,11 +208,11 @@ static void render_regular_game_scene(Scene_t* scene) Vector2 pos = p_ent->position; pos = Vector2Subtract( pos, - get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->flip_x) + get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->node.flip & 1) ); Vector2 offset = spr.offset; - if (p_cspr->flip_x) offset.x *= -1; + if (p_cspr->node.flip & 1) offset.x *= -1; pos = Vector2Add(pos, offset); draw_sprite( @@ -220,7 +220,7 @@ static void render_regular_game_scene(Scene_t* scene) 2 * data->selected_solid_tilemap + ( (data->coins.current < data->coins.total) ? 0 : 1 ), - pos, 0.0f, p_cspr->flip_x + pos, 0.0f, p_cspr->node.flip & 1 ); } } @@ -258,19 +258,19 @@ static void render_regular_game_scene(Scene_t* scene) { pos = Vector2Add( pos, - get_anchor_offset(p_bbox->size, spr.dest_anchor, p_cspr->flip_x) + get_anchor_offset(p_bbox->size, spr.dest_anchor, p_cspr->node.flip & 1) ); } pos = Vector2Subtract( pos, - get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->flip_x) + get_anchor_offset(spr.sprite->frame_size, spr.src_anchor, p_cspr->node.flip & 1) ); Vector2 offset = spr.offset; - if (p_cspr->flip_x) offset.x *= -1; + if (p_cspr->node.flip & 1) offset.x *= -1; pos = Vector2Add(pos, offset); - draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x); + draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->node.flip & 1); } continue; } diff --git a/scenes/game_systems.c b/scenes/game_systems.c index 28d2e78..d44e97e 100644 --- a/scenes/game_systems.c +++ b/scenes/game_systems.c @@ -2155,7 +2155,7 @@ void level_end_detection_system(Scene_t* scene) ent->position.y += tilemap.tile_size >> 1; CSprite_t* p_cspr = get_component(p_other_ent, CSPRITE_T); CSprite_t* new_cspr = get_component(ent, CSPRITE_T); - new_cspr->flip_x = p_cspr->flip_x; + new_cspr->node.flip = p_cspr->node.flip; } destroy_entity(scene, &lvl_scene->data.tilemap, p_other_ent); diff --git a/scenes/items_ent.c b/scenes/items_ent.c index df36397..4a72542 100644 --- a/scenes/items_ent.c +++ b/scenes/items_ent.c @@ -74,6 +74,9 @@ Entity_t* create_crate(EntityManager_t* ent_manager, bool metal, ContainerItem_t CSprite_t* p_cspr = add_component(p_crate, CSPRITE_T); p_cspr->sprites = item_sprite_map; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + { CContainer_t* p_container = add_component(p_crate, CCONTAINER_T); p_container->material = metal? METAL_CONTAINER : WOODEN_CONTAINER; @@ -122,6 +125,9 @@ Entity_t* create_boulder(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_boulder, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 19; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + p_cspr->depth = 2; return p_boulder; } @@ -145,6 +151,8 @@ Entity_t* create_arrow(EntityManager_t* ent_manager, uint8_t dir) CSprite_t* p_cspr = add_component(p_arrow, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 2; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; //p_hitbox->boxes[0] = (Rectangle){TILE_SIZE - 5, TILE_SIZE / 2 - 5, 5, 5}; const int HITBOX_LONG_SIDE = 10; const int HITBOX_SHORT_SIDE = 4; @@ -197,6 +205,8 @@ Entity_t* create_bomb(EntityManager_t* ent_manager, Vector2 launch_dir) CSprite_t* p_cspr = add_component(p_bomb, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 6; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; CTransform_t* p_ctransform = add_component(p_bomb, CTRANSFORM_COMP_T); p_ctransform->active = true; @@ -230,6 +240,9 @@ Entity_t* create_explosion(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_explosion, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 17; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + p_cspr->depth = 3; CLifeTimer_t* p_clifetimer = add_component(p_explosion, CLIFETIMER_T); p_clifetimer->life_time = 0.05f; @@ -269,6 +282,9 @@ Entity_t* create_urchin(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_urchin, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 21; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + p_cspr->depth = 2; add_component(p_urchin, CSQUISHABLE_T); @@ -298,6 +314,9 @@ Entity_t* create_chest(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_chest, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 18; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; + p_cspr->depth = 2; return p_chest; @@ -311,6 +330,8 @@ Entity_t* create_level_end(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_flag, CSPRITE_T); p_cspr->sprites = item_sprite_map; p_cspr->current_idx = 20; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->node.colour = WHITE; add_component(p_flag, CTILECOORD_COMP_T); return p_flag; diff --git a/scenes/player_ent.c b/scenes/player_ent.c index 0032706..b8ec3ab 100644 --- a/scenes/player_ent.c +++ b/scenes/player_ent.c @@ -30,8 +30,13 @@ static unsigned int player_sprite_transition_func(Entity_t* ent) CSprite_t* p_spr = get_component(ent, CSPRITE_T); CPlayerState_t* p_plr = get_component(ent, CPLAYERSTATE_T); - if (p_ctrans->velocity.x > 0) p_spr->flip_x = true; - else if (p_ctrans->velocity.x < 0) p_spr->flip_x = false; + if (p_ctrans->velocity.x > 0) { + p_spr->node.flip |= 1; + } + else if (p_ctrans->velocity.x < 0) + { + p_spr->node.flip &= ~1; + } p_spr->pause = false; @@ -111,6 +116,9 @@ Entity_t* create_player(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T); p_cspr->sprites = player_sprite_map; p_cspr->transition_func = &player_sprite_transition_func; + p_cspr->node.colour = WHITE; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->depth = 1; CEmitter_t* p_emitter = add_component(p_ent, CEMITTER_T); p_emitter->offset = (Vector2){7,0}; @@ -133,6 +141,9 @@ Entity_t* create_dead_player(EntityManager_t* ent_manager) CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T); p_cspr->sprites = player_sprite_map; p_cspr->current_idx = SPR_PLAYER_DEAD; + p_cspr->node.colour = WHITE; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->depth = 2; add_component(p_ent, CMOVEMENTSTATE_T); @@ -160,6 +171,9 @@ Entity_t* create_player_finish(EntityManager_t* ent_manager) p_cspr->sprites = player_sprite_map; p_cspr->current_idx = SPR_PLAYER_ENTER; p_cspr->transition_func = &player_finish_transition_func; + p_cspr->node.colour = WHITE; + p_cspr->node.scale = (Vector2){1, 1}; + p_cspr->depth = 1; CLifeTimer_t* p_clifetimer = add_component(p_ent, CLIFETIMER_T); p_clifetimer->life_time = 0.9f; diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index 86a2f19..05ff6a2 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -75,6 +75,7 @@ typedef struct LevelSceneData { bool show_grid; Vector2 player_spawn; LevelSceneStateMachine_t sm; + RenderManager render_manager; }LevelSceneData_t; static inline void change_level_state(LevelSceneData_t* data, LevelSceneState_t state) diff --git a/scenes/scene_systems.c b/scenes/scene_systems.c index 6996b7e..b9d6b1d 100644 --- a/scenes/scene_systems.c +++ b/scenes/scene_systems.c @@ -7,6 +7,8 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* tiles, Rectangle view_zone) { + init_render_manager(&data->render_manager); + data->game_rec = view_zone; memset(&data->camera, 0, sizeof(LevelCamera_t)); data->camera.cam.rotation = 0.0f; @@ -45,6 +47,7 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* t data->show_grid = false; memset(&data->sm, 0, sizeof(data->sm)); + } void term_level_scene_data(LevelSceneData_t* data) diff --git a/water_test.c b/water_test.c index 309cfb6..060a327 100644 --- a/water_test.c +++ b/water_test.c @@ -110,7 +110,7 @@ static void level_scene_render_func(Scene_t* scene) if (spr.sprite != NULL) { Vector2 pos = Vector2Add(p_ent->position, spr.offset); - draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->flip_x); + draw_sprite(spr.sprite, p_cspr->current_frame, pos, 0.0f, p_cspr->node.flip & 1); } } }