feat(engine): 重构游戏引擎核心逻辑

- 重新设计了引擎的初始化和运行流程
- 引入了实体组件系统(ECS)和物理系统
- 优化了渲染系统和输入系统
- 移除了不必要的资源管理系统
- 调整了日志系统的实现
This commit is contained in:
ZZY
2025-06-29 18:46:36 +08:00
parent 5ce660e3a6
commit 89bede93a9
37 changed files with 1294 additions and 350 deletions

View File

@@ -1,20 +0,0 @@
#ifndef __GE_ENTIRY_H__
#define __GE_ENTIRY_H__
#include "../ge_config.h"
#include "../math/ge_vector2i.h"
typedef struct {
uint16_t id;
uint16_t components;
} ge_entity_t;
typedef struct {
ge_vector2i_t position;
unsigned char z;
} ge_position_t;
#endif // __GE_ENTIRY_H__

View File

@@ -1,6 +0,0 @@
#ifndef __GE_SPRITE_H__
#define __GE_SPRITE_H__
#endif // __GE_SPRITE_H__

View File

@@ -0,0 +1,64 @@
#ifndef __GE_ENTIRY_H__
#define __GE_ENTIRY_H__
#include <ge_core.h>
#include <utils/ge_vector2i.h>
#include "ge_render_component.h"
#include "ge_physics_component.h"
#include <stdint.h>
typedef uint16_t ge_ecs_id_t; // 支持65536个实体
#define GE_ECS_MAX 128
typedef enum {
GE_COMPONENT_ACVIVE = 1 << 0,
GE_COMPONENT_POSITION = 1 << 1,
GE_COMPONENT_TRANSFORM = 1 << 2, // TODO not implimented
GE_COMPONENT_RENDERABLE = 1 << 3,
GE_COMPONENT_PHYSICS_BODY = 1 << 4, // TODO not implimented
GE_COMPONENT_COLLIDER = 1 << 5, // TODO not implimented
GE_COMPONENT_TIMED_LIFE = 1 << 6, // TODO not implimented
} ge_ecs_mask_t;
#define GE_RENDERABLE_MASK \
(GE_COMPONENT_POSITION | GE_COMPONENT_RENDERABLE)
#define GE_PHYSICS_MASK \
(GE_COMPONENT_POSITION | GE_COMPONENT_PHYSICS_BODY)
typedef struct ge_entity {
ge_ecs_id_t id;
ge_ecs_mask_t component_mask;
ge_vector2i_t position;
ge_render_component_t renderable;
ge_physics_component_t physics_body;
} ge_entity_t;
typedef struct {
// TODO static storage to dynamic storage
ge_entity_t entities[GE_ECS_MAX];
ge_ecs_id_t count;
} ge_ecs_storage_t;
typedef struct ge_ecs {
ge_ecs_storage_t storage;
} ge_ecs_t;
static inline ge_ecs_id_t ge_ecs_add_entity(ge_ecs_t* ecs, ge_entity_t** entity) {
ge_ecs_id_t id = ++ecs->storage.count;
if (id >= GE_ECS_MAX) {
return 0;
}
// TODO squeze the data
if (entity != NULL) *entity = &ecs->storage.entities[id];
return id;
}
static inline ge_entity_t* ge_ecs_get_entity(ge_ecs_t* ecs, ge_ecs_id_t id) {
if(id >= ecs->storage.count) {
return NULL;
}
return &ecs->storage.entities[id];
}
#endif // __GE_ENTIRY_H__

View File

@@ -0,0 +1,21 @@
#ifndef __GE_PHYSICS_COMPONENT_H__
#define __GE_PHYSICS_COMPONENT_H__
#include <utils/ge_vector2i.h>
#define GE_PHYSICS_VELOCITY_BIT 3
#define GE_PHYSICS_ACCELERATION_BIT 3
typedef enum {
GE_PHYSICS_COMPONENT_TYPE_NONE = 1 << 0,
GE_PHYSICS_COMPONENT_TYPE_VELOCITY = 1 << 1,
GE_PHYSICS_COMPONENT_TYPE_ACCELERATION = 1 << 2,
} ge_physics_component_type_t;
typedef struct ge_physics_component {
ge_physics_component_type_t type;
ge_vector2i_t velocity;
ge_vector2i_t acceleration;
} ge_physics_component_t;
#endif // __GE_PHYSICS_COMPONENT_H__

View File

@@ -0,0 +1,39 @@
#ifndef __GE_PHYSICS_SYSTEM_H__
#define __GE_PHYSICS_SYSTEM_H__
#include "ge_entity.h"
#include "ge_physics_component.h"
#include <pynic_log/pynic_log.h>
typedef struct ge_physics_system {
ge_ecs_storage_t* ecs;
} ge_physics_system_t;
#define _GE_PHYSICS_MASK (GE_PHYSICS_MASK | GE_COMPONENT_ACVIVE)
static inline void
ge_physics_system_run_all(ge_physics_system_t* ctx) {
Assert(ctx != NULL);
ge_ecs_storage_t* ecs = ctx->ecs;
Assert(ecs != NULL);
for (int i = 1; i <= ecs->count && i < GE_ECS_MAX; ++i) {
ge_entity_t* entity = &ecs->entities[i];
ge_ecs_mask_t mask = entity->component_mask;
if ((mask & _GE_PHYSICS_MASK) != _GE_PHYSICS_MASK) continue;
ge_physics_component_t* comp = &entity->physics_body;
Assert(comp != NULL);
ge_physics_component_type_t type= comp->type;
if (type & GE_PHYSICS_COMPONENT_TYPE_ACCELERATION) {
comp->velocity.x += comp->acceleration.x >> GE_PHYSICS_ACCELERATION_BIT;
comp->velocity.y += comp->acceleration.y >> GE_PHYSICS_ACCELERATION_BIT;
}
if (type & GE_PHYSICS_COMPONENT_TYPE_VELOCITY) {
entity->position.x += comp->velocity.x >> GE_PHYSICS_VELOCITY_BIT;
entity->position.y += comp->velocity.y >> GE_PHYSICS_VELOCITY_BIT;
}
}
}
#endif // __GE_PHYSICS_SYSTEM_H__

View File

@@ -0,0 +1,27 @@
#ifndef __GE_RENDER_COMPONENT_H__
#define __GE_RENDER_COMPONENT_H__
#include <interface/ge_render.h>
typedef enum {
GE_RENDER_COMPONENT_TYPE_NONE,
GE_RENDER_COMPONENT_TYPE_POINT,
GE_RENDER_COMPONENT_TYPE_TEXT,
GE_RENDER_COMPONENT_TYPE_RECT,
GE_RENDER_COMPONENT_TYPE_RECOURCE,
} ge_render_component_type_t;
typedef struct ge_render_component {
ge_render_component_type_t type;
union {
struct {
ge_render_color_t color;
} point;
struct {
ge_render_pos2_t size;
ge_render_color_t color;
} rect;
} data;
} ge_render_component_t;
#endif // __GE_RENDER_COMPONENT_H__

View File

@@ -0,0 +1,69 @@
#ifndef __GE_RENDER_SYSTEM_H__
#define __GE_RENDER_SYSTEM_H__
#include "ge_entity.h"
#include "ge_render_component.h"
#include <pynic_log/pynic_log.h>
typedef struct ge_render_system {
ge_render_t* render;
ge_ecs_storage_t* ecs;
} ge_render_system_t;
static inline void
ge_render_system_init(ge_render_system_t* ctx, ge_render_t* render) {
Assert(ctx != NULL && render != NULL);
ctx->render = render;
}
#define _GE_RENDERABLE_MASK (GE_RENDERABLE_MASK | GE_COMPONENT_ACVIVE)
static inline void
ge_render_system_draw_all(ge_render_system_t* ctx) {
Assert(ctx != NULL);
ge_ecs_storage_t* ecs = ctx->ecs;
Assert(ecs != NULL);
for (int i = 1; i <= ecs->count && i < GE_ECS_MAX; ++i) {
ge_entity_t* entity = &ecs->entities[i];
ge_ecs_mask_t mask = entity->component_mask;
if ((mask & _GE_RENDERABLE_MASK) != _GE_RENDERABLE_MASK) continue;
ge_render_pos2_t pos = {
entity->position.x,
entity->position.y,
};
ge_render_component_t* comp = &entity->renderable;
Assert(comp != NULL);
switch (comp->type) {
case GE_RENDER_COMPONENT_TYPE_POINT:
ctx->render->func_draw_point(
ctx->render,
&pos,
comp->data.point.color
);
break;
case GE_RENDER_COMPONENT_TYPE_RECT:
ctx->render->func_draw_rect(
ctx->render,
&(ge_render_rect_t) {
pos,
comp->data.rect.size,
},
comp->data.rect.color
);
break;
case GE_RENDER_COMPONENT_TYPE_TEXT:
TODO();
break;
case GE_RENDER_COMPONENT_TYPE_RECOURCE:
TODO();
break;
default:
LOG_WARN("render component not set Avaliable type %d, id %d", comp->type, i);
break;
}
}
}
#endif // __GE_RENDER_SYSTEM_H__

View File

@@ -9,4 +9,8 @@
#include <utils/ge_static_alloc.h>
#include <utils/ge_vector2i.h>
#include <interface/ge_timer.h>
#include <interface/ge_input.h>
#include <interface/ge_render.h>
#endif // __GE_COMMON_H__

View File

@@ -7,48 +7,48 @@ void ge_engine_init(ge_core_t *core) {
for (int i = 0; i < (int)sizeof(ge_core_t); i++) {
*(ptr + i) = 0;
}
core->configs.fps = 60;
core->configs.fps = 120;
}
static inline void ge_init(ge_core_t* core) {
/**
* check render
*/
ge_render_t* render_ctx = &core->render;
if (render_ctx->content) {
Assert(render_ctx->clear && render_ctx->draw
&& render_ctx->getsize);
GE_SAFE_CALL(render_ctx->init, render_ctx);
render_ctx->getsize(render_ctx, &render_ctx->screen_size);
ge_render_t* render_ctx = &core->_render;
if (render_ctx->context) {
GE_SAFE_CALL(render_ctx->init_func, render_ctx, NULL);
}
Assert(core->timer.sleep_ms != NULL);
Assert(core->configs.fps != 0);
Assert(core->_timer.func_sleepms != NULL);
core->timer.fps_ctl.target_fps = 0;
if (core->timer.get_ms != NULL) {
ge_fps_init(&core->timer.fps_ctl, core->configs.fps,
core->timer.get_ms, core->timer.sleep_ms);
/**
* init ecs
*/
for (int i = 0; i < GE_ECS_MAX; ++i) {
core->ecs.storage.entities[i].component_mask = 0;
}
}
ge_render_system_init(&core->_systems.render, &core->_render);
// TODO using other storage system
core->_systems.render.ecs = &core->ecs.storage;
core->ecs.storage.count = 0;
static inline void ge_render(ge_render_t* ctx) {
// ctx->clear(ctx);
core->_systems.physics.ecs = &core->ecs.storage;
}
void ge_engine_run(ge_core_t *core) {
GE_SAFE_CALL(core->callbacks.init, core);
ge_init(core);
GE_SAFE_CALL(core->callbacks.init, core);
core->state = GE_ENGINE_STATE_RUNNING;
while (core->state == GE_ENGINE_STATE_RUNNING) {
if (core->timer.fps_ctl.target_fps) ge_fps_begin_frame(&core->timer.fps_ctl);
GE_SAFE_CALL(core->_inner_run, core);
GE_SAFE_CALL(core->callbacks.run, core);
if (core->render.content) ge_render(&core->render);
ge_physics_system_run_all(&core->_systems.physics);
GE_SAFE_CALL(core->callbacks.process, core);
ge_render_system_draw_all(&core->_systems.render);
if (core->timer.fps_ctl.target_fps) ge_fps_end_frame(&core->timer.fps_ctl);
else core->timer.sleep_ms(1000 / core->configs.fps);
GE_SAFE_CALL(core->_render.func_flush, &core->_render);
core->_timer.func_sleepms(&core->_timer, 1000 / core->configs.fps);
}
GE_SAFE_CALL(core->callbacks.exit, core);
}

View File

@@ -2,8 +2,9 @@
#define __GE_CORE_H__
#include <ge_common.h>
#include <render/ge_render.h>
#include <timer/ge_timer.h>
#include <ecs/ge_entity.h>
#include <ecs/ge_render_system.h>
#include <ecs/ge_physics_system.h>
struct ge_engine_core;
typedef struct ge_engine_core ge_core_t;
@@ -24,20 +25,31 @@ struct ge_engine_core {
struct {
ge_init_func_t init;
ge_exit_func_t exit;
ge_run_func_t run;
ge_run_func_t process;
} callbacks;
ge_engine_state_t state;
ge_render_t render;
ge_timer_t timer;
ge_ecs_t ecs;
DECLARE_GE_KFIFO(einput, ge_uptr_t, 16, ge_event_input_t);
struct {
ge_uint_t fps;
} configs;
void* context;
struct {
ge_render_system_t render;
ge_physics_system_t physics;
} _systems;
ge_render_t _render;
ge_timer_t _timer;
ge_input_t _input;
ge_run_func_t _inner_run;
void* _inner_context;
};
/**
* Basic Call
*/
int ge_main(ge_core_t* core);
void ge_engine_init(ge_core_t *core);
void ge_engine_run(ge_core_t *core);

View File

@@ -0,0 +1,57 @@
#ifndef __GE_INPUT_H__
#define __GE_INPUT_H__
#include <stdint.h>
struct ge_input;
typedef struct ge_input ge_input_t;
typedef union ge_input_event {
void* ctx;
uintptr_t num;
} ge_input_event_t;
typedef int(*ge_input_send_func_t)(ge_input_t* ctx, ge_input_event_t event);
typedef int(*ge_input_peek_func_t)(ge_input_t* ctx, ge_input_event_t* event);
typedef int(*ge_input_recv_func_t)(ge_input_t* ctx, ge_input_event_t* event);
struct ge_input {
void* context;
ge_input_send_func_t func_send;
ge_input_peek_func_t func_peek;
ge_input_recv_func_t func_recv;
};
#ifdef __GE_INPUT_EASY_IMPLIMENT_H__
DECLARE_GE_KFIFO(ge_input_fifo, ge_input_event_t, 16, ge_input_fifo_t);
static int ge_input_send (ge_input_t* ctx, ge_input_event_t event) {
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
if (ge_kfifo_is_full(fifo)) {
return -1;
}
ge_kfifo_put(fifo, event);
return 0;
}
static int ge_input_peek (ge_input_t* ctx, ge_input_event_t* event) {
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
if (ge_kfifo_is_empty(fifo)) {
return -1;
}
ge_kfifo_peek(fifo, event);
return 0;
}
static int ge_input_recv (ge_input_t* ctx, ge_input_event_t* event) {
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
if (ge_kfifo_is_empty(fifo)) {
return -1;
}
ge_kfifo_get(fifo, event);
return 0;
}
#endif
#endif // __GE_INPUT_H__

View File

@@ -0,0 +1,236 @@
/*
* A generic kernel FIFO implementation
*
* Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __GE_KFIFO_H__
#define __GE_KFIFO_H__
/**
* 仿照linux内核中的kfifo实现
*/
#ifndef GE_MEMORY_BARRIR
#define GE_MEMORY_BARRIR() __sync_synchronize()
#endif
#ifndef GE_ARRAY_SIZE
#define GE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
struct __ge_kfifo {
unsigned int in;
unsigned int out;
unsigned int mask;
unsigned int esize;
void *data;
};
#define __STRUCT_GE_KFIFO(type, size) \
{ \
struct __ge_kfifo kfifo; \
type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
}
/**
* DECLARE_KFIFO - macro to declare a fifo object
* @fifo: name of the declared fifo
* @type: type of the fifo elements
* @size: the number of elements in the fifo, this must be a power of 2
*/
#define DECLARE_GE_KFIFO(fifo, type, size, tname) struct tname __STRUCT_GE_KFIFO(type, size) fifo
#define INIT_GE_KFIFO(fifo) do { \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__kfifo->in = 0; \
__kfifo->out = 0; \
__kfifo->mask = GE_ARRAY_SIZE((fifo)->buf) - 1; \
__kfifo->esize = sizeof(*((fifo)->buf)); \
__kfifo->data = (fifo)->buf; \
} while (0)
/**
* DEFINE_KFIFO - macro to define and initialize a fifo
* @fifo: name of the declared fifo datatype
* @type: type of the fifo elements
* @size: the number of elements in the fifo, this must be a power of 2
*
* Note: the macro can be used for global and local fifo data type variables.
*/
#define DEFINE_GE_KFIFO(fifo, type, size, tname) \
DECLARE_GE_KFIFO(fifo, type, size, tname) = \
(struct tname) { { \
.in = 0, \
.out = 0, \
.mask = GE_ARRAY_SIZE((fifo).buf) - 1, \
.esize = sizeof(*(fifo).buf), \
.data = (fifo).buf, \
}, { 0 } }
/**
* kfifo_size - returns the size of the fifo in elements
* @fifo: address of the fifo to be used
*/
#define ge_kfifo_size(fifo) \
((fifo)->kfifo.mask + 1)
/**
* kfifo_len - returns the number of used elements in the fifo
* @fifo: address of the fifo to be used
*/
#define ge_kfifo_len(fifo) \
((fifo)->kfifo.in - (fifo)->kfifo.out)
/**
* kfifo_is_empty - returns true if the fifo is empty
* @fifo: address of the fifo to be used
*/
#define ge_kfifo_is_empty(fifo) \
((fifo)->kfifo.in == (fifo)->kfifo.out)
/**
* kfifo_is_full - returns true if the fifo is full
* @fifo: address of the fifo to be used
*/
#define ge_kfifo_is_full(fifo) (ge_kfifo_len(fifo) > (fifo)->kfifo.mask)
/**
* kfifo_put - put data into the fifo
* @fifo: address of the fifo to be used
* @val: the data to be added
*
* This macro copies the given value into the fifo.
* It returns 0 if the fifo was full. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define ge_kfifo_put(fifo, val) do { \
unsigned int __ret; \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__ret = !ge_kfifo_is_full(fifo); \
if (__ret) { \
((fifo)->buf)[__kfifo->in & __kfifo->mask] = val; \
/*smp_wmb();*/ \
GE_MEMORY_BARRIR(); \
__kfifo->in++; \
} \
/*__ret;*/ \
} while(0)
/**
* kfifo_get - get data from the fifo
* @fifo: address of the fifo to be used
* @val: address where to store the data
*
* This macro reads the data from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define ge_kfifo_get(fifo, val) do { \
unsigned int __ret; \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__ret = !ge_kfifo_is_empty(fifo); \
if (__ret) { \
*val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \
/*smp_wmb();*/ \
GE_MEMORY_BARRIR(); \
__kfifo->out++; \
} \
/*__ret;*/ \
} while(0)
/**
* kfifo_peek - get data from the fifo without removing
* @fifo: address of the fifo to be used
* @val: address where to store the data
*
* This reads the data from the fifo without removing it from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define ge_kfifo_peek(fifo, val) do { \
unsigned int __ret; \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__ret = !ge_kfifo_is_empty(fifo); \
if (__ret) { \
*val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \
/*smp_wmb();*/ \
GE_MEMORY_BARRIR(); \
} \
/*__ret;*/ \
} while(0)
/**
* kfifo_in - put data into the fifo
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
*
* This macro copies the given buffer into the fifo and returns the
* number of copied elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
/*
#define kfifo_in(fifo, buf, n) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr_const) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_in(__kfifo, __buf, __n); \
})
*/
/**
* kfifo_out - get data from the fifo
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
*
* This macro gets some data from the fifo and returns the numbers of elements
* copied.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
/*
#define kfifo_out(fifo, buf, n) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out(__kfifo, __buf, __n); \
})
*/
#endif // __GE_KFIFO_H__

View File

@@ -0,0 +1,42 @@
#ifndef __GE_RENDER_H__
#define __GE_RENDER_H__
#include "ge_resource.h"
#include <windows.h>
typedef int ge_render_unit_t;
typedef COLORREF ge_render_color_t;
typedef struct ge_render_pos2 {
ge_render_unit_t x;
ge_render_unit_t y;
} ge_render_pos2_t;
typedef struct ge_render_rect {
ge_render_pos2_t pos;
ge_render_pos2_t size;
} ge_render_rect_t;
struct ge_render;
typedef struct ge_render ge_render_t;
typedef int(*ge_render_init_func_t) (ge_render_t* ctx, const ge_render_pos2_t* init_screen_size);
typedef int(*ge_render_flush_func_t) (ge_render_t* ctx);
typedef int(*ge_render_draw_point_func_t) (ge_render_t* ctx, const ge_render_pos2_t* pos, ge_render_color_t color);
typedef int(*ge_render_draw_rect_func_t) (ge_render_t* ctx, const ge_render_rect_t* rect, ge_render_color_t color);
typedef int(*ge_render_draw_text_func_t) (ge_render_t* ctx, const ge_render_pos2_t* pos, const char* text);
typedef int(*ge_render_draw_resource_func_t)(ge_render_t* ctx, const ge_render_pos2_t* pos, const ge_resource_t* res);
struct ge_render {
void* context;
ge_render_pos2_t screen_size;
ge_render_init_func_t init_func;
ge_render_flush_func_t func_flush;
ge_render_draw_point_func_t func_draw_point;
ge_render_draw_rect_func_t func_draw_rect;
ge_render_draw_text_func_t func_draw_text;
ge_render_draw_resource_func_t func_draw_res;
};
#endif // __GE_RENDER_H__

View File

@@ -0,0 +1,12 @@
#ifndef __GE_RESOURCE_H__
#define __GE_RESOURCE_H__
struct ge_resource;
typedef struct ge_resource ge_resource_t;
struct ge_resource {
int type;
void* context;
};
#endif // __GE_RESOURCE_H__

View File

@@ -0,0 +1,23 @@
#ifndef __GE_TIMER_H__
#define __GE_TIMER_H__
#include <stdint.h>
typedef uint64_t ge_time_t;
struct ge_timer;
typedef struct ge_timer ge_timer_t;
typedef ge_time_t(*ge_timer_getus_func_t)(ge_timer_t* timer);
typedef void(*ge_timer_sleepus_func_t)(const ge_timer_t* timer, ge_time_t time);
typedef ge_time_t(*ge_timer_getms_func_t)(ge_timer_t* timer);
typedef void(*ge_timer_sleepms_func_t)(const ge_timer_t* timer, ge_time_t time);
struct ge_timer {
ge_time_t time;
ge_timer_getms_func_t func_getms;
ge_timer_sleepms_func_t func_sleepms;
ge_timer_getus_func_t func_getus;
ge_timer_sleepus_func_t func_sleepus;
};
#endif // __GE_TIMER_H__

View File

@@ -0,0 +1,66 @@
// ge_fps.c
#include "ge_fps.h"
// 初始化FPS控制器
void ge_fps_init(ge_fps_controller_t* fps_ctrl, ge_u32_t target_fps,
ge_fps_get_us_func_t get_us, ge_fps_sleep_us_func_t sleep_us) {
fps_ctrl->target_fps = target_fps;
fps_ctrl->frame_duration = 1000 / target_fps;
fps_ctrl->last_frame_time = get_us();
fps_ctrl->frame_time = 0;
fps_ctrl->sleep_time = 0;
fps_ctrl->frame_count = 0;
fps_ctrl->fps = 0;
fps_ctrl->last_fps_time = fps_ctrl->last_frame_time;
fps_ctrl->call_get_us = get_us;
fps_ctrl->call_sleep_us = sleep_us;
}
// 帧开始
void ge_fps_begin_frame(ge_fps_controller_t* fps_ctrl) {
fps_ctrl->last_frame_time = fps_ctrl->call_get_us();
}
// 帧结束
void ge_fps_end_frame(ge_fps_controller_t* fps_ctrl) {
ge_u32_t current_time = fps_ctrl->call_get_us();
fps_ctrl->frame_time = current_time - fps_ctrl->last_frame_time;
// 帧率自适应算法
if (fps_ctrl->frame_time < fps_ctrl->frame_duration) {
ge_u32_t sleep_time = fps_ctrl->frame_duration - fps_ctrl->frame_time;
// 动态调整休眠精度
if (sleep_time > 2000) { // >2ms使用Sleep
fps_ctrl->call_sleep_us(sleep_time - 1000); // 提前1ms唤醒
current_time = fps_ctrl->call_get_us();
// 剩余时间忙等待
while ((current_time - fps_ctrl->last_frame_time) < fps_ctrl->frame_duration) {
current_time = fps_ctrl->call_get_us();
}
} else {
// 短时间直接忙等待
while ((fps_ctrl->call_get_us() - fps_ctrl->last_frame_time) < fps_ctrl->frame_duration);
}
}
// 更新FPS计数同原逻辑
fps_ctrl->frame_count++;
if (current_time - fps_ctrl->last_fps_time >= 1000000) {
fps_ctrl->fps = fps_ctrl->frame_count;
fps_ctrl->frame_count = 0;
fps_ctrl->last_fps_time = current_time;
// 动态调整目标帧时间±5%容差)
// ge_u32_t avg_frame_time = 1000000 / fps_ctrl->fps;
// if (avg_frame_time > fps_ctrl->frame_duration * 1.05f) {
// fps_ctrl->frame_duration = avg_frame_time;
// } else if (avg_frame_time < fps_ctrl->frame_duration * 0.95f) {
// fps_ctrl->frame_duration = GE_MAX(
// fps_ctrl->target_fps * 1000,
// avg_frame_time
// );
// }
}
}

View File

@@ -5,11 +5,11 @@
struct ge_fps_controller;
typedef struct ge_fps_controller ge_fps_controller_t;
typedef ge_u32_t (*ge_fps_get_ms_func_t)(void);
typedef void (*ge_fps_sleep_ms_func_t)(ge_u32_t ms);
typedef ge_u32_t (*ge_fps_get_us_func_t)(void);
typedef void (*ge_fps_sleep_us_func_t)(ge_u32_t us);
void ge_fps_init(ge_fps_controller_t* fps_ctrl, ge_u32_t target_fps,
ge_fps_get_ms_func_t get_ms, ge_fps_sleep_ms_func_t sleep_ms);
ge_fps_get_us_func_t get_ms, ge_fps_sleep_us_func_t sleep_ms);
void ge_fps_begin_frame(ge_fps_controller_t* fps_ctrl);
void ge_fps_end_frame(ge_fps_controller_t* fps_ctrl);
@@ -24,8 +24,8 @@ struct ge_fps_controller {
ge_u32_t fps; // 实际帧率
ge_u32_t last_fps_time; // 上次计算FPS的时间
ge_fps_get_ms_func_t call_get_ms;
ge_fps_sleep_ms_func_t call_sleep_ms;
ge_fps_get_us_func_t call_get_us;
ge_fps_sleep_us_func_t call_sleep_us;
};
#endif // __GE_FPS_H__

View File

@@ -7,9 +7,16 @@
typedef void (*ge_sleep_ms_func_t)(ge_u32_t);
typedef ge_u32_t (*ge_get_ms_func_t)(void);
typedef void (*ge_sleep_us_func_t)(ge_u32_t);
typedef ge_u32_t (*ge_get_us_func_t)(void);
typedef struct {
ge_sleep_ms_func_t sleep_ms;
ge_get_ms_func_t get_ms;
ge_sleep_us_func_t sleep_us;
ge_get_us_func_t get_us;
ge_fps_controller_t fps_ctl;
} ge_timer_t;

View File

@@ -5,8 +5,8 @@
* 提供跨平台的终端文本颜色和样式控制支持
*/
#ifndef __PYTHONIC_TERMINAL_COLOR_H__
#define __PYTHONIC_TERMINAL_COLOR_H__
#ifndef __PYNIC_TERMINAL_COLOR_H__
#define __PYNIC_TERMINAL_COLOR_H__
/// @name 前景色控制码
/// @{
@@ -56,4 +56,4 @@
#define ANSI_FMT(str, fmt) str ///< 禁用样式输出
#endif
#endif // __PYTHONIC_TERMINAL_COLOR_H__
#endif // __PYNIC_TERMINAL_COLOR_H__

View File

@@ -3,10 +3,10 @@
* @brief 模仿python标准库logger的日志系统核心模块支持多级日志、断言和异常处理
*/
#ifndef __PYTHONIC_LOG_H__
#define __PYTHONIC_LOG_H__
#ifndef __PYNIC_LOG_H__
#define __PYNIC_LOG_H__
#ifndef __NO_STDIO__
#ifndef __PYNIC_NO_STDIO__
#include <stdio.h>
#include <stdlib.h>
@@ -21,11 +21,11 @@
#endif
#endif
#ifndef __NO_PYNIC_COLOR__
#ifndef __PYNIC_NO_COLOR__
#include "pynic_color.h"
#else
#ifndef __LOG_NO_COLOR__
#define __LOG_NO_COLOR__
#ifndef __PYNIC_LOG_NO_COLOR__
#define __PYNIC_LOG_NO_COLOR__
#endif
#endif
@@ -50,7 +50,7 @@
#endif
#define _PYNIC_STR(str) #str
#define PYLIKE_STR(str) _PYNIC_STR(str)
#define PYNIC_STR(str) _PYNIC_STR(str)
/**
* @brief 日志级别枚举
@@ -199,7 +199,7 @@ void log_set_handler(logger_t* logger, pynic_log_handler handler);
#define AssertFmt(cond, format, ...) _Assert(cond, "Assertion Failure: " format, ## __VA_ARGS__) ///< 带格式的断言检查
#define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) ///< 立即触发致命错误
#ifndef Assert
#define Assert(cond) AssertFmt(cond, "cond is `" PYLIKE_STR(cond) "`") ///< 基础断言检查
#define Assert(cond) AssertFmt(cond, "cond is `" PYNIC_STR(cond) "`") ///< 基础断言检查
#endif
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
#define TODO() PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
@@ -219,7 +219,7 @@ static inline const char* pynic_level_str(log_level_t level) {
return level_str;
}
#ifdef __PYTHONIC_TERMINAL_COLOR_H__
#ifdef __PYNIC_TERMINAL_COLOR_H__
static inline const char* pynic_level_color(log_level_t level) {
const char* color_code = ANSI_NONE;
switch (level) {
@@ -237,11 +237,11 @@ static inline const char* pynic_level_color(log_level_t level) {
#ifdef __PYNIC_LOG_IMPLIMENT__
static void default_handler(log_level_t level, const char* module, const char* file, int line, const char* message) {
static void __pynic_log_default_handler(log_level_t level, const char* module, const char* file, int line, const char* message) {
const char* level_str = pynic_level_str(level);
/// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出
#ifndef __LOG_NO_COLOR__
/// @note: 定义 __PYNIC_LOG_NO_COLOR__ 会取消颜色输出
#ifndef __PYNIC_LOG_NO_COLOR__
_pynic_logout_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n",
pynic_level_color(level), level_str, module, file, line, message);
#else
@@ -256,7 +256,7 @@ static void default_handler(log_level_t level, const char* module, const char* f
static logger_t __pynic_root_logger = {
.name = "root",
.level = LOG_LEVEL_ALL,
.handler = default_handler,
.handler = __pynic_log_default_handler,
};
void init_logger(logger_t* logger, const char* name) {
@@ -265,7 +265,7 @@ void init_logger(logger_t* logger, const char* name) {
void init_logger_ex(logger_t* logger, const char* name, pynic_log_handler hander) {
logger->name = name;
logger->handler = hander ? hander : default_handler;
logger->handler = hander ? hander : __pynic_log_default_handler;
log_set_level(logger, LOG_LEVEL_ALL);
}
@@ -285,4 +285,4 @@ void log_set_handler(logger_t* logger, pynic_log_handler handler) {
}
#endif
#endif // __PYTHONIC_LOG_H__
#endif // __PYNIC_LOG_H__

View File

@@ -1,30 +0,0 @@
#ifndef __GE_RENDER_H__
#define __GE_RENDER_H__
#include <ge_common.h>
struct ge_render_ctx;
typedef struct ge_render_ctx ge_render_t;
typedef void (*ge_render_init_func_t)(ge_render_t* ctx);
typedef void (*ge_render_clear_func_t)(ge_render_t* ctx);
typedef void (*ge_render_draw_func_t)
(ge_render_t* ctx, ge_vector2i_t pos, const char* data);
typedef void (*ge_render_drawex_func_t)
(ge_render_t* ctx, ge_vector2i_t pos, const char* data, const void* propety);
typedef void (*ge_render_getsize_func_t)
(ge_render_t* ctx, ge_vector2i_t *size);
typedef void (*ge_render_push_event)
(ge_render_t* ctx, void* event);
struct ge_render_ctx {
const void* content;
ge_vector2i_t screen_size;
ge_render_init_func_t init;
ge_render_clear_func_t clear;
ge_render_draw_func_t draw;
ge_render_drawex_func_t drawex;
ge_render_getsize_func_t getsize;
};
#endif // __GE_RENDER_H__

View File

@@ -1,38 +0,0 @@
#ifndef __GE_RESOURCES_H__
#define __GE_RESOURCES_H__
#include <ge_common.h>
typedef struct {
} ge_res_bmp_t;
typedef struct {
ge_uid_t res_id;
const char* data;
} ge_drawable_t;
/*
tank 3 * 3 (0)
"|\n"
" # \n"
"###\n"
"###\n"
wall 3 * 3 (1)
"@@@\n"
"@@@\n"
"@@@\n"
tilemap 3 * 3
"1,1,1\n"
"-1,1,0\n"
"1,0,1\n"
exece
{qiang}
"@@@\n""@@@\n"
"@@@\n""@@@\n"
"@@@\n""@@@\n"
*/
#endif // __GE_RESOURCES_H__

View File

@@ -1,53 +0,0 @@
// ge_fps.c
#include "ge_fps.h"
// 初始化FPS控制器
void ge_fps_init(ge_fps_controller_t* fps_ctrl, ge_u32_t target_fps,
ge_fps_get_ms_func_t get_ms, ge_fps_sleep_ms_func_t sleep_ms) {
fps_ctrl->target_fps = target_fps;
fps_ctrl->frame_duration = 1000 / target_fps;
fps_ctrl->last_frame_time = get_ms();
fps_ctrl->frame_time = 0;
fps_ctrl->sleep_time = 0;
fps_ctrl->frame_count = 0;
fps_ctrl->fps = 0;
fps_ctrl->last_fps_time = fps_ctrl->last_frame_time;
fps_ctrl->call_get_ms = get_ms;
fps_ctrl->call_sleep_ms = sleep_ms;
}
// 帧开始
void ge_fps_begin_frame(ge_fps_controller_t* fps_ctrl) {
fps_ctrl->last_frame_time = fps_ctrl->call_get_ms();
}
// 帧结束
void ge_fps_end_frame(ge_fps_controller_t* fps_ctrl) {
// 计算当前帧耗时
ge_u32_t current_time = fps_ctrl->call_get_ms();
fps_ctrl->frame_time = current_time - fps_ctrl->last_frame_time;
// 计算需要休眠的时间
if (fps_ctrl->frame_time < fps_ctrl->frame_duration) {
fps_ctrl->sleep_time = fps_ctrl->frame_duration - fps_ctrl->frame_time;
// 高精度休眠
fps_ctrl->call_sleep_ms(fps_ctrl->sleep_time);
// 更新实际休眠后时间
current_time = fps_ctrl->call_get_ms();
fps_ctrl->sleep_time = current_time - fps_ctrl->last_frame_time - fps_ctrl->frame_time;
} else {
fps_ctrl->sleep_time = 0;
}
// 更新FPS计数
fps_ctrl->frame_count++;
// 每秒计算一次实际FPS
if (current_time - fps_ctrl->last_fps_time >= 1000) {
fps_ctrl->fps = fps_ctrl->frame_count;
fps_ctrl->frame_count = 0;
fps_ctrl->last_fps_time = current_time;
}
}

View File

@@ -54,13 +54,13 @@ struct __ge_kfifo {
*/
#define DECLARE_GE_KFIFO(fifo, type, size, tname) struct tname __STRUCT_GE_KFIFO(type, size) fifo
#define INIT_GE_KFIFO(fifo, type) do { \
#define INIT_GE_KFIFO(fifo) do { \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__kfifo->in = 0; \
__kfifo->out = 0; \
__kfifo->mask = GE_ARRAY_SIZE((fifo).buf) - 1; \
__kfifo->esize = sizeof(*(fifo).buf); \
__kfifo->data = (fifo).buf; \
__kfifo->mask = GE_ARRAY_SIZE((fifo)->buf) - 1; \
__kfifo->esize = sizeof(*((fifo)->buf)); \
__kfifo->data = (fifo)->buf; \
} while (0)
/**
@@ -173,7 +173,7 @@ struct __ge_kfifo {
#define ge_kfifo_peek(fifo, val) do { \
unsigned int __ret; \
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
__ret = !kfifo_is_empty(fifo); \
__ret = !ge_kfifo_is_empty(fifo); \
if (__ret) { \
*val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \
/*smp_wmb();*/ \

View File

@@ -14,7 +14,7 @@
#undef GE_ABS
#define GE_ABS(x) ((x) > 0 ? (x) : -(x))
#endif
typedef int ge_unit_t; /**< 坐标值类型定义 */
typedef int32_t ge_unit_t; /**< 坐标值类型定义 */
/**
* @struct ge_vector2_t