feat(game): 添加基础游戏引擎和渲染模块

- 新增游戏引擎核心模块,包括初始化和运行逻辑
- 实现基本的渲染功能,支持控制台输出
- 添加物理引擎基础,包括碰撞检测
- 集成日志系统,用于调试和信息输出
- 创建窗口和输入管理模块
This commit is contained in:
ZZY
2025-06-24 02:16:01 +08:00
commit 5ce660e3a6
30 changed files with 2056 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,129 @@
#ifndef __GE_MAROC_H__
#define __GE_MAROC_H__
#define GE_ABS(x) ((x) > 0 : (x) : -(x))
#define GE_MAX(a, b) ((a) > (b) ? (a) : (b))
#define GE_MIN(a, b) ((a) < (b) ? (a) : (b))
#define _GE_STR(x) #x
#define GE_STRINGIFY(x) _GE_STR(x)
#define GE_SAFE_CALL(func, ...) \
do { \
if (func) func(__VA_ARGS__); \
} while(0)
#endif // __GE_MAROC_H__
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
/*
#ifndef __MACRO_H__
#define __MACRO_H__
#include <string.h>
// macro stringizing
#define str_temp(x) #x
#define str(x) str_temp(x)
// strlen() for string constant
#define STRLEN(CONST_STR) (sizeof(CONST_STR) - 1)
// calculate the length of an array
#define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
// macro concatenation
#define concat_temp(x, y) x ## y
#define concat(x, y) concat_temp(x, y)
#define concat3(x, y, z) concat(concat(x, y), z)
#define concat4(x, y, z, w) concat3(concat(x, y), z, w)
#define concat5(x, y, z, v, w) concat4(concat(x, y), z, v, w)
// macro testing
// See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro
#define CHOOSE2nd(a, b, ...) b
#define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b)
#define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b)
// define placeholders for some property
#define __P_DEF_0 X,
#define __P_DEF_1 X,
#define __P_ONE_1 X,
#define __P_ZERO_0 X,
// define some selection functions based on the properties of BOOLEAN macro
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)
#define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X)
#define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y)
#define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_,macro, X, Y)
// test if a boolean macro is defined
#define ISDEF(macro) MUXDEF(macro, 1, 0)
// test if a boolean macro is undefined
#define ISNDEF(macro) MUXNDEF(macro, 1, 0)
// test if a boolean macro is defined to 1
#define ISONE(macro) MUXONE(macro, 1, 0)
// test if a boolean macro is defined to 0
#define ISZERO(macro) MUXZERO(macro, 1, 0)
// test if a macro of ANY type is defined
// NOTE1: it ONLY works inside a function, since it calls `strcmp()`
// NOTE2: macros defined to themselves (#define A A) will get wrong results
#define isdef(macro) (strcmp("" #macro, "" str(macro)) != 0)
// simplification for conditional compilation
#define __IGNORE(...)
#define __KEEP(...) __VA_ARGS__
// keep the code if a boolean macro is defined
#define IFDEF(macro, ...) MUXDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is undefined
#define IFNDEF(macro, ...) MUXNDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is defined to 1
#define IFONE(macro, ...) MUXONE(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is defined to 0
#define IFZERO(macro, ...) MUXZERO(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// functional-programming-like macro (X-macro)
// apply the function `f` to each element in the container `c`
// NOTE1: `c` should be defined as a list like:
// f(a0) f(a1) f(a2) ...
// NOTE2: each element in the container can be a tuple
#define MAP(c, f) c(f)
#define BITMASK(bits) ((1ull << (bits)) - 1)
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
#define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1))
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1))
#define PG_ALIGN __attribute((aligned(4096)))
#if !defined(likely)
#define likely(cond) __builtin_expect(cond, 1)
#define unlikely(cond) __builtin_expect(cond, 0)
#endif
// for AM IOE
#define io_read(reg) \
({ reg##_T __io_param; \
ioe_read(reg, &__io_param); \
__io_param; })
#define io_write(reg, ...) \
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
ioe_write(reg, &__io_param); })
#endif
*/

View File

@@ -0,0 +1,6 @@
#ifndef __GE_STATIC_ALLOC_H__
#define __GE_STATIC_ALLOC_H__
#include <ge_config.h>
#endif // __GE_STATIC_ALLOC_H__

View File

@@ -0,0 +1,254 @@
#ifndef __GE_VECTOR2_H__
#define __GE_VECTOR2_H__
/**
* @file ge_vector2i.h
* @brief 2D整数向量库 (仿Godot Vector2i设计) 不依赖任何库的单文件
* @defgroup Vector2 2D向量操作
*/
// #define GE_VEC2I_USE_SHORT_NAMES
#ifdef GE_ABS
#undef GE_ABS
#define GE_ABS(x) ((x) > 0 ? (x) : -(x))
#endif
typedef int ge_unit_t; /**< 坐标值类型定义 */
/**
* @struct ge_vector2_t
* @brief 2D整数向量结构体
* @ingroup Vector2
*/
typedef struct {
ge_unit_t x; /**< X轴坐标 */
ge_unit_t y; /**< Y轴坐标 */
} ge_vector2i_t;
// ========================= 构造函数 =========================
/**
* @def GE_VEC2I
* @brief 创建向量 (x, y)
* @param x_val X坐标值
* @param y_val Y坐标值
* @return 构造的向量
* @ingroup Vector2
*/
#define GE_VEC2I(x_val, y_val) ((ge_vector2i_t){(x_val), (y_val)})
// ========================= 常量定义 =========================
/** @def GE_VEC2I_ZERO 零向量 (0, 0) */
#define GE_VEC2I_ZERO GE_VEC2I(0, 0)
/** @def GE_VEC2I_ONE 单位向量 (1, 1) */
#define GE_VEC2I_ONE GE_VEC2I(1, 1)
/** @def GE_VEC2I_LEFT 左方向向量 (-1, 0) */
#define GE_VEC2I_LEFT GE_VEC2I(-1, 0)
/** @def GE_VEC2I_RIGHT 右方向向量 (1, 0) */
#define GE_VEC2I_RIGHT GE_VEC2I(1, 0)
/** @def GE_VEC2I_UP 上方向向量 (0, -1) */
#define GE_VEC2I_UP GE_VEC2I(0, -1)
/** @def GE_VEC2I_DOWN 下方向向量 (0, 1) */
#define GE_VEC2I_DOWN GE_VEC2I(0, 1)
// ========================= 运算宏定义 =========================
/**
* @def GE_VEC2I_ADD
* @brief 向量加法
* @param a 第一个向量
* @param b 第二个向量
* @return a + b
* @ingroup Vector2
*/
#define GE_VEC2I_ADD(a, b) GE_VEC2I((a).x + (b).x, (a).y + (b).y)
/**
* @def GE_VEC2I_SUB
* @brief 向量减法
* @param a 被减向量
* @param b 减数向量
* @return a - b
* @ingroup Vector2
*/
#define GE_VEC2I_SUB(a, b) GE_VEC2I((a).x - (b).x, (a).y - (b).y)
/**
* @def GE_VEC2I_MUL
* @brief 向量分量乘法
* @param a 第一个向量
* @param b 第二个向量
* @return a * b (分量相乘)
* @ingroup Vector2
*/
#define GE_VEC2I_MUL(a, b) GE_VEC2I((a).x * (b).x, (a).y * (b).y)
/**
* @def GE_VEC2I_DIV
* @brief 向量分量除法
* @param a 被除向量
* @param b 除数向量
* @return a / b (分量相除)如果分母为0会出现严重错误
* @ingroup Vector2
*/
#define GE_VEC2I_DIV(a, b) GE_VEC2I( \
(a).x / (b).x, \
(a).y / (b).y \
)
/**
* @def GE_VEC2I_DIV_SAFE
* @brief 向量分量除法
* @param a 被除向量
* @param b 除数向量
* @return a / b (分量相除),除零保护(分母为0返回0)
* @ingroup Vector2
*/
#define GE_VEC2I_DIV_SAFE(a, b) GE_VEC2I( \
(b).x ? (a).x / (b).x : 0, \
(b).y ? (a).y / (b).y : 0 \
)
/**
* @def GE_VEC2I_MUL_SCALAR
* @brief 向量标量乘法
* @param v 目标向量
* @param s 标量值
* @return v * s
* @ingroup Vector2
*/
#define GE_VEC2I_MUL_SCALAR(v, s) GE_VEC2I((v).x * (s), (v).y * (s))
/**
* @def GE_VEC2I_DOT
* @brief 向量点积
* @param a 第一个向量
* @param b 第二个向量
* @return a · b
* @ingroup Vector2
*/
#define GE_VEC2I_DOT(a, b) ((a).x * (b).x + (a).y * (b).y)
/**
* @def GE_VEC2I_LENGTH_SQR
* @brief 向量长度平方
* @param v 目标向量
* @return |v|²
* @ingroup Vector2
*/
#define GE_VEC2I_LENGTH_SQR(v) (GE_VEC2I_DOT(v, v))
/**
* @def GE_VEC2I_DISTANCE_SQR
* @brief 两点间距离平方
* @param a 起点向量
* @param b 终点向量
* @return |a - b|²
* @ingroup Vector2
*/
#define GE_VEC2I_DISTANCE_SQR(a, b) GE_VEC2I_LENGTH_SQR(GE_VEC2I_SUB(a, b))
/**
* @def GE_VEC2I_MIN
* @brief 分量最小值
* @param a 第一个向量
* @param b 第二个向量
* @return (min(a.x, b.x), min(a.y, b.y))
* @ingroup Vector2
*/
#define GE_VEC2I_MIN(a, b) GE_VEC2I( \
((a).x < (b).x) ? (a).x : (b).x, \
((a).y < (b).y) ? (a).y : (b).y \
)
/**
* @def GE_VEC2I_MAX
* @brief 分量最大值
* @param a 第一个向量
* @param b 第二个向量
* @return (max(a.x, b.x), max(a.y, b.y))
* @ingroup Vector2
*/
#define GE_VEC2I_MAX(a, b) GE_VEC2I( \
((a).x > (b).x) ? (a).x : (b).x, \
((a).y > (b).y) ? (a).y : (b).y \
)
/**
* @def GE_VEC2I_CLAMP
* @brief 分量钳制(钳制操作的意思是:如果某个分量小于最小值,
* 则将其设置为最小值;如果大于最大值,则设置为最大值;
* 如果在最小值和最大值之间,则保持不变。)
* @param v 目标向量
* @param min_vec 最小值向量
* @param max_vec 最大值向量
* @return 钳制后的向量
* @ingroup Vector2
*/
#define GE_VEC2I_CLAMP(v, min_vec, max_vec) \
GE_VEC2I_MIN(GE_VEC2I_MAX(v, min_vec), max_vec)
// ========================= 操作符 =========================
/**
* @def GE_VEC2I_EQUAL
* @brief 判断两个向量是否相等(分量完全相等)
* @param a 第一个向量
* @param b 第二个向量
* @return 1 表示相等0 表示不相等
* @ingroup Vector2
*/
#define GE_VEC2I_EQUAL(a, b) (((a).x == (b).x) && ((a).y == (b).y))
/**
* @def GE_VEC2I_NOT_EQUAL
* @brief 判断两个向量是否不相等
* @param a 第一个向量
* @param b 第二个向量
* @return 1 表示不相等0 表示相等
* @ingroup Vector2
*/
#define GE_VEC2I_NOT_EQUAL(a, b) (((a).x != (b).x) || ((a).y != (b).y))
/**
* @def GE_VEC2I_APPROX_EQUAL
* @brief 判断两个向量是否近似相等(在容忍度范围内)
* @param a 第一个向量
* @param b 第二个向量
* @param tolerance 容忍度值
* @return 1 表示近似相等0 表示不近似相等
* @note 对于整数向量,通常使用精确比较,但此宏提供了容忍度机制
* @ingroup Vector2
*/
#define GE_VEC2I_APPROX_EQUAL(a, b, tolerance) \
((GE_ABS((a).x - (b).x) <= tolerance) && \
(GE_ABS((a).y - (b).y) <= tolerance))
// ========================= 可选前缀模式 =========================
#ifdef GE_VEC2I_USE_SHORT_NAMES
#define vec2i(x, y) GE_VEC2I(x, y)
#define vec2i_zero GE_VEC2I_ZERO
#define vec2i_one GE_VEC2I_ONE
#define vec2i_add(a, b) GE_VEC2I_ADD(a, b)
#define vec2i_sub(a, b) GE_VEC2I_SUB(a, b)
#define vec2i_mul(a, b) GE_VEC2I_MUL(a, b)
#define vec2i_mul_scalar(v, s) GE_VEC2I_MUL_SCALAR(v, s)
#define vec2i_div(a, b) GE_VEC2I_DIV(a, b)
#define vec2i_div_safe(a, b) GE_VEC2I_DIV_SAFE(a, b)
#define vec2i_dot(a, b) GE_VEC2I_DOT(a, b)
#define vec2i_length_sqr(v) GE_VEC2I_LENGTH_SQR(v)
#define vec2i_min(a, b) GE_VEC2I_MIN(a, b)
#define vec2i_max(a, b) GE_VEC2I_MAX(a, b)
#define vec2i_clamp(v, min, max) GE_VEC2I_CLAMP(v, min, max)
#define vec2i_equal(a, b) GE_VEC2I_EQUAL(a, b)
#define vec2i_not_equal(a, b) GE_VEC2I_NOT_EQUAL(a, b)
#define vec2i_approx_equal(a, b, tol) GE_VEC2I_APPROX_EQUAL(a, b, tol)
#endif
#endif // __GE_VECTOR2_H__