feat(engine): 重构游戏引擎核心逻辑
- 重新设计了引擎的初始化和运行流程 - 引入了实体组件系统(ECS)和物理系统 - 优化了渲染系统和输入系统 - 移除了不必要的资源管理系统 - 调整了日志系统的实现
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,8 @@
|
|||||||
!.gitignore
|
!.gitignore
|
||||||
build/
|
build/
|
||||||
test/
|
test/
|
||||||
|
resource/
|
||||||
|
embedding/
|
||||||
*.txt
|
*.txt
|
||||||
|
|
||||||
*.obj
|
*.obj
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# 编译器设置
|
# 编译器设置
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -Wall -Wextra -g -I../game_engine
|
CFLAGS = -Wall -Wextra -g -I../game_engine
|
||||||
LDFLAGS =
|
LDFLAGS = -lgdi32
|
||||||
|
|
||||||
# 目录设置
|
# 目录设置
|
||||||
ROOT_DIR := .
|
ROOT_DIR := .
|
||||||
@@ -10,18 +10,9 @@ ENGINE_DIR := ../game_engine
|
|||||||
|
|
||||||
# 手动指定源文件目录
|
# 手动指定源文件目录
|
||||||
SRC_DIRS = $(ROOT_DIR) \
|
SRC_DIRS = $(ROOT_DIR) \
|
||||||
$(ROOT_DIR)/test \
|
$(ROOT_DIR)/plantform/win_app \
|
||||||
$(ROOT_DIR)/plantform \
|
$(ENGINE_DIR)
|
||||||
$(ROOT_DIR)/plantform/win_term \
|
|
||||||
$(ENGINE_DIR) \
|
|
||||||
$(ENGINE_DIR)/components \
|
|
||||||
$(ENGINE_DIR)/events \
|
|
||||||
$(ENGINE_DIR)/physics \
|
|
||||||
$(ENGINE_DIR)/pynic_log \
|
|
||||||
$(ENGINE_DIR)/render \
|
|
||||||
$(ENGINE_DIR)/resources \
|
|
||||||
$(ENGINE_DIR)/timer \
|
|
||||||
$(ENGINE_DIR)/utils
|
|
||||||
|
|
||||||
SRCS = $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
|
SRCS = $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
|
||||||
OBJS := $(patsubst $(ROOT_DIR)/%.c,$(BUILD_DIR)/core/%.o,$(filter $(ROOT_DIR)/%,$(SRCS)))
|
OBJS := $(patsubst $(ROOT_DIR)/%.c,$(BUILD_DIR)/core/%.o,$(filter $(ROOT_DIR)/%,$(SRCS)))
|
||||||
|
|||||||
22
game_core/ge_color.h
Normal file
22
game_core/ge_color.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef __GE_COLOR_H__
|
||||||
|
#define __GE_COLOR_H__
|
||||||
|
|
||||||
|
// 基础颜色宏
|
||||||
|
#define GE_COLOR_BLACK RGB(0, 0, 0)
|
||||||
|
#define GE_COLOR_WHITE RGB(255, 255, 255)
|
||||||
|
#define GE_COLOR_RED RGB(255, 0, 0)
|
||||||
|
#define GE_COLOR_GREEN RGB(0, 255, 0)
|
||||||
|
#define GE_COLOR_BLUE RGB(0, 0, 255)
|
||||||
|
#define GE_COLOR_YELLOW RGB(255, 255, 0)
|
||||||
|
#define GE_COLOR_CYAN RGB(0, 255, 255)
|
||||||
|
#define GE_COLOR_MAGENTA RGB(255, 0, 255)
|
||||||
|
#define GE_COLOR_GRAY RGB(128, 128, 128)
|
||||||
|
|
||||||
|
// 扩展颜色宏
|
||||||
|
#define GE_COLOR_DARK_RED RGB(139, 0, 0)
|
||||||
|
#define GE_COLOR_DARK_GREEN RGB(0, 100, 0)
|
||||||
|
#define GE_COLOR_DARK_BLUE RGB(0, 0, 139)
|
||||||
|
#define GE_COLOR_ORANGE RGB(255, 165, 0)
|
||||||
|
#define GE_COLOR_PURPLE RGB(128, 0, 128)
|
||||||
|
|
||||||
|
#endif // __GE_COLOR_H__
|
||||||
127
game_core/main.c
127
game_core/main.c
@@ -1,12 +1,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "ge_color.h"
|
||||||
|
|
||||||
#define GE_VEC2I_USE_SHORT_NAMES
|
#define GE_VEC2I_USE_SHORT_NAMES
|
||||||
#define _pynic_logout_printf(...) fprintf(fp , ##__VA_ARGS__)
|
#define _pynic_logout_printf(...) fprintf(fp , ##__VA_ARGS__)
|
||||||
|
|
||||||
#include <ge_core.h>
|
#include <ge_core.h>
|
||||||
#include "plantform/win_term/interface.h"
|
// #include "plantform/win_term/interface.h"
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
logger_t logger;
|
logger_t logger;
|
||||||
|
|
||||||
@@ -17,56 +18,96 @@ static void log_handler
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_BULLET 16
|
||||||
|
#define BASIC_SPEED (1 << GE_PHYSICS_VELOCITY_BIT)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ge_entity_t* player;
|
||||||
|
ge_entity_t* bullet[MAX_BULLET];
|
||||||
|
ge_render_rect_t screen;
|
||||||
|
} game_ctx_t;
|
||||||
|
|
||||||
void init(ge_core_t* core) {
|
void init(ge_core_t* core) {
|
||||||
register_win_term(core);
|
(void)core;
|
||||||
register_win_timer(core);
|
fp = fopen("D:\\Git_Code\\school_stm32\\game_core\\log.txt", "w+");
|
||||||
fp = fopen("./log.txt", "w+");
|
|
||||||
init_logger_ex(&logger, "game", log_handler);
|
init_logger_ex(&logger, "game", log_handler);
|
||||||
Assert(fp != NULL);
|
Assert(fp != NULL);
|
||||||
|
|
||||||
|
static game_ctx_t ctx = { 0 };
|
||||||
|
ge_ecs_add_entity(&core->ecs, &ctx.player);
|
||||||
|
ctx.player->component_mask = GE_COMPONENT_ACVIVE | GE_RENDERABLE_MASK;
|
||||||
|
ctx.player->position = (ge_vector2i_t){ 32, 32 };
|
||||||
|
ctx.player->renderable = (ge_render_component_t) {
|
||||||
|
.type = GE_RENDER_COMPONENT_TYPE_RECT,
|
||||||
|
.data.rect = {
|
||||||
|
.size = {8, 8},
|
||||||
|
.color = GE_COLOR_YELLOW,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_BULLET; ++i) {
|
||||||
|
ge_ecs_add_entity(&core->ecs, &ctx.bullet[i]);
|
||||||
|
ctx.bullet[i]->component_mask = GE_RENDERABLE_MASK | GE_PHYSICS_MASK;
|
||||||
|
ctx.bullet[i]->renderable = (ge_render_component_t) {
|
||||||
|
.type = GE_RENDER_COMPONENT_TYPE_RECT,
|
||||||
|
.data.rect = {
|
||||||
|
.size = {2, 2},
|
||||||
|
.color = GE_COLOR_RED,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.bullet[i]->physics_body = (ge_physics_component_t) {
|
||||||
|
.type = GE_PHYSICS_COMPONENT_TYPE_VELOCITY,
|
||||||
|
.velocity = { 0, - BASIC_SPEED / 2},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.screen = (ge_render_rect_t) {
|
||||||
|
.pos = {0, 0},
|
||||||
|
.size = core->_render.screen_size,
|
||||||
|
};
|
||||||
|
core->context = &ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ge_core_t* core) {
|
void process(ge_core_t* core) {
|
||||||
static ge_vector2i_t pos = vec2i(0, 0);
|
game_ctx_t* ctx = (game_ctx_t*)core->context;
|
||||||
// LOG_INFO("vec2: %d, %d", a.x, a.y);
|
core->_render.func_draw_rect(&core->_render, &ctx->screen, GE_COLOR_WHITE);
|
||||||
|
ge_vector2i_t* pos = &ctx->player->position;
|
||||||
|
|
||||||
int key = terminal_get_key((win_term_t*)core->render.content);
|
ge_input_event_t key;
|
||||||
switch (key) {
|
if (!core->_input.func_recv(&core->_input, &key)) {
|
||||||
case 'w':
|
switch (key.num) {
|
||||||
MLOG_INFO(&logger, "w");
|
case 'w':
|
||||||
core->render.clear(&core->render);
|
MLOG_INFO(&logger, "w");
|
||||||
pos = vec2i_add(pos, GE_VEC2I_UP);
|
*pos = vec2i_add(*pos, GE_VEC2I_UP);
|
||||||
core->render.draw(&core->render, pos, "@");
|
break;
|
||||||
break;
|
case 'a':
|
||||||
case 'a':
|
MLOG_INFO(&logger, "a");
|
||||||
MLOG_INFO(&logger, "a");
|
*pos = vec2i_add(*pos, GE_VEC2I_LEFT);
|
||||||
core->render.clear(&core->render);
|
break;
|
||||||
pos = vec2i_add(pos, GE_VEC2I_LEFT);
|
case 's':
|
||||||
core->render.draw(&core->render, pos, "@");
|
MLOG_INFO(&logger, "s");
|
||||||
break;
|
*pos = vec2i_add(*pos, GE_VEC2I_DOWN);
|
||||||
case 's':
|
break;
|
||||||
MLOG_INFO(&logger, "s");
|
case 'd':
|
||||||
core->render.clear(&core->render);
|
MLOG_INFO(&logger, "d");
|
||||||
pos = vec2i_add(pos, GE_VEC2I_DOWN);
|
*pos = vec2i_add(*pos, GE_VEC2I_RIGHT);
|
||||||
core->render.draw(&core->render, pos, "@");
|
break;
|
||||||
break;
|
case 'f':
|
||||||
case 'd':
|
ctx->bullet[0]->component_mask |= GE_COMPONENT_ACVIVE;
|
||||||
MLOG_INFO(&logger, "d");
|
ctx->bullet[0]->position.x = pos->x + 4; // TODO
|
||||||
core->render.clear(&core->render);
|
ctx->bullet[0]->position.y = pos->y; // TODO
|
||||||
pos = vec2i_add(pos, GE_VEC2I_RIGHT);
|
break;
|
||||||
core->render.draw(&core->render, pos, "@");
|
case 'q':
|
||||||
break;
|
core->state = GE_ENGINE_STATE_EXIT;
|
||||||
case 'q':
|
MLOG_INFO(&logger, "exit");
|
||||||
core->state = GE_ENGINE_STATE_EXIT;
|
break;
|
||||||
MLOG_INFO(&logger, "exit");
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int ge_main(ge_core_t* core) {
|
||||||
ge_core_t core;
|
core->callbacks.init = init;
|
||||||
ge_engine_init(&core);
|
core->callbacks.process = process;
|
||||||
core.callbacks.init = init;
|
ge_engine_run(core);
|
||||||
core.callbacks.run = run;
|
|
||||||
ge_engine_run(&core);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
10
game_core/plantform/win_app/win_interface.h
Normal file
10
game_core/plantform/win_app/win_interface.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __WIN_INTERFACE_H__
|
||||||
|
#define __WIN_INTERFACE_H__
|
||||||
|
|
||||||
|
#include <ge_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
void win_sleep_us(ge_u32_t us);
|
||||||
|
ge_u32_t win_get_us(void);
|
||||||
|
|
||||||
|
#endif // __WIN_INTERFACE_H__
|
||||||
293
game_core/plantform/win_app/win_main.c
Normal file
293
game_core/plantform/win_app/win_main.c
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include "win_interface.h"
|
||||||
|
#include <ge_core.h>
|
||||||
|
|
||||||
|
|
||||||
|
// 自定义渲染上下文结构体(包含双缓冲资源)
|
||||||
|
typedef struct {
|
||||||
|
HWND hwnd; // 窗口句柄
|
||||||
|
HDC hdc_front; // 前台设备上下文
|
||||||
|
HDC hdc_back; // 后台缓冲区设备上下文
|
||||||
|
HBITMAP hbm_back; // 后台位图
|
||||||
|
HBITMAP hbm_old; // 保存原始位图(用于恢复)
|
||||||
|
RECT client_rect; // 窗口客户区大小
|
||||||
|
} win_render_context_t;
|
||||||
|
|
||||||
|
// 双缓冲初始化函数
|
||||||
|
static void win_render_init(ge_render_t* ctx, const ge_render_pos2_t* init_screen_size) {
|
||||||
|
(void) init_screen_size;
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
HDC hdc = GetDC(wctx->hwnd);
|
||||||
|
|
||||||
|
// 获取窗口尺寸
|
||||||
|
GetClientRect(wctx->hwnd, &wctx->client_rect);
|
||||||
|
int width = wctx->client_rect.right - wctx->client_rect.left;
|
||||||
|
int height = wctx->client_rect.bottom - wctx->client_rect.top;
|
||||||
|
|
||||||
|
// 创建双缓冲资源
|
||||||
|
wctx->hdc_front = hdc;
|
||||||
|
wctx->hdc_back = CreateCompatibleDC(hdc);
|
||||||
|
wctx->hbm_back = CreateCompatibleBitmap(hdc, width, height);
|
||||||
|
wctx->hbm_old = (HBITMAP)SelectObject(wctx->hdc_back, wctx->hbm_back);
|
||||||
|
|
||||||
|
// 保存屏幕尺寸到渲染上下文
|
||||||
|
ctx->screen_size.x = width;
|
||||||
|
ctx->screen_size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空后台缓冲区
|
||||||
|
static void win_render_draw_rect(ge_render_t* ctx, const ge_render_rect_t* rect, ge_render_color_t color) {
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
RECT win_rect = {
|
||||||
|
.top = rect->pos.y,
|
||||||
|
.bottom = rect->pos.y + rect->size.y,
|
||||||
|
.left = rect->pos.x,
|
||||||
|
.right = rect->pos.x + rect->size.x,
|
||||||
|
};
|
||||||
|
win_rect.bottom *= 4;
|
||||||
|
win_rect.right *= 4;
|
||||||
|
win_rect.left *= 4;
|
||||||
|
win_rect.top *= 4;
|
||||||
|
HBRUSH brush = CreateSolidBrush(color); // WHITE background
|
||||||
|
|
||||||
|
FillRect(wctx->hdc_back, &win_rect, brush);
|
||||||
|
DeleteObject(brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将后台缓冲区复制到屏幕(双缓冲交换)
|
||||||
|
static void win_render_flush(ge_render_t* ctx) {
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
BitBlt(wctx->hdc_front,
|
||||||
|
0, 0,
|
||||||
|
wctx->client_rect.right,
|
||||||
|
wctx->client_rect.bottom,
|
||||||
|
wctx->hdc_back,
|
||||||
|
0, 0,
|
||||||
|
SRCCOPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_render_draw_text(ge_render_t* ctx, const ge_render_pos2_t* pos, const char* text) {
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
// 使用GDI函数在 wctx->hdc_back 上绘制
|
||||||
|
TextOut(wctx->hdc_back, pos->x, pos->y, text, strlen(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 键盘事件处理函数(将按键转换为字符)
|
||||||
|
static char win_key_to_char(WPARAM wParam, LPARAM lParam) {
|
||||||
|
BYTE keyboardState[256] = {0};
|
||||||
|
WORD charBuffer = 0;
|
||||||
|
|
||||||
|
// 获取当前键盘状态
|
||||||
|
GetKeyboardState(keyboardState);
|
||||||
|
|
||||||
|
// 将虚拟键码转换为ASCII字符
|
||||||
|
if (ToAscii((UINT)wParam, (UINT)((lParam >> 16) & 0xFF),
|
||||||
|
keyboardState, &charBuffer, 0) > 0) {
|
||||||
|
// // 只返回可打印字符(ASCII 32-126)
|
||||||
|
// if (charBuffer >= 32 && charBuffer <= 126) {
|
||||||
|
return (char)charBuffer;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return 0; // 不可打印字符或转换失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窗口过程函数
|
||||||
|
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
ge_core_t* core = (ge_core_t*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
|
|
||||||
|
switch (uMsg) {
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (!core) {
|
||||||
|
goto END;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将按键转换为字符
|
||||||
|
char ch = win_key_to_char(wParam, lParam);
|
||||||
|
ge_input_event_t event;
|
||||||
|
if (ch != 0) {
|
||||||
|
// 将字符放入事件缓冲区
|
||||||
|
event.num = ch;
|
||||||
|
core->_input.func_send(&core->_input, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case WM_DESTROY:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
core->state = GE_ENGINE_STATE_EXIT;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
END:
|
||||||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_render_getsize(ge_render_t* ctx, ge_vector2i_t* size) {
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
|
||||||
|
GetClientRect(wctx->hwnd, &wctx->client_rect);
|
||||||
|
ctx->screen_size.x = wctx->client_rect.right - wctx->client_rect.left;
|
||||||
|
ctx->screen_size.y = wctx->client_rect.bottom - wctx->client_rect.top;
|
||||||
|
|
||||||
|
size->x = ctx->screen_size.x;
|
||||||
|
size->x = ctx->screen_size.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows计时函数
|
||||||
|
static ge_u32_t win_get_ms(void* ctx) {
|
||||||
|
return GetTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_sleep_ms(void* ctx, ge_u32_t ms) {
|
||||||
|
Sleep(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_run_at_frame(ge_core_t* core) {
|
||||||
|
static MSG msg;
|
||||||
|
const win_render_context_t* xctx = (win_render_context_t*)core->_inner_context;
|
||||||
|
|
||||||
|
while (PeekMessage(&msg, xctx->hwnd, 0, 0, 0)) {
|
||||||
|
GetMessage(&msg, NULL, 0, 0);
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void win_render_drawex(ge_render_t* ctx, ge_vector2i_t pos, const char* data, const void* propety) {
|
||||||
|
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||||
|
|
||||||
|
// 将 data 转换为 HBITMAP (假设传入的是位图句柄)
|
||||||
|
HBITMAP hBitmap = (HBITMAP)data;
|
||||||
|
|
||||||
|
// 创建兼容的内存设备上下文
|
||||||
|
HDC hdcMem = CreateCompatibleDC(wctx->hdc_back);
|
||||||
|
|
||||||
|
// 将位图选入内存设备上下文
|
||||||
|
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);
|
||||||
|
|
||||||
|
// 获取位图尺寸
|
||||||
|
BITMAP bitmap;
|
||||||
|
GetObject(hBitmap, sizeof(BITMAP), &bitmap);
|
||||||
|
|
||||||
|
// 绘制位图到后台缓冲区
|
||||||
|
BitBlt(
|
||||||
|
wctx->hdc_back, // 目标设备上下文
|
||||||
|
pos.x, // 目标左上角X
|
||||||
|
pos.y, // 目标左上角Y
|
||||||
|
bitmap.bmWidth, // 位图宽度
|
||||||
|
bitmap.bmHeight, // 位图高度
|
||||||
|
hdcMem, // 源设备上下文
|
||||||
|
0, // 源左上角X
|
||||||
|
0, // 源左上角Y
|
||||||
|
SRCCOPY // 光栅操作码
|
||||||
|
);
|
||||||
|
|
||||||
|
// 清理资源
|
||||||
|
SelectObject(hdcMem, hOldBitmap);
|
||||||
|
DeleteDC(hdcMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主游戏逻辑函数
|
||||||
|
int ge_main(ge_core_t* core);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows入口点
|
||||||
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||||
|
(void) hPrevInstance;
|
||||||
|
(void) lpCmdLine;
|
||||||
|
// 创建窗口
|
||||||
|
wchar_t CLASS_NAME[] = L"GameWindow";
|
||||||
|
|
||||||
|
WNDCLASS wc = {0};
|
||||||
|
wc.lpfnWndProc = WindowProc;
|
||||||
|
wc.hInstance = hInstance;
|
||||||
|
wc.lpszClassName = CLASS_NAME;
|
||||||
|
|
||||||
|
RegisterClass(&wc);
|
||||||
|
|
||||||
|
HWND hwnd = CreateWindowEx(
|
||||||
|
0,
|
||||||
|
CLASS_NAME,
|
||||||
|
"Game Engine",
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, 128 * 4, 128 * 4,
|
||||||
|
NULL, NULL, hInstance, NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hwnd == NULL) return 0;
|
||||||
|
|
||||||
|
// 初始化引擎核心
|
||||||
|
static ge_core_t core;
|
||||||
|
ge_engine_init(&core);
|
||||||
|
|
||||||
|
// 创建双缓冲上下文
|
||||||
|
win_render_context_t* wctx = (win_render_context_t*)malloc(sizeof(win_render_context_t));
|
||||||
|
wctx->hwnd = hwnd;
|
||||||
|
|
||||||
|
// 配置渲染器
|
||||||
|
core._render.context = wctx;
|
||||||
|
core._render.init_func = (ge_render_init_func_t)win_render_init;
|
||||||
|
core._render.func_flush = (ge_render_flush_func_t)win_render_flush;
|
||||||
|
core._render.func_draw_text = (ge_render_draw_text_func_t)win_render_draw_text;
|
||||||
|
core._render.func_draw_rect = (ge_render_draw_rect_func_t)win_render_draw_rect;
|
||||||
|
|
||||||
|
// // 初始化渲染器
|
||||||
|
// if (core->render.init) core->render.init(&core->render);
|
||||||
|
|
||||||
|
// 配置计时器
|
||||||
|
core._timer.func_getms = (ge_timer_getms_func_t)win_get_ms;
|
||||||
|
core._timer.func_sleepms = (ge_timer_sleepms_func_t)win_sleep_ms;
|
||||||
|
|
||||||
|
core._inner_run = win_run_at_frame;
|
||||||
|
core._inner_context = wctx;
|
||||||
|
|
||||||
|
INIT_GE_KFIFO(&ge_input_fifo);
|
||||||
|
core._input.context = &ge_input_fifo;
|
||||||
|
core._input.func_send = ge_input_send;
|
||||||
|
core._input.func_peek = ge_input_peek;
|
||||||
|
core._input.func_recv = ge_input_recv;
|
||||||
|
|
||||||
|
// 将core指针关联到窗口
|
||||||
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&core);
|
||||||
|
|
||||||
|
ShowWindow(hwnd, nCmdShow);
|
||||||
|
UpdateWindow(hwnd);
|
||||||
|
// 运行主游戏逻辑
|
||||||
|
ge_main(&core);
|
||||||
|
|
||||||
|
// 清理资源
|
||||||
|
SelectObject(wctx->hdc_back, wctx->hbm_old);
|
||||||
|
DeleteObject(wctx->hbm_back);
|
||||||
|
DeleteDC(wctx->hdc_back);
|
||||||
|
ReleaseDC(hwnd, wctx->hdc_front);
|
||||||
|
free(wctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
31
game_core/plantform/win_app/win_timer.c
Normal file
31
game_core/plantform/win_app/win_timer.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <ge_common.h>
|
||||||
|
|
||||||
|
// 获取当前时间(微秒)
|
||||||
|
ge_u32_t win_get_us(void) {
|
||||||
|
static LARGE_INTEGER frequency;
|
||||||
|
static BOOL initialized = FALSE;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
QueryPerformanceFrequency(&frequency);
|
||||||
|
initialized = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER counter;
|
||||||
|
QueryPerformanceCounter(&counter);
|
||||||
|
return (ge_u32_t)((counter.QuadPart * 1000000) / frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 微秒级休眠
|
||||||
|
void win_sleep_us(ge_u32_t us) {
|
||||||
|
if (us < 1000) {
|
||||||
|
// 短时间使用忙等待
|
||||||
|
ge_u32_t start = win_get_us();
|
||||||
|
while ((win_get_us() - start) < us) {
|
||||||
|
// 空循环
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 长时间使用Sleep
|
||||||
|
Sleep(us / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ static inline void register_win_term(ge_core_t* core);
|
|||||||
void win_sleep_ms(uint32_t ms);
|
void win_sleep_ms(uint32_t ms);
|
||||||
uint32_t win_get_timer_ms();
|
uint32_t win_get_timer_ms();
|
||||||
static inline void register_win_timer(ge_core_t* core) {
|
static inline void register_win_timer(ge_core_t* core) {
|
||||||
core->timer.sleep_ms = (ge_sleep_ms_func_t)win_sleep_ms;
|
core->_timer.sleep_ms = (ge_sleep_ms_func_t)win_sleep_ms;
|
||||||
core->timer.get_ms = (ge_get_ms_func_t)win_get_timer_ms;
|
core->_timer.get_ms = (ge_get_ms_func_t)win_get_timer_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void win_render_draw(ge_render_t* ctx, ge_vector2i_t pos, const char* data) {
|
static void win_render_draw(ge_render_t* ctx, ge_vector2i_t pos, const char* data) {
|
||||||
@@ -44,7 +44,7 @@ static void win_render_draw(ge_render_t* ctx, ge_vector2i_t pos, const char* dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 普通字符处理
|
// 普通字符处理
|
||||||
char char_str[2] = { *ptr, '\0' };
|
char char_str[2] = { *ptr };
|
||||||
terminal_print(term, current_x, current_y, char_str);
|
terminal_print(term, current_x, current_y, char_str);
|
||||||
|
|
||||||
current_x++;
|
current_x++;
|
||||||
@@ -61,14 +61,19 @@ static void win_render_getsize(ge_render_t* ctx, ge_vector2i_t* size) {
|
|||||||
size->x = terminal_get_width((win_term_t*)ctx->content);
|
size->x = terminal_get_width((win_term_t*)ctx->content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void win_render_flush(ge_render_t* ctx) {
|
||||||
|
terminal_flush((win_term_t*)ctx->content);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void register_win_term(ge_core_t* core) {
|
static inline void register_win_term(ge_core_t* core) {
|
||||||
win_term_t* ctx = terminal_init();
|
win_term_t* ctx = terminal_init();
|
||||||
Assert(ctx != NULL);
|
Assert(ctx != NULL);
|
||||||
core->render.content = ctx;
|
core->_render.content = ctx;
|
||||||
core->render.init = NULL;
|
core->_render.init = NULL;
|
||||||
core->render.draw = win_render_draw;
|
core->_render.draw = win_render_draw;
|
||||||
core->render.clear = win_render_clear;
|
core->_render.clear = win_render_clear;
|
||||||
core->render.getsize = win_render_getsize;
|
core->_render.getsize = win_render_getsize;
|
||||||
|
core->_render.flush = win_render_flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __WIN_TERM_INTERFACE_H__
|
#endif // __WIN_TERM_INTERFACE_H__
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <pynic_log/pynic_log.h>
|
||||||
#include "win_term.h"
|
#include "win_term.h"
|
||||||
|
|
||||||
// 终端抽象结构体
|
// 终端抽象结构体
|
||||||
@@ -9,35 +10,108 @@ struct win_term {
|
|||||||
HANDLE hStdout;
|
HANDLE hStdout;
|
||||||
HANDLE hStdin;
|
HANDLE hStdin;
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
char buffer[120 * 30 + 120 * 30];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ESC "\x1b"
|
||||||
|
#define CSI "\x1b["
|
||||||
|
|
||||||
// 初始化终端
|
// 初始化终端
|
||||||
win_term_t* terminal_init() {
|
win_term_t* terminal_init() {
|
||||||
win_term_t* term = malloc(sizeof(win_term_t));
|
win_term_t* term = malloc(sizeof(win_term_t));
|
||||||
|
Assert(term != NULL);
|
||||||
|
|
||||||
term->hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
term->hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
term->hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
term->hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
// Using UTF-8
|
||||||
SetConsoleOutputCP(65001);
|
SetConsoleOutputCP(65001);
|
||||||
SetConsoleCP(65001);
|
SetConsoleCP(65001);
|
||||||
|
|
||||||
// 保存初始控制台信息
|
// https://learn.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences
|
||||||
GetConsoleScreenBufferInfo(term->hStdout, &term->csbi);
|
// Set output mode to handle virtual terminal sequences
|
||||||
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (hOut == INVALID_HANDLE_VALUE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
if (hIn == INVALID_HANDLE_VALUE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// 设置输入模式(禁用行缓冲)
|
DWORD dwOriginalOutMode = 0;
|
||||||
DWORD mode = 0;
|
DWORD dwOriginalInMode = 0;
|
||||||
GetConsoleMode(term->hStdin, &mode);
|
if (!GetConsoleMode(hOut, &dwOriginalOutMode)) {
|
||||||
SetConsoleMode(term->hStdin, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!GetConsoleMode(hIn, &dwOriginalInMode)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// 关闭光标(游标)
|
DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
CONSOLE_CURSOR_INFO cursorInfo;
|
DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
GetConsoleCursorInfo(term->hStdout, &cursorInfo);
|
|
||||||
cursorInfo.bVisible = FALSE; // 设置为 FALSE 隐藏光标
|
|
||||||
SetConsoleCursorInfo(term->hStdout, &cursorInfo);
|
|
||||||
|
|
||||||
system("cls");
|
DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
|
||||||
|
if (!SetConsoleMode(hOut, dwOutMode)) {
|
||||||
|
// we failed to set both modes, try to step down mode gracefully.
|
||||||
|
dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
|
||||||
|
if (!SetConsoleMode(hOut, dwOutMode)) {
|
||||||
|
// Failed to set any VT mode, can't do anything here.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwInMode = dwOriginalInMode | dwRequestedInModes;
|
||||||
|
if (!SetConsoleMode(hIn, dwInMode)) {
|
||||||
|
// Failed to set VT input mode, can't do anything here.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable cursor
|
||||||
|
printf(CSI"?25l");
|
||||||
|
term->height = terminal_get_height(term);
|
||||||
|
term->width = terminal_get_width(term);
|
||||||
|
terminal_clean(term);
|
||||||
|
terminal_flush(term);
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void terminal_flush(win_term_t* term) {
|
||||||
|
// ESC[nJ
|
||||||
|
// printf(CSI"2J");
|
||||||
|
// for (int i = 0; i < term->height; i++) {
|
||||||
|
// // ESC[x;yH 设置光标位置 x 行 y 列
|
||||||
|
// // WriteConsole(term->hStdout, term->buffer + ((term->width + 1) * i), term->width, NULL, NULL);
|
||||||
|
// WriteFile(term->hStdout, term->buffer + ((term->width + 1) * i), term->width - 1, NULL, NULL);
|
||||||
|
// }
|
||||||
|
printf(CSI"0;0H%s", term->buffer);
|
||||||
|
// fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int terminal_clean(win_term_t* term) {
|
||||||
|
// printf(CSI"2J");
|
||||||
|
memset(term->buffer, ' ', sizeof(term->buffer));
|
||||||
|
for (int i = 1; i <= term->height; i++) {
|
||||||
|
term->buffer[i * term->width] = '\n';
|
||||||
|
}
|
||||||
|
term->buffer[term->width * term->height] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印文本(带位置和颜色)
|
||||||
|
void terminal_print(win_term_t* term, int x, int y, const char* text) {
|
||||||
|
// terminal_set_cursor(term, x, y);
|
||||||
|
// printf(CSI"%d;%dH%s", y, x, text);
|
||||||
|
while (*text) {
|
||||||
|
*((term->buffer) + ((term->width + 1) * y) + x) = *text;
|
||||||
|
x++;
|
||||||
|
text++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 清理终端
|
// 清理终端
|
||||||
void terminal_cleanup(win_term_t* term) {
|
void terminal_cleanup(win_term_t* term) {
|
||||||
// 恢复初始属性
|
// 恢复初始属性
|
||||||
@@ -45,19 +119,6 @@ void terminal_cleanup(win_term_t* term) {
|
|||||||
free(term);
|
free(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置光标位置
|
|
||||||
static inline void terminal_set_cursor(win_term_t* term, int x, int y) {
|
|
||||||
COORD coord = { x, y };
|
|
||||||
SetConsoleCursorPosition(term->hStdout, coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印文本(带位置和颜色)
|
|
||||||
void terminal_print(win_term_t* term, int x, int y, const char* text) {
|
|
||||||
terminal_set_cursor(term, x, y);
|
|
||||||
printf("%s", text);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取按键事件
|
// 获取按键事件
|
||||||
int terminal_get_key(win_term_t* term) {
|
int terminal_get_key(win_term_t* term) {
|
||||||
INPUT_RECORD ir;
|
INPUT_RECORD ir;
|
||||||
@@ -86,60 +147,6 @@ int terminal_get_height(win_term_t* term) {
|
|||||||
return term->csbi.srWindow.Bottom - term->csbi.srWindow.Top + 1;
|
return term->csbi.srWindow.Bottom - term->csbi.srWindow.Top + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int terminal_clean(win_term_t* term) {
|
|
||||||
// Write the sequence for clearing the display.
|
|
||||||
DWORD written = 0;
|
|
||||||
PCWSTR sequence = L"\x1b[2J";
|
|
||||||
if (!WriteConsoleW(term->hStdout, sequence, (DWORD)wcslen(sequence), &written, NULL))
|
|
||||||
{
|
|
||||||
// If we fail, try to restore the mode on the way out.
|
|
||||||
SetConsoleMode(term->hStdout, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
|
||||||
return GetLastError();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int main() {
|
|
||||||
// win_term_t* term = terminal_init();
|
|
||||||
|
|
||||||
// // 清屏
|
|
||||||
// system("cls");
|
|
||||||
|
|
||||||
// // 打印彩色文本
|
|
||||||
// terminal_print(term, 10, 5,
|
|
||||||
// "按方向键移动, ESC退出");
|
|
||||||
|
|
||||||
// int x = 10, y = 10;
|
|
||||||
// char* player = "@";
|
|
||||||
|
|
||||||
// while (1) {
|
|
||||||
// // 绘制玩家
|
|
||||||
// terminal_print(term, x, y,
|
|
||||||
// player);
|
|
||||||
|
|
||||||
// // 获取按键
|
|
||||||
// int key = terminal_get_key(term);
|
|
||||||
|
|
||||||
// // 擦除旧位置
|
|
||||||
// terminal_print(term, x, y, " ");
|
|
||||||
|
|
||||||
// // 处理移动
|
|
||||||
// switch (key) {
|
|
||||||
// case VK_UP: y--; break;
|
|
||||||
// case VK_DOWN: y++; break;
|
|
||||||
// case VK_LEFT: x--; break;
|
|
||||||
// case VK_RIGHT: x++; break;
|
|
||||||
// case VK_ESCAPE:
|
|
||||||
// terminal_cleanup(term);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 边界检查
|
|
||||||
// if (x < 0) x = 0;
|
|
||||||
// if (y < 0) y = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
uint32_t win_get_timer_ms() {
|
uint32_t win_get_timer_ms() {
|
||||||
static LARGE_INTEGER freq = {0};
|
static LARGE_INTEGER freq = {0};
|
||||||
static BOOL has_freq = FALSE;
|
static BOOL has_freq = FALSE;
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ int terminal_get_key(win_term_t* term);
|
|||||||
int terminal_get_width(win_term_t* term);
|
int terminal_get_width(win_term_t* term);
|
||||||
int terminal_get_height(win_term_t* term);
|
int terminal_get_height(win_term_t* term);
|
||||||
int terminal_clean(win_term_t* term);
|
int terminal_clean(win_term_t* term);
|
||||||
|
void terminal_flush(win_term_t* term);
|
||||||
|
|
||||||
#endif // __WIN_TERM_H__
|
#endif // __WIN_TERM_H__
|
||||||
|
|||||||
9
game_core/tilemap.c
Normal file
9
game_core/tilemap.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __TILEMAP_H__
|
||||||
|
#define __TILEMAP_H__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __TILE_MAP_H__
|
||||||
@@ -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__
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#ifndef __GE_SPRITE_H__
|
|
||||||
#define __GE_SPRITE_H__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __GE_SPRITE_H__
|
|
||||||
64
game_engine/ecs/ge_entity.h
Normal file
64
game_engine/ecs/ge_entity.h
Normal 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__
|
||||||
21
game_engine/ecs/ge_physics_component.h
Normal file
21
game_engine/ecs/ge_physics_component.h
Normal 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__
|
||||||
39
game_engine/ecs/ge_physics_system.h
Normal file
39
game_engine/ecs/ge_physics_system.h
Normal 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__
|
||||||
27
game_engine/ecs/ge_render_component.h
Normal file
27
game_engine/ecs/ge_render_component.h
Normal 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__
|
||||||
69
game_engine/ecs/ge_render_system.h
Normal file
69
game_engine/ecs/ge_render_system.h
Normal 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__
|
||||||
@@ -9,4 +9,8 @@
|
|||||||
#include <utils/ge_static_alloc.h>
|
#include <utils/ge_static_alloc.h>
|
||||||
#include <utils/ge_vector2i.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__
|
#endif // __GE_COMMON_H__
|
||||||
|
|||||||
@@ -7,48 +7,48 @@ void ge_engine_init(ge_core_t *core) {
|
|||||||
for (int i = 0; i < (int)sizeof(ge_core_t); i++) {
|
for (int i = 0; i < (int)sizeof(ge_core_t); i++) {
|
||||||
*(ptr + i) = 0;
|
*(ptr + i) = 0;
|
||||||
}
|
}
|
||||||
core->configs.fps = 60;
|
core->configs.fps = 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ge_init(ge_core_t* core) {
|
static inline void ge_init(ge_core_t* core) {
|
||||||
/**
|
/**
|
||||||
* check render
|
* check render
|
||||||
*/
|
*/
|
||||||
ge_render_t* render_ctx = &core->render;
|
ge_render_t* render_ctx = &core->_render;
|
||||||
if (render_ctx->content) {
|
if (render_ctx->context) {
|
||||||
Assert(render_ctx->clear && render_ctx->draw
|
GE_SAFE_CALL(render_ctx->init_func, render_ctx, NULL);
|
||||||
&& render_ctx->getsize);
|
|
||||||
GE_SAFE_CALL(render_ctx->init, render_ctx);
|
|
||||||
render_ctx->getsize(render_ctx, &render_ctx->screen_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(core->timer.sleep_ms != NULL);
|
Assert(core->_timer.func_sleepms != NULL);
|
||||||
Assert(core->configs.fps != 0);
|
|
||||||
|
|
||||||
core->timer.fps_ctl.target_fps = 0;
|
/**
|
||||||
if (core->timer.get_ms != NULL) {
|
* init ecs
|
||||||
ge_fps_init(&core->timer.fps_ctl, core->configs.fps,
|
*/
|
||||||
core->timer.get_ms, core->timer.sleep_ms);
|
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) {
|
core->_systems.physics.ecs = &core->ecs.storage;
|
||||||
// ctx->clear(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ge_engine_run(ge_core_t *core) {
|
void ge_engine_run(ge_core_t *core) {
|
||||||
GE_SAFE_CALL(core->callbacks.init, core);
|
|
||||||
ge_init(core);
|
ge_init(core);
|
||||||
|
GE_SAFE_CALL(core->callbacks.init, core);
|
||||||
|
|
||||||
core->state = GE_ENGINE_STATE_RUNNING;
|
core->state = GE_ENGINE_STATE_RUNNING;
|
||||||
while (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);
|
ge_physics_system_run_all(&core->_systems.physics);
|
||||||
if (core->render.content) ge_render(&core->render);
|
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);
|
GE_SAFE_CALL(core->_render.func_flush, &core->_render);
|
||||||
else core->timer.sleep_ms(1000 / core->configs.fps);
|
core->_timer.func_sleepms(&core->_timer, 1000 / core->configs.fps);
|
||||||
}
|
}
|
||||||
GE_SAFE_CALL(core->callbacks.exit, core);
|
GE_SAFE_CALL(core->callbacks.exit, core);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
#define __GE_CORE_H__
|
#define __GE_CORE_H__
|
||||||
|
|
||||||
#include <ge_common.h>
|
#include <ge_common.h>
|
||||||
#include <render/ge_render.h>
|
#include <ecs/ge_entity.h>
|
||||||
#include <timer/ge_timer.h>
|
#include <ecs/ge_render_system.h>
|
||||||
|
#include <ecs/ge_physics_system.h>
|
||||||
|
|
||||||
struct ge_engine_core;
|
struct ge_engine_core;
|
||||||
typedef struct ge_engine_core ge_core_t;
|
typedef struct ge_engine_core ge_core_t;
|
||||||
@@ -24,20 +25,31 @@ struct ge_engine_core {
|
|||||||
struct {
|
struct {
|
||||||
ge_init_func_t init;
|
ge_init_func_t init;
|
||||||
ge_exit_func_t exit;
|
ge_exit_func_t exit;
|
||||||
ge_run_func_t run;
|
ge_run_func_t process;
|
||||||
} callbacks;
|
} callbacks;
|
||||||
ge_engine_state_t state;
|
ge_engine_state_t state;
|
||||||
|
ge_ecs_t ecs;
|
||||||
ge_render_t render;
|
DECLARE_GE_KFIFO(einput, ge_uptr_t, 16, ge_event_input_t);
|
||||||
ge_timer_t timer;
|
|
||||||
struct {
|
struct {
|
||||||
ge_uint_t fps;
|
ge_uint_t fps;
|
||||||
} configs;
|
} 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
|
* Basic Call
|
||||||
*/
|
*/
|
||||||
|
int ge_main(ge_core_t* core);
|
||||||
void ge_engine_init(ge_core_t *core);
|
void ge_engine_init(ge_core_t *core);
|
||||||
void ge_engine_run(ge_core_t *core);
|
void ge_engine_run(ge_core_t *core);
|
||||||
|
|
||||||
|
|||||||
57
game_engine/interface/ge_input.h
Normal file
57
game_engine/interface/ge_input.h
Normal 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__
|
||||||
236
game_engine/interface/ge_kfifo.h
Normal file
236
game_engine/interface/ge_kfifo.h
Normal 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__
|
||||||
42
game_engine/interface/ge_render.h
Normal file
42
game_engine/interface/ge_render.h
Normal 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__
|
||||||
12
game_engine/interface/ge_resource.h
Normal file
12
game_engine/interface/ge_resource.h
Normal 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__
|
||||||
23
game_engine/interface/ge_timer.h
Normal file
23
game_engine/interface/ge_timer.h
Normal 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__
|
||||||
66
game_engine/interface/timer/ge_fps.c
Normal file
66
game_engine/interface/timer/ge_fps.c
Normal 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
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,11 @@
|
|||||||
struct ge_fps_controller;
|
struct ge_fps_controller;
|
||||||
typedef struct ge_fps_controller ge_fps_controller_t;
|
typedef struct ge_fps_controller ge_fps_controller_t;
|
||||||
|
|
||||||
typedef ge_u32_t (*ge_fps_get_ms_func_t)(void);
|
typedef ge_u32_t (*ge_fps_get_us_func_t)(void);
|
||||||
typedef void (*ge_fps_sleep_ms_func_t)(ge_u32_t ms);
|
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,
|
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_begin_frame(ge_fps_controller_t* fps_ctrl);
|
||||||
void ge_fps_end_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 fps; // 实际帧率
|
||||||
ge_u32_t last_fps_time; // 上次计算FPS的时间
|
ge_u32_t last_fps_time; // 上次计算FPS的时间
|
||||||
|
|
||||||
ge_fps_get_ms_func_t call_get_ms;
|
ge_fps_get_us_func_t call_get_us;
|
||||||
ge_fps_sleep_ms_func_t call_sleep_ms;
|
ge_fps_sleep_us_func_t call_sleep_us;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __GE_FPS_H__
|
#endif // __GE_FPS_H__
|
||||||
@@ -7,9 +7,16 @@
|
|||||||
typedef void (*ge_sleep_ms_func_t)(ge_u32_t);
|
typedef void (*ge_sleep_ms_func_t)(ge_u32_t);
|
||||||
typedef ge_u32_t (*ge_get_ms_func_t)(void);
|
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 {
|
typedef struct {
|
||||||
ge_sleep_ms_func_t sleep_ms;
|
ge_sleep_ms_func_t sleep_ms;
|
||||||
ge_get_ms_func_t get_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_fps_controller_t fps_ctl;
|
||||||
} ge_timer_t;
|
} ge_timer_t;
|
||||||
|
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
* 提供跨平台的终端文本颜色和样式控制支持
|
* 提供跨平台的终端文本颜色和样式控制支持
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PYTHONIC_TERMINAL_COLOR_H__
|
#ifndef __PYNIC_TERMINAL_COLOR_H__
|
||||||
#define __PYTHONIC_TERMINAL_COLOR_H__
|
#define __PYNIC_TERMINAL_COLOR_H__
|
||||||
|
|
||||||
/// @name 前景色控制码
|
/// @name 前景色控制码
|
||||||
/// @{
|
/// @{
|
||||||
@@ -56,4 +56,4 @@
|
|||||||
#define ANSI_FMT(str, fmt) str ///< 禁用样式输出
|
#define ANSI_FMT(str, fmt) str ///< 禁用样式输出
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // __PYTHONIC_TERMINAL_COLOR_H__
|
#endif // __PYNIC_TERMINAL_COLOR_H__
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
* @brief 模仿python标准库logger的日志系统核心模块(支持多级日志、断言和异常处理)
|
* @brief 模仿python标准库logger的日志系统核心模块(支持多级日志、断言和异常处理)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PYTHONIC_LOG_H__
|
#ifndef __PYNIC_LOG_H__
|
||||||
#define __PYTHONIC_LOG_H__
|
#define __PYNIC_LOG_H__
|
||||||
|
|
||||||
#ifndef __NO_STDIO__
|
#ifndef __PYNIC_NO_STDIO__
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __NO_PYNIC_COLOR__
|
#ifndef __PYNIC_NO_COLOR__
|
||||||
#include "pynic_color.h"
|
#include "pynic_color.h"
|
||||||
#else
|
#else
|
||||||
#ifndef __LOG_NO_COLOR__
|
#ifndef __PYNIC_LOG_NO_COLOR__
|
||||||
#define __LOG_NO_COLOR__
|
#define __PYNIC_LOG_NO_COLOR__
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _PYNIC_STR(str) #str
|
#define _PYNIC_STR(str) #str
|
||||||
#define PYLIKE_STR(str) _PYNIC_STR(str)
|
#define PYNIC_STR(str) _PYNIC_STR(str)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 日志级别枚举
|
* @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 AssertFmt(cond, format, ...) _Assert(cond, "Assertion Failure: " format, ## __VA_ARGS__) ///< 带格式的断言检查
|
||||||
#define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) ///< 立即触发致命错误
|
#define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) ///< 立即触发致命错误
|
||||||
#ifndef Assert
|
#ifndef Assert
|
||||||
#define Assert(cond) AssertFmt(cond, "cond is `" PYLIKE_STR(cond) "`") ///< 基础断言检查
|
#define Assert(cond) AssertFmt(cond, "cond is `" PYNIC_STR(cond) "`") ///< 基础断言检查
|
||||||
#endif
|
#endif
|
||||||
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
|
#define Panic(...) PanicFmt(__VA_ARGS__) ///< 触发致命错误(带自定义消息)
|
||||||
#define TODO() PanicFmt("TODO please implement me") ///< 标记未实现代码(触发致命错误)
|
#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;
|
return level_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __PYTHONIC_TERMINAL_COLOR_H__
|
#ifdef __PYNIC_TERMINAL_COLOR_H__
|
||||||
static inline const char* pynic_level_color(log_level_t level) {
|
static inline const char* pynic_level_color(log_level_t level) {
|
||||||
const char* color_code = ANSI_NONE;
|
const char* color_code = ANSI_NONE;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@@ -237,11 +237,11 @@ static inline const char* pynic_level_color(log_level_t level) {
|
|||||||
|
|
||||||
#ifdef __PYNIC_LOG_IMPLIMENT__
|
#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);
|
const char* level_str = pynic_level_str(level);
|
||||||
|
|
||||||
/// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出
|
/// @note: 定义 __PYNIC_LOG_NO_COLOR__ 会取消颜色输出
|
||||||
#ifndef __LOG_NO_COLOR__
|
#ifndef __PYNIC_LOG_NO_COLOR__
|
||||||
_pynic_logout_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n",
|
_pynic_logout_printf(ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n",
|
||||||
pynic_level_color(level), level_str, module, file, line, message);
|
pynic_level_color(level), level_str, module, file, line, message);
|
||||||
#else
|
#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 = {
|
static logger_t __pynic_root_logger = {
|
||||||
.name = "root",
|
.name = "root",
|
||||||
.level = LOG_LEVEL_ALL,
|
.level = LOG_LEVEL_ALL,
|
||||||
.handler = default_handler,
|
.handler = __pynic_log_default_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_logger(logger_t* logger, const char* name) {
|
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) {
|
void init_logger_ex(logger_t* logger, const char* name, pynic_log_handler hander) {
|
||||||
logger->name = name;
|
logger->name = name;
|
||||||
logger->handler = hander ? hander : default_handler;
|
logger->handler = hander ? hander : __pynic_log_default_handler;
|
||||||
log_set_level(logger, LOG_LEVEL_ALL);
|
log_set_level(logger, LOG_LEVEL_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,4 +285,4 @@ void log_set_handler(logger_t* logger, pynic_log_handler handler) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // __PYTHONIC_LOG_H__
|
#endif // __PYNIC_LOG_H__
|
||||||
|
|||||||
@@ -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__
|
|
||||||
@@ -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__
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,13 +54,13 @@ struct __ge_kfifo {
|
|||||||
*/
|
*/
|
||||||
#define DECLARE_GE_KFIFO(fifo, type, size, tname) struct tname __STRUCT_GE_KFIFO(type, size) fifo
|
#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); \
|
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
|
||||||
__kfifo->in = 0; \
|
__kfifo->in = 0; \
|
||||||
__kfifo->out = 0; \
|
__kfifo->out = 0; \
|
||||||
__kfifo->mask = GE_ARRAY_SIZE((fifo).buf) - 1; \
|
__kfifo->mask = GE_ARRAY_SIZE((fifo)->buf) - 1; \
|
||||||
__kfifo->esize = sizeof(*(fifo).buf); \
|
__kfifo->esize = sizeof(*((fifo)->buf)); \
|
||||||
__kfifo->data = (fifo).buf; \
|
__kfifo->data = (fifo)->buf; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,7 +173,7 @@ struct __ge_kfifo {
|
|||||||
#define ge_kfifo_peek(fifo, val) do { \
|
#define ge_kfifo_peek(fifo, val) do { \
|
||||||
unsigned int __ret; \
|
unsigned int __ret; \
|
||||||
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
|
struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \
|
||||||
__ret = !kfifo_is_empty(fifo); \
|
__ret = !ge_kfifo_is_empty(fifo); \
|
||||||
if (__ret) { \
|
if (__ret) { \
|
||||||
*val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \
|
*val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \
|
||||||
/*smp_wmb();*/ \
|
/*smp_wmb();*/ \
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#undef GE_ABS
|
#undef GE_ABS
|
||||||
#define GE_ABS(x) ((x) > 0 ? (x) : -(x))
|
#define GE_ABS(x) ((x) > 0 ? (x) : -(x))
|
||||||
#endif
|
#endif
|
||||||
typedef int ge_unit_t; /**< 坐标值类型定义 */
|
typedef int32_t ge_unit_t; /**< 坐标值类型定义 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct ge_vector2_t
|
* @struct ge_vector2_t
|
||||||
|
|||||||
Reference in New Issue
Block a user