feat(engine): 重构游戏引擎核心逻辑
- 重新设计了引擎的初始化和运行流程 - 引入了实体组件系统(ECS)和物理系统 - 优化了渲染系统和输入系统 - 移除了不必要的资源管理系统 - 调整了日志系统的实现
This commit is contained in:
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
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
||||
31
game_engine/interface/timer/ge_fps.h
Normal file
31
game_engine/interface/timer/ge_fps.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __GE_FPS_H__
|
||||
#define __GE_FPS_H__
|
||||
|
||||
#include <ge_common.h>
|
||||
struct ge_fps_controller;
|
||||
typedef struct ge_fps_controller ge_fps_controller_t;
|
||||
|
||||
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_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);
|
||||
|
||||
// FPS控制器结构体
|
||||
struct ge_fps_controller {
|
||||
ge_u32_t target_fps; // 目标帧率
|
||||
ge_u32_t frame_duration; // 目标每帧时长(毫秒)
|
||||
ge_u32_t last_frame_time; // 上一帧开始时间
|
||||
ge_u32_t frame_time; // 当前帧耗时
|
||||
ge_u32_t sleep_time; // 需要休眠的时间
|
||||
ge_u32_t frame_count; // 帧计数器
|
||||
ge_u32_t fps; // 实际帧率
|
||||
ge_u32_t last_fps_time; // 上次计算FPS的时间
|
||||
|
||||
ge_fps_get_us_func_t call_get_us;
|
||||
ge_fps_sleep_us_func_t call_sleep_us;
|
||||
};
|
||||
|
||||
#endif // __GE_FPS_H__
|
||||
0
game_engine/interface/timer/ge_timer.c
Normal file
0
game_engine/interface/timer/ge_timer.c
Normal file
23
game_engine/interface/timer/ge_timer.h
Normal file
23
game_engine/interface/timer/ge_timer.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __GE_TIMER_H__
|
||||
#define __GE_TIMER_H__
|
||||
|
||||
#include <ge_config.h>
|
||||
#include "ge_fps.h"
|
||||
|
||||
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;
|
||||
|
||||
#endif // __GE_TIMER_H__
|
||||
Reference in New Issue
Block a user