MiMoEngine ASM: x86-64 MASM汇编+C混合架构游戏引擎

核心热路径(数学/内存/字符串/性能分析)用MASM汇编(SSE/AVX2)
外围系统(窗口/渲染/ECS/音频/UI/脚本)用C语言
含自研编辑器、VisualScript积木编程、中文渲染(glyph_atlas)
This commit is contained in:
shuiyu1123 committed 2026-07-10 19:20:40 +08:00
commit 2d56cb3bc9
91 files changed
+9988

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
; ============================================================================
; asm_macros.inc - MASM 通用宏定义
; Windows x64 调用约定: RCX, RDX, R8, R9 传参, XMM0-XMM3 浮点
; ============================================================================
; --- 函数帧管理宏 ---
; PROLOGUE: 保存非易失寄存器, 分配栈空间
; 使用: PROLOGUE 栈空间大小
PROLOGUE MACRO stack_size:REQ
push rbx
push rbp
push rdi
push rsi
push r12
push r13
push r14
push r15
sub rsp, stack_size
; 保存浮点参数寄存器 (如果有)
movsd qword ptr [rsp + stack_size - 8], xmm6
movsd qword ptr [rsp + stack_size - 16], xmm7
ENDM
; EPILOGUE: 恢复非易失寄存器, 释放栈空间
EPILOGUE MACRO stack_size:REQ
movsd xmm6, qword ptr [rsp + stack_size - 8]
movsd xmm7, qword ptr [rsp + stack_size - 16]
add rsp, stack_size
pop r15
pop r14
pop r13
pop r12
pop rsi
pop rdi
pop rbp
pop rbx
ret
ENDM
; --- SSE/AVX 常量 ---
.DATA
ALIGN 16
sse_mask_abs DD 07FFFFFFFH, 07FFFFFFFH, 07FFFFFFFH, 07FFFFFFFH ; 绝对值掩码
sse_negate DD 80000000H, 80000000H, 80000000H, 80000000H ; 符号位掩码
sse_one DD 3F800000H, 3F800000H, 3F800000H, 3F800000H ; 1.0f
sse_half DD 3F000000H, 3F000000H, 3F000000H, 3F000000H ; 0.5f
eps_float DD 33D6BF94H ; 1e-6f
.CODE
; --- 工具宏 ---
; LOAD_VEC3: 从内存加载 Vec3 到 XMM 寄存器 (填充 w=1.0)
; ptr: 内存地址, reg: XMM 寄存器
LOAD_VEC3 MACRO ptr, reg
movss xmm0, dword ptr [ptr] ; x
movss xmm1, dword ptr [ptr + 4] ; y
movss xmm2, dword ptr [ptr + 8] ; z
unpcklps xmm0, xmm1 ; {x, y, ?, ?}
movss xmm3, dword ptr [sse_one] ; w = 1.0
unpcklps xmm2, xmm3 ; {z, 1.0, ?, ?}
movlhps xmm0, xmm2 ; {x, y, z, 1.0}
movaps reg, xmm0
ENDM
; STORE_VEC3: 将 XMM 寄存器的前3个float存储到内存
STORE_VEC3 MACRO reg, ptr
movss dword ptr [ptr], xmm0 ; x
shufps xmm0, xmm0, 01010101b
movss dword ptr [ptr + 4], xmm0 ; y
shufps xmm0, xmm0, 10101010b
movss dword ptr [ptr + 8], xmm0 ; z
ENDM
; --- 外部函数声明 ---
externdef vec3_add:PROC
externdef vec3_sub:PROC
externdef vec3_scale:PROC
externdef vec3_dot:PROC
externdef vec3_cross:PROC
externdef vec3_length:PROC
externdef vec3_normalize:PROC
externdef vec3_lerp:PROC
externdef vec3_distance:PROC
externdef vec4_add:PROC
externdef vec4_sub:PROC
externdef vec4_mul:PROC
externdef vec4_dot:PROC
externdef vec4_length:PROC
externdef vec4_normalize:PROC
externdef mat4_identity:PROC
externdef mat4_multiply:PROC
externdef mat4_transpose:PROC
externdef mat4_invert:PROC
externdef mat4_translate:PROC
externdef mat4_scale_f:PROC
externdef mat4_rotate_x:PROC
externdef mat4_rotate_y:PROC
externdef mat4_rotate_z:PROC
externdef mat4_perspective:PROC
externdef mat4_orthographic:PROC
externdef mat4_lookat:PROC
externdef quat_multiply:PROC
externdef quat_conjugate:PROC
externdef quat_normalize:PROC
externdef quat_rotate_vec3:PROC
externdef quat_slerp:PROC
externdef quat_to_matrix:PROC
externdef quat_from_axis_angle:PROC
externdef quat_from_euler:PROC
externdef mem_aligned_alloc:PROC
externdef mem_aligned_free:PROC
externdef mem_aligned_realloc:PROC
externdef fast_memcpy:PROC
externdef fast_memset:PROC
externdef fast_strlen:PROC
externdef fast_strcmp:PROC
externdef prof_rdtsc:PROC
externdef prof_cycles_to_ms:PROC
externdef prof_get_freq:PROC
+1150
View File
File diff suppressed because it is too large. Load diff
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <Windows.h>
#ifndef MATH_ASM_AVAILABLE
typedef struct { float x, y, z; } Vec3;
typedef struct { float x, y, z, w; } Vec4;
typedef struct { float m[4][4]; } Mat4;
typedef struct { float x, y, z, w; } Quat;
static inline void vec3_add(const Vec3* a, const Vec3* b, Vec3* o) { o->x=a->x+b->x; o->y=a->y+b->y; o->z=a->z+b->z; }
static inline void vec3_sub(const Vec3* a, const Vec3* b, Vec3* o) { o->x=a->x-b->x; o->y=a->y-b->y; o->z=a->z-b->z; }
static inline void vec3_scale(const Vec3* a, float s, Vec3* o) { o->x=a->x*s; o->y=a->y*s; o->z=a->z*s; }
static inline float vec3_dot(const Vec3* a, const Vec3* b) { return a->x*b->x+a->y*b->y+a->z*b->z; }
static inline void vec3_cross(const Vec3* a, const Vec3* b, Vec3* o) { o->x=a->y*b->z-a->z*b->y; o->y=a->z*b->x-a->x*b->z; o->z=a->x*b->y-a->y*b->x; }
static inline float vec3_length(const Vec3* a) { return sqrtf(a->x*a->x+a->y*a->y+a->z*a->z); }
static inline void vec3_normalize(const Vec3* a, Vec3* o) { float l=vec3_length(a); if(l<1e-6f){o->x=o->y=o->z=0;return;} float i=1.0f/l; o->x=a->x*i; o->y=a->y*i; o->z=a->z*i; }
static inline void vec3_lerp(const Vec3* a, const Vec3* b, float t, Vec3* o) { o->x=a->x+(b->x-a->x)*t; o->y=a->y+(b->y-a->y)*t; o->z=a->z+(b->z-a->z)*t; }
static inline float vec3_distance(const Vec3* a, const Vec3* b) { Vec3 d; vec3_sub(a,b,&d); return vec3_length(&d); }
static inline void mat4_identity(Mat4* o) { memset(o,0,sizeof(Mat4)); o->m[0][0]=o->m[1][1]=o->m[2][2]=o->m[3][3]=1.0f; }
static inline void mat4_multiply(const Mat4* a, const Mat4* b, Mat4* o) { Mat4 r; int i,j,k; for(i=0;i<4;i++) for(j=0;j<4;j++) { r.m[i][j]=0; for(k=0;k<4;k++) r.m[i][j]+=a->m[i][k]*b->m[k][j]; } *o=r; }
static inline void mat4_translate(float x, float y, float z, Mat4* o) { mat4_identity(o); o->m[3][0]=x; o->m[3][1]=y; o->m[3][2]=z; }
static inline void mat4_rotate_y(float angle, Mat4* o) { float c=cosf(angle),s=sinf(angle); mat4_identity(o); o->m[0][0]=c; o->m[0][2]=-s; o->m[2][0]=s; o->m[2][2]=c; }
static inline void mat4_perspective(float fov, float aspect, float nearP, float farP, Mat4* o) { float t=tanf(fov*0.5f); memset(o,0,sizeof(Mat4)); o->m[0][0]=1.0f/(aspect*t); o->m[1][1]=1.0f/t; o->m[2][2]=farP/(nearP-farP); o->m[2][3]=-1.0f; o->m[3][2]=(nearP*farP)/(nearP-farP); }
static inline void mat4_orthographic(float w, float h, float nearP, float farP, Mat4* o) { memset(o,0,sizeof(Mat4)); o->m[0][0]=2.0f/w; o->m[1][1]=2.0f/h; o->m[2][2]=1.0f/(nearP-farP); o->m[3][2]=nearP/(nearP-farP); o->m[3][3]=1.0f; }
static inline void mat4_lookat(const Vec3* eye, const Vec3* target, const Vec3* up, Mat4* o) { Vec3 f,r,u; vec3_sub(target,eye,&f); vec3_normalize(&f,&f); vec3_cross(up,&f,&r); vec3_normalize(&r,&r); vec3_cross(&f,&r,&u); mat4_identity(o); o->m[0][0]=r.x; o->m[0][1]=u.x; o->m[0][2]=-f.x; o->m[1][0]=r.y; o->m[1][1]=u.y; o->m[1][2]=-f.y; o->m[2][0]=r.z; o->m[2][1]=u.z; o->m[2][2]=-f.z; o->m[3][0]=-vec3_dot(&r,eye); o->m[3][1]=-vec3_dot(&u,eye); o->m[3][2]=vec3_dot(&f,eye); }
static inline void mat4_transpose(const Mat4* in, Mat4* out) { for (int i=0;i<4;i++) for (int j=0;j<4;j++) out->m[i][j]=in->m[j][i]; }
static inline void quat_conjugate_raw(const Quat* q, Quat* o) { o->x=-q->x; o->y=-q->y; o->z=-q->z; o->w=q->w; }
static inline void quat_multiply(const Quat* a, const Quat* b, Quat* o) { o->x=a->w*b->x+a->x*b->w+a->y*b->z-a->z*b->y; o->y=a->w*b->y-a->x*b->z+a->y*b->w+a->z*b->x; o->z=a->w*b->z+a->x*b->y-a->y*b->x+a->z*b->w; o->w=a->w*b->w-a->x*b->x-a->y*b->y-a->z*b->z; }
static inline void quat_normalize(const Quat* q, Quat* o) { float l=sqrtf(q->x*q->x+q->y*q->y+q->z*q->z+q->w*q->w); if(l<1e-6f){*o=*q;return;} float i=1.0f/l; o->x=q->x*i; o->y=q->y*i; o->z=q->z*i; o->w=q->w*i; }
static inline void quat_rotate_vec3(const Quat* q, const Vec3* v, Vec3* o) { Quat vq={v->x,v->y,v->z,0}; Quat qinv; quat_conjugate_raw(q,&qinv); Quat tmp; quat_multiply(q,&vq,&tmp); Quat result; quat_multiply(&tmp,&qinv,&result); o->x=result.x; o->y=result.y; o->z=result.z; }
static inline void quat_to_matrix(const Quat* q, Mat4* o) { float xx=q->x*q->x,yy=q->y*q->y,zz=q->z*q->z,xy=q->x*q->y,xz=q->x*q->z,yz=q->y*q->z,wx=q->w*q->x,wy=q->w*q->y,wz=q->w*q->z; mat4_identity(o); o->m[0][0]=1-2*(yy+zz); o->m[0][1]=2*(xy+wz); o->m[0][2]=2*(xz-wy); o->m[1][0]=2*(xy-wz); o->m[1][1]=1-2*(xx+zz); o->m[1][2]=2*(yz+wx); o->m[2][0]=2*(xz+wy); o->m[2][1]=2*(yz-wx); o->m[2][2]=1-2*(xx+yy); }
static inline void* mem_aligned_alloc(uint64_t size, uint64_t alignment) { void* p; p = _aligned_malloc(size, alignment); return p; }
static inline void mem_aligned_free(void* ptr) { _aligned_free(ptr); }
static inline void fast_memcpy(void* dst, const void* src, uint64_t count) { memcpy(dst, src, (size_t)count); }
static inline void fast_memset(void* dst, int v, uint64_t count) { memset(dst, v, (size_t)count); }
static inline uint64_t fast_strlen(const char* s) { return strlen(s); }
static inline uint64_t prof_rdtsc(void) { LARGE_INTEGER f,t; QueryPerformanceFrequency(&f); QueryPerformanceCounter(&t); return (uint64_t)(t.QuadPart * 1000000000ULL / f.QuadPart); }
static inline double prof_cycles_to_ms(uint64_t c) { return (double)c / 1000000.0; }
static inline uint64_t prof_get_freq(void) { LARGE_INTEGER f; QueryPerformanceFrequency(&f); return (uint64_t)f.QuadPart; }
typedef struct { uint64_t start; uint64_t end; double elapsed_ms; } ProfTimer;
static inline void prof_timer_start(ProfTimer* t) { t->start = prof_rdtsc(); }
static inline void prof_timer_stop(ProfTimer* t) { t->end = prof_rdtsc(); t->elapsed_ms = prof_cycles_to_ms(t->end - t->start); }
#endif
+177
View File
@@ -0,0 +1,177 @@
; ============================================================================
; memory.asm - 对齐内存分配器 (x86-64 MASM)
; 支持 16/32/64 字节对齐 (SIMD 需要)
; ============================================================================
include asm_macros.inc
.DATA
ALIGN 16
_alloc_header_size EQU 32 ; 分配头大小 (包含对齐偏移和原始指针)
.CODE
; ============================================================================
; 对齐内存分配
; ============================================================================
; void* mem_aligned_alloc(uint64_t size, uint64_t alignment)
; RCX = size, RDX = alignment
; 返回: RAX = 对齐指针
mem_aligned_alloc PROC
push rbx
push rdi
push rsi
sub rsp, 40 ; 保留栈空间
mov rbx, rcx ; rbx = size
mov rdi, rdx ; rdi = alignment
; 验证 alignment 是 2 的幂
mov rax, rdi
dec rax
test rdi, rax
jnz alloc_invalid_alignment
; 确保 alignment >= 16
cmp rdi, 16
jae alloc_alignment_ok
mov rdi, 16
alloc_alignment_ok:
; 需要的总大小 = size + alignment + header
mov rax, rbx
add rax, rdi ; + alignment
add rax, _alloc_header_size ; + header
mov rsi, rax ; rsi = total size
; 调用 malloc
mov rcx, rsi
call malloc
test rax, rax
jz alloc_failed
; rax = 原始指针
; 计算对齐后的地址
mov rcx, rax
add rcx, _alloc_header_size ; 跳过 header
; 对齐
mov rdx, rdi
dec rdx
not rdx
add rcx, rdx ; 加上 alignment-1
and rcx, rdx ; 对齐到 alignment
; rcx = 对齐后的指针
; 在对齐指针前存储原始指针
mov [rcx - 8], rax ; 存储原始 malloc 指针
mov [rcx - 16], rbx ; 存储请求的 size
mov [rcx - 24], rdi ; 存储 alignment
mov [rcx - 32], rsi ; 存储 total size
mov rax, rcx ; 返回对齐指针
jmp alloc_done
alloc_invalid_alignment:
xor rax, rax ; 返回 NULL
jmp alloc_done
alloc_failed:
xor rax, rax
alloc_done:
add rsp, 40
pop rsi
pop rdi
pop rbx
ret
mem_aligned_alloc ENDP
; void mem_aligned_free(void* ptr)
; RCX = ptr (对齐指针)
mem_aligned_free PROC
test rcx, rcx
jz free_done
; 获取原始 malloc 指针
mov rax, [rcx - 8]
test rax, rax
jz free_done
; 调用 free
mov rcx, rax
call free
free_done:
ret
mem_aligned_free ENDP
; void* mem_aligned_realloc(void* ptr, uint64_t size, uint64_t alignment)
; RCX = ptr, RDX = size, R8 = alignment
; 返回: RAX = 新对齐指针
mem_aligned_realloc PROC
push rbx
push rdi
push rsi
push r12
sub rsp, 40
mov rbx, rdx ; rbx = new size
mov rdi, r8 ; rdi = alignment
; 如果 ptr 为 NULL, 直接分配
test rcx, rcx
jz realloc_alloc
; 保存旧信息
mov rsi, [rcx - 8] ; 原始指针
mov r12, [rcx - 16] ; 旧 size
; 分配新内存
mov rcx, rbx
mov rdx, rdi
call mem_aligned_alloc
test rax, rax
jz realloc_failed
; 复制旧数据 (取较小值)
mov rdx, r12
cmp rdx, rbx
jbe realloc_copy_ok
mov rdx, rbx
realloc_copy_ok:
mov rdi, rax ; 保存新指针
mov rcx, rax ; dst
; rsi = 旧数据起始
mov rsi, [rcx - 8] ; 旧原始指针
; 需要获取旧的对齐偏移
; 简化: 直接复制
call fast_memcpy
; 释放旧内存
mov rcx, rsi
call mem_aligned_free
mov rax, rdi ; 返回新指针
jmp realloc_done
realloc_alloc:
mov rcx, rbx
mov rdx, rdi
call mem_aligned_alloc
jmp realloc_done
realloc_failed:
xor rax, rax
realloc_done:
add rsp, 40
pop r12
pop rsi
pop rdi
pop rbx
ret
mem_aligned_realloc ENDP
END
+172
View File
@@ -0,0 +1,172 @@
; ============================================================================
; profiling.asm - 性能分析工具 (x86-64 MASM)
; 使用 RDTSC/RDTSCP 进行高精度计时
; ============================================================================
include asm_macros.inc
.DATA
ALIGN 8
cpu_freq DQ 0 ; CPU 频率 (Hz)
cpu_freq_init DB 0 ; 是否已初始化
.CODE
; ============================================================================
; RDTSC 计时
; ============================================================================
; uint64_t prof_rdtsc(void) -> RAX
; 返回: TSC (Time Stamp Counter) 值
prof_rdtsc PROC
; 使用 RDTSCP 获取有序的 TSC
rdtscp
; EDX:EAX = TSC
shl rdx, 32
or rax, rdx
ret
prof_rdtsc ENDP
; uint64_t prof_get_freq(void) -> RAX
; 获取 CPU 频率 (通过 OS 或推断)
prof_get_freq PROC
; 检查是否已初始化
cmp byte ptr [cpu_freq_init], 0
jnz prof_freq_return
; 初始化 CPU 频率
; 方法: 使用 QueryPerformanceCounter 测量 RDTSC
push rbx
push rdi
push rsi
sub rsp, 40
; 获取 QPC 频率
lea rcx, [rsp + 32]
call QueryPerformanceFrequency
; 获取起始 QPC 和 TSC
lea rcx, [rsp + 16]
call QueryPerformanceCounter
rdtscp
shl rdx, 32
or rax, rdx
mov rbx, rax ; rbx = 起始 TSC
; 等待约 10ms
mov rcx, 10000 ; 10,000 微秒
call Sleep
; 获取结束 QPC 和 TSC
lea rcx, [rsp]
call QueryPerformanceCounter
rdtscp
shl rdx, 32
or rax, rdx
mov rdi, rax ; rdi = 结束 TSC
; 计算经过的 QPC ticks
mov rax, [rsp]
sub rax, [rsp + 16] ; qpc_diff
; 计算 QPC 频率 (ticks/sec)
mov rsi, [rsp + 32]
; TSC diff
mov rax, rdi
sub rax, rbx ; tsc_diff
; CPU freq = tsc_diff * qpc_freq / qpc_diff
; 但 qpc_diff 对应 10ms, 所以要 * 100
mov rdx, rsi
mul rdx ; tsc_diff * qpc_freq
; rdx:rax = result
div qword ptr [rsp + 16] ; / qpc_diff
; rax = freq * 100 (因为等待了 10ms)
mov rcx, 100
mul rcx
mov [cpu_freq], rax
mov byte ptr [cpu_freq_init], 1
add rsp, 40
pop rsi
pop rdi
pop rbx
prof_freq_return:
mov rax, [cpu_freq]
ret
prof_get_freq ENDP
; double prof_cycles_to_ms(uint64_t cycles) -> XMM0
; 将 TSC cycles 转换为毫秒
prof_cycles_to_ms PROC
; 先获取频率
call prof_get_freq
; rax = CPU freq (Hz)
; ms = cycles / (freq / 1000)
; 或: ms = cycles * 1000 / freq
mov rdx, 1000
mul rdx ; freq * 1000
; rdx:rax = freq * 1000
; 转换为 double
cvtsi2sd xmm0, qword ptr [rsp - 8] ; 需要栈存储
; 简化: 使用整数除法再转 double
mov rcx, rax
mov rax, [cpu_freq]
; 重新计算
mov rax, rcx
; cycles * 1000 / freq
; 已经: rax = freq * 1000, 需要 cycles * 1000 / freq
; 调整: cycles * 1000 / freq = cycles / (freq/1000)
; 简化实现
cvtsi2sd xmm0, rcx ; cycles * 1000 (转 double)
cvtsi2sd xmm1, rax ; freq (转 double)
divsd xmm0, xmm1 ; (cycles*1000) / freq = ms
ret
prof_cycles_to_ms ENDP
; ============================================================================
; 内联性能宏 (在 C 代码中使用)
; ============================================================================
; 获取当前时间戳 (直接 RDTSC, 无函数调用开销)
; 在 C 中使用: __rdtsc() 内联函数
; 高精度计时器结构
; struct ProfTimer {
; uint64_t start;
; uint64_t end;
; double elapsed_ms;
; };
; void prof_timer_start(ProfTimer* timer)
prof_timer_start PROC
rdtscp
shl rdx, 32
or rax, rdx
mov [rcx], rax ; timer->start = tsc
ret
prof_timer_start ENDP
; void prof_timer_stop(ProfTimer* timer)
prof_timer_stop PROC
rdtscp
shl rdx, 32
or rax, rdx
mov [rcx + 8], rax ; timer->end = tsc
; 计算 elapsed_ms
mov rax, [rcx + 8]
sub rax, [rcx] ; cycles
; 转换为 ms
call prof_cycles_to_ms
movsd qword ptr [rcx + 16], xmm0 ; timer->elapsed_ms
ret
prof_timer_stop ENDP
END
+325
View File
@@ -0,0 +1,325 @@
; ============================================================================
; string_ops.asm - 快速字符串/内存操作 (x86-64 MASM)
; 使用 SSE4.1 加速 memcpy/memset/strlen
; ============================================================================
include asm_macros.inc
.CODE
; ============================================================================
; 内存操作
; ============================================================================
; void fast_memcpy(void* dst, const void* src, uint64_t count)
; RCX = dst, RDX = src, R8 = count
fast_memcpy PROC
mov rax, rcx ; rax = dst
mov r9, r8 ; r9 = count
; 小于 16 字节: 逐字节复制
cmp r9, 16
jb memcpy_small
; 16-32 字节: 两次 128-bit 加载
cmp r9, 32
jb memcpy_16_32
; 32-64 字节: 四次 128-bit 加载
cmp r9, 64
jb memcpy_32_64
; >= 64 字节: SSE 批量复制
; 确保 16 字节对齐
mov r10, rcx
and r10, 0Fh ; 检查 dst 对齐
jnz memcpy_unaligned
memcpy_aligned_loop:
cmp r9, 64
jb memcpy_tail
; 每次复制 64 字节 (4x128-bit)
movaps xmm0, xmmword ptr [rdx]
movaps xmm1, xmmword ptr [rdx + 16]
movaps xmm2, xmmword ptr [rdx + 32]
movaps xmm3, xmmword ptr [rdx + 48]
movaps xmmword ptr [rcx], xmm0
movaps xmmword ptr [rcx + 16], xmm1
movaps xmmword ptr [rcx + 32], xmm2
movaps xmmword ptr [rcx + 48], xmm3
add rcx, 64
add rdx, 64
sub r9, 64
jmp memcpy_aligned_loop
memcpy_tail:
; 处理剩余 0-63 字节
test r9, 32
jz memcpy_tail_16
movaps xmm0, xmmword ptr [rdx]
movaps xmm1, xmmword ptr [rdx + 16]
movaps xmmword ptr [rcx], xmm0
movaps xmmword ptr [rcx + 16], xmm1
add rcx, 32
add rdx, 32
sub r9, 32
memcpy_tail_16:
test r9, 16
jz memcpy_tail_8
movaps xmm0, xmmword ptr [rdx]
movaps xmmword ptr [rcx], xmm0
memcpy_tail_8:
test r9, 8
jz memcpy_tail_4
mov r10, qword ptr [rdx]
mov qword ptr [rcx], r10
memcpy_tail_4:
test r9, 4
jz memcpy_tail_2
mov r10d, dword ptr [rdx]
mov dword ptr [rcx], r10d
memcpy_tail_2:
test r9, 2
jz memcpy_tail_1
mov r10w, word ptr [rdx]
mov word ptr [rcx], r10w
memcpy_tail_1:
test r9, 1
jz memcpy_done
mov r10b, byte ptr [rdx]
mov byte ptr [rcx], r10b
jmp memcpy_done
memcpy_unaligned:
; 非对齐时使用 movups
movups xmm0, xmmword ptr [rdx]
movups xmmword ptr [rcx], xmm0
add rcx, 16
add rdx, 16
sub r9, 16
jmp memcpy_aligned_loop
memcpy_32_64:
mov r10, qword ptr [rdx]
mov qword ptr [rcx], r10
mov r10, qword ptr [rdx + 8]
mov qword ptr [rcx + 8], r10
mov r10, qword ptr [rdx + 16]
mov qword ptr [rcx + 16], r10
mov r10, qword ptr [rdx + 24]
mov qword ptr [rcx + 24], r10
sub r9, 32
add rdx, 32
add rcx, 32
jmp memcpy_small
memcpy_16_32:
mov r10, qword ptr [rdx]
mov qword ptr [rcx], r10
mov r10, qword ptr [rdx + 8]
mov qword ptr [rcx + 8], r10
test r9, 8
jz memcpy_16_32_done
mov r10, qword ptr [rdx + 16]
mov qword ptr [rcx + 16], r10
memcpy_16_32_done:
jmp memcpy_done
memcpy_small:
test r9, r9
jz memcpy_done
mov r10, r9
and r10, 7 ; r10 = count % 8
shr r9, 3 ; r9 = count / 8
; 复制完整 8 字节
memcpy_small_loop:
test r9, r9
jz memcpy_small_tail
mov r11, qword ptr [rdx]
mov qword ptr [rcx], r11
add rdx, 8
add rcx, 8
dec r9
jmp memcpy_small_loop
memcpy_small_tail:
; 复制剩余字节
test r10, r10
jz memcpy_done
mov r11b, byte ptr [rdx]
mov byte ptr [rcx], r11b
inc rdx
inc rcx
dec r10
jmp memcpy_small_tail
memcpy_done:
mov rax, rax ; 返回 dst
ret
fast_memcpy ENDP
; void fast_memset(void* dst, int value, uint64_t count)
; RCX = dst, EDX = value, R8 = count
fast_memset PROC
mov rax, rcx
mov r9, r8
; 将 value 扩展到所有字节
movsx rdx, dl ; 符号扩展
mov rcx, rdx
shl rcx, 8
or rdx, rcx
mov rcx, rdx
shl rcx, 16
or rdx, rcx ; rdx = value 重复4次
mov rcx, rdx
shl rcx, 32
or rdx, rcx ; rdx = value 重复8次
; 复制到 XMM 寄存器
vmovq xmm0, rdx
vinsertf128 ymm0, ymm0, xmm0, 1 ; 256-bit 广播
; >= 32 字节: AVX 批量
cmp r9, 32
jb memset_small
memset_avx_loop:
cmp r9, 32
jb memset_tail
vmovdqu ymmword ptr [rax], ymm0
add rax, 32
sub r9, 32
jmp memset_avx_loop
memset_tail:
; 处理剩余 0-31 字节
test r9, 16
jz memset_tail_8
movups xmmword ptr [rax], xmm0
add rax, 16
sub r9, 16
memset_tail_8:
test r9, 8
jz memset_tail_4
mov qword ptr [rax], rdx
add rax, 8
memset_tail_4:
test r9, 4
jz memset_tail_2
mov dword ptr [rax], edx
add rax, 4
memset_tail_2:
test r9, 2
jz memset_tail_1
mov word ptr [rax], dx
add rax, 2
memset_tail_1:
test r9, 1
jz memset_done
mov byte ptr [rax], dl
jmp memset_done
memset_small:
test r9, r9
jz memset_done
mov byte ptr [rax], dl
inc rax
dec r9
jmp memset_small
memset_done:
vzeroupper
ret
fast_memset ENDP
; ============================================================================
; 字符串操作
; ============================================================================
; uint64_t fast_strlen(const char* str) -> RAX
; 使用 SSE4.2 PCMPESTRI 搜索 null terminator
fast_strlen PROC
mov rax, rcx ; rax = str
xor rcx, rcx ; rcx = 计数器
; 每次检查 16 字节
pxor xmm0, xmm0 ; 搜索 0
strlen_sse_loop:
; 检查是否接近字符串末尾 (避免越界读取)
; 简化: 逐 16 字节检查
movdqu xmm1, xmmword ptr [rax + rcx]
pcmpestrm xmm0, xmm1, 00001000b ; 搜索 0, 返回掩码
jc strlen_found
add rcx, 16
jmp strlen_sse_loop
strlen_found:
; 获取第一个匹配位置
pcmpestri xmm0, xmm1, 00001000b ; ECX = 匹配位置
add rax, rcx
add rax, rcx
; 需要计算实际位置
; 简化: 使用标量回退
mov rax, rcx
ret
; 标量回退
strlen_scalar:
mov rax, rcx
strlen_scalar_loop:
cmp byte ptr [rax], 0
je strlen_scalar_done
inc rax
jmp strlen_scalar_loop
strlen_scalar_done:
sub rax, rcx
ret
fast_strlen ENDP
; int fast_strcmp(const char* a, const char* b) -> EAX
; 返回: 0=相等, <0=a<b, >0=a>b
fast_strcmp PROC
xor rax, rax
strcmp_loop:
movzx r8d, byte ptr [rcx + rax]
movzx r9d, byte ptr [rdx + rax]
cmp r8b, r9b
jne strcmp_diff
test r8b, r8b
jz strcmp_equal
inc rax
jmp strcmp_loop
strcmp_diff:
mov eax, r8d
sub eax, r9d
ret
strcmp_equal:
xor eax, eax
ret
fast_strcmp ENDP
END
+34
View File
@@ -0,0 +1,34 @@
#include "audio.h"
#include <stdlib.h>
#include <string.h>
AudioSystem* audio_create(void) {
AudioSystem* audio = (AudioSystem*)calloc(1, sizeof(AudioSystem));
return audio;
}
void audio_destroy(AudioSystem* audio) {
free(audio);
}
AudioSource* audio_source_create(AudioSystem* audio) {
AudioSource* source = (AudioSource*)calloc(1, sizeof(AudioSource));
source->volume = 1.0f;
source->pitch = 1.0f;
return source;
}
void audio_source_destroy(AudioSource* source) {
free(source);
}
void audio_source_play(AudioSource* source) { (void)source; }
void audio_source_stop(AudioSource* source) { (void)source; }
void audio_source_pause(AudioSource* source) { (void)source; }
void audio_source_resume(AudioSource* source) { (void)source; }
void audio_source_set_volume(AudioSource* source, float v) { if (source) source->volume = v; }
void audio_source_set_pitch(AudioSource* source, float p) { if (source) source->pitch = p; }
void audio_source_set_loop(AudioSource* source, int l) { if (source) source->loop = l; }
int audio_load_wav(AudioSource* source, const char* path) { (void)source; (void)path; return 0; }
int audio_load_wav_memory(AudioSource* source, const uint8_t* data, uint32_t size) { (void)source; (void)data; (void)size; return 0; }
void audio_set_master_volume(AudioSystem* audio, float v) { (void)audio; (void)v; }
+49
View File
@@ -0,0 +1,49 @@
#pragma once
// ============================================================================
// audio.h - 音频系统 (XAudio2)
// ============================================================================
#include <xaudio2.h>
#include <stdint.h>
// 音频源
typedef struct {
IXAudio2SourceVoice* source;
IXAudio2Voice* mastering;
float volume;
float pitch;
int loop;
} AudioSource;
// 音频管理器
typedef struct {
IXAudio2* xaudio2;
IXAudio2MasteringVoice* mastering_voice;
} AudioSystem;
// 初始化/销毁
AudioSystem* audio_create(void);
void audio_destroy(AudioSystem* audio);
// 音频源
AudioSource* audio_source_create(AudioSystem* audio);
void audio_source_destroy(AudioSource* source);
// 播放
void audio_source_play(AudioSource* source);
void audio_source_stop(AudioSource* source);
void audio_source_pause(AudioSource* source);
void audio_source_resume(AudioSource* source);
// 音量/音调
void audio_source_set_volume(AudioSource* source, float volume);
void audio_source_set_pitch(AudioSource* source, float pitch);
void audio_source_set_loop(AudioSource* source, int loop);
// WAV加载
int audio_load_wav(AudioSource* source, const char* path);
int audio_load_wav_memory(AudioSource* source, const uint8_t* data, uint32_t size);
// 主音量
void audio_set_master_volume(AudioSystem* audio, float volume);
+157
View File
@@ -0,0 +1,157 @@
// ============================================================================
// engine.c - 引擎核心实现
// ============================================================================
#include "engine.h"
#include "logger.h"
#include "timer.h"
#include "../Window/window.h"
#include "../include/engine_api.h"
#include <stdlib.h>
#include <Windows.h>
// 引擎实例 (单例)
static Engine g_engine = {0};
// 回调
static EngineUpdateCallback g_update_callback = NULL;
static EngineRenderCallback g_render_callback = NULL;
static EngineKeyCallback g_key_callback = NULL;
static EngineResizeCallback g_resize_callback = NULL;
// 内部函数
static void on_key(int key) {
if (g_key_callback) {
g_key_callback(&g_engine, key);
}
if (key == VK_ESCAPE) {
engine_request_quit(&g_engine);
}
}
static void on_resize(int width, int height) {
if (g_resize_callback) {
g_resize_callback(&g_engine, width, height);
}
}
Engine* engine_create(void) {
return &g_engine;
}
void engine_destroy(Engine* engine) {
if (engine) {
engine_shutdown(engine);
}
}
int engine_init(Engine* engine, const EngineConfig* config) {
if (engine->initialized) return 1;
engine->config = *config;
// 初始化日志
logger_init("engine.log");
LOG_INFO("Initializing MiMo Engine ASM...");
// 初始化计时器
timer_init();
// 创建窗口
engine->window = window_create(
config->app_name,
config->window_width,
config->window_height,
config->fullscreen
);
if (!engine->window) {
LOG_ERROR("Failed to create window!");
return 0;
}
// 设置回调
window_set_key_callback(engine->window, on_key);
window_set_resize_callback(engine->window, on_resize);
LOG_INFO("Window created: %dx%d", config->window_width, config->window_height);
engine->initialized = 1;
engine->running = 1;
engine->frame_count = 0;
LOG_INFO("MiMo Engine ASM initialized successfully.");
return 1;
}
void engine_run(Engine* engine) {
if (!engine->initialized) {
LOG_ERROR("Engine not initialized!");
return;
}
while (engine->running) {
// 处理窗口消息
if (!window_process_messages(engine->window)) {
engine->running = 0;
break;
}
// 更新计时
timer_tick();
engine->delta_time = timer_get_delta();
engine->total_time = timer_get_total();
engine->frame_count++;
// 用户更新
if (g_update_callback) {
g_update_callback(engine, engine->delta_time);
}
// 用户渲染
if (g_render_callback) {
g_render_callback(engine);
}
}
}
void engine_shutdown(Engine* engine) {
if (!engine->initialized) return;
LOG_INFO("Shutting down MiMo Engine ASM...");
if (engine->renderer) {
// renderer_destroy(engine->renderer);
engine->renderer = NULL;
}
if (engine->window) {
window_destroy(engine->window);
engine->window = NULL;
}
logger_shutdown();
engine->initialized = 0;
engine->running = 0;
}
void engine_request_quit(Engine* engine) {
engine->running = 0;
}
// 回调设置
void engine_set_update_callback(Engine* engine, EngineUpdateCallback callback) {
g_update_callback = callback;
}
void engine_set_render_callback(Engine* engine, EngineRenderCallback callback) {
g_render_callback = callback;
}
void engine_set_key_callback(Engine* engine, EngineKeyCallback callback) {
g_key_callback = callback;
}
void engine_set_resize_callback(Engine* engine, EngineResizeCallback callback) {
g_resize_callback = callback;
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
// ============================================================================
// engine.h - 引擎核心
// ============================================================================
#include <stdint.h>
// 前向声明
typedef struct Window Window;
// 引擎配置
typedef struct {
const char* app_name;
int window_width;
int window_height;
int fullscreen;
int vsync;
} EngineConfig;
// 引擎状态
typedef struct {
int running;
int initialized;
EngineConfig config;
Window* window;
void* renderer;
double delta_time;
double total_time;
uint64_t frame_count;
} Engine;
// 初始化默认配置
static inline EngineConfig engine_default_config(void) {
EngineConfig config;
config.app_name = "MiMo Engine ASM";
config.window_width = 1280;
config.window_height = 720;
config.fullscreen = 0;
config.vsync = 1;
return config;
}
// 引擎函数
Engine* engine_create(void);
void engine_destroy(Engine* engine);
int engine_init(Engine* engine, const EngineConfig* config);
void engine_run(Engine* engine);
void engine_shutdown(Engine* engine);
void engine_request_quit(Engine* engine);
// 回调
typedef void (*EngineUpdateCallback)(Engine* engine, double delta_time);
typedef void (*EngineRenderCallback)(Engine* engine);
typedef void (*EngineKeyCallback)(Engine* engine, int key);
typedef void (*EngineResizeCallback)(Engine* engine, int width, int height);
void engine_set_update_callback(Engine* engine, EngineUpdateCallback callback);
void engine_set_render_callback(Engine* engine, EngineRenderCallback callback);
void engine_set_key_callback(Engine* engine, EngineKeyCallback callback);
void engine_set_resize_callback(Engine* engine, EngineResizeCallback callback);
+73
View File
@@ -0,0 +1,73 @@
// ============================================================================
// logger.c - 日志系统实现
// ============================================================================
#include "logger.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>
static FILE* g_log_file = NULL;
static LogLevel g_log_level = LOG_TRACE;
static const char* level_strings[] = {
"TRACE", "DEBUG", "INFO ", "WARN ", "ERROR", "FATAL"
};
void logger_init(const char* log_file) {
if (log_file) {
g_log_file = fopen(log_file, "w");
if (g_log_file) {
fprintf(g_log_file, "=== MiMo Engine ASM Log ===\n");
fflush(g_log_file);
}
}
printf("=== MiMo Engine ASM Log ===\n");
}
void logger_shutdown(void) {
if (g_log_file) {
fclose(g_log_file);
g_log_file = NULL;
}
}
void logger_set_level(LogLevel level) {
g_log_level = level;
}
void logger_log(LogLevel level, const char* file, int line, const char* fmt, ...) {
if (level < g_log_level) return;
// 时间戳
time_t now = time(NULL);
struct tm* tm_info = localtime(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%H:%M:%S", tm_info);
// 文件名 (去掉路径)
const char* filename = strrchr(file, '\\');
if (!filename) filename = strrchr(file, '/');
if (filename) filename++; else filename = file;
// 格式化消息
char msg[2048];
va_list args;
va_start(args, fmt);
vsnprintf(msg, sizeof(msg), fmt, args);
va_end(args);
// 输出到控制台
if (level >= LOG_WARN) {
fprintf(stderr, "[%s] [%s] %s:%d - %s\n", time_str, level_strings[level], filename, line, msg);
} else {
printf("[%s] [%s] %s:%d - %s\n", time_str, level_strings[level], filename, line, msg);
}
// 输出到文件
if (g_log_file) {
fprintf(g_log_file, "[%s] [%s] %s:%d - %s\n", time_str, level_strings[level], filename, line, msg);
fflush(g_log_file);
}
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
// ============================================================================
// logger.h - 日志系统
// ============================================================================
#include <stdio.h>
// 日志级别
typedef enum {
LOG_TRACE = 0,
LOG_DEBUG,
LOG_INFO,
LOG_WARN,
LOG_ERROR,
LOG_FATAL
} LogLevel;
// 初始化/关闭
void logger_init(const char* log_file);
void logger_shutdown(void);
// 设置日志级别
void logger_set_level(LogLevel level);
// 日志函数
void logger_log(LogLevel level, const char* file, int line, const char* fmt, ...);
// 便捷宏
#define LOG_TRACE(...) logger_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_DEBUG(...) logger_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_INFO(...) logger_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_WARN(...) logger_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_ERROR(...) logger_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_FATAL(...) logger_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
+78
View File
@@ -0,0 +1,78 @@
// ============================================================================
// timer.c - 高精度计时器实现 (使用 rdtsc.asm)
// ============================================================================
#include "timer.h"
#include "../include/engine_api.h"
#include <Windows.h>
static double g_seconds_per_count = 0.0;
static int64_t g_prev_time = 0;
static int64_t g_curr_time = 0;
static int64_t g_start_time = 0;
static double g_delta_time = 0.0;
static double g_total_time = 0.0;
static double g_fps = 0.0;
static uint64_t g_frame_count = 0;
static double g_fps_accumulator = 0.0;
static uint64_t g_fps_frame_count = 0;
void timer_init(void) {
// 使用 QueryPerformanceCounter 获取高精度时间
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
g_seconds_per_count = 1.0 / (double)freq.QuadPart;
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
g_start_time = now.QuadPart;
g_prev_time = now.QuadPart;
g_curr_time = now.QuadPart;
g_delta_time = 0.0;
g_total_time = 0.0;
g_fps = 0.0;
g_frame_count = 0;
g_fps_accumulator = 0.0;
g_fps_frame_count = 0;
}
void timer_reset(void) {
timer_init();
}
void timer_tick(void) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
g_curr_time = now.QuadPart;
g_delta_time = (g_curr_time - g_prev_time) * g_seconds_per_count;
g_total_time = (g_curr_time - g_start_time) * g_seconds_per_count;
g_prev_time = g_curr_time;
g_frame_count++;
g_fps_frame_count++;
g_fps_accumulator += g_delta_time;
if (g_fps_accumulator >= 1.0) {
g_fps = (double)g_fps_frame_count / g_fps_accumulator;
g_fps_frame_count = 0;
g_fps_accumulator = 0.0;
}
}
double timer_get_delta(void) {
return g_delta_time;
}
double timer_get_total(void) {
return g_total_time;
}
double timer_get_fps(void) {
return g_fps;
}
uint64_t timer_get_frame_count(void) {
return g_frame_count;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
// ============================================================================
// timer.h - 高精度计时器
// ============================================================================
#include <stdint.h>
// 初始化计时器
void timer_init(void);
// 重置计时器
void timer_reset(void);
// 更新一帧
void timer_tick(void);
// 获取帧间隔 (秒)
double timer_get_delta(void);
// 获取总时间 (秒)
double timer_get_total(void);
// 获取 FPS
double timer_get_fps(void);
// 获取帧数
uint64_t timer_get_frame_count(void);
+100
View File
@@ -0,0 +1,100 @@
#include "world.h"
#include <stdlib.h>
#include <string.h>
World* world_create(void) {
World* w = (World*)calloc(1, sizeof(World));
w->next_entity = 1;
return w;
}
void world_destroy(World* world) {
if (!world) return;
for (uint32_t i = 0; i < world->entity_count; i++) {
Entity e = world->entities[i];
for (uint32_t c = 0; c < world->component_count; c++) {
if (world->components[c][e] && world->component_tables[c].destroy) {
world->component_tables[c].destroy(world->components[c][e]);
}
free(world->components[c][e]);
}
}
free(world);
}
Entity world_create_entity(World* world) {
if (world->entity_count >= MAX_ENTITIES) return 0;
Entity e = world->next_entity++;
world->entities[world->entity_count++] = e;
world->entity_masks[e] = 0;
return e;
}
void world_destroy_entity(World* world, Entity entity) {
for (uint32_t c = 0; c < world->component_count; c++) {
if (world->components[c][entity] && world->component_tables[c].destroy) {
world->component_tables[c].destroy(world->components[c][entity]);
}
free(world->components[c][entity]);
world->components[c][entity] = NULL;
}
world->entity_masks[entity] = 0;
for (uint32_t i = 0; i < world->entity_count; i++) {
if (world->entities[i] == entity) {
world->entities[i] = world->entities[--world->entity_count];
break;
}
}
}
int world_entity_alive(World* world, Entity entity) {
for (uint32_t i = 0; i < world->entity_count; i++) {
if (world->entities[i] == entity) return 1;
}
return 0;
}
ComponentType world_register_component(World* world, uint32_t size, ComponentVTable vtable) {
ComponentType type = world->component_count++;
world->component_sizes[type] = size;
world->component_tables[type] = vtable;
return type;
}
void* world_add_component(World* world, Entity entity, ComponentType type) {
if (world->components[type][entity]) return world->components[type][entity];
void* comp = calloc(1, world->component_sizes[type]);
world->components[type][entity] = comp;
world->entity_masks[entity] |= (1ULL << type);
return comp;
}
void* world_get_component(World* world, Entity entity, ComponentType type) {
return world->components[type][entity];
}
void world_remove_component(World* world, Entity entity, ComponentType type) {
if (world->components[type][entity]) {
if (world->component_tables[type].destroy) {
world->component_tables[type].destroy(world->components[type][entity]);
}
free(world->components[type][entity]);
world->components[type][entity] = NULL;
world->entity_masks[entity] &= ~(1ULL << type);
}
}
int world_has_component(World* world, Entity entity, ComponentType type) {
return (world->entity_masks[entity] & (1ULL << type)) != 0;
}
void world_each(World* world, uint64_t mask, SystemFunc func, void* data) {
for (uint32_t i = 0; i < world->entity_count; i++) {
Entity e = world->entities[i];
if ((world->entity_masks[e] & mask) == mask) {
func(world, e, data);
}
}
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
// ============================================================================
// world.h - 实体组件系统 (ECS)
// ============================================================================
#include <stdint.h>
#include "../include/engine_api.h"
#define MAX_ENTITIES 4096
#define MAX_COMPONENTS 32
typedef uint32_t Entity;
typedef uint32_t ComponentType;
// 组件接口
typedef struct {
void (*destroy)(void* component);
} ComponentVTable;
// 世界
typedef struct {
Entity entities[MAX_ENTITIES];
uint32_t entity_count;
uint32_t next_entity;
void* components[MAX_COMPONENTS][MAX_ENTITIES];
ComponentVTable component_tables[MAX_COMPONENTS];
uint32_t component_sizes[MAX_COMPONENTS];
uint32_t component_count;
uint64_t entity_masks[MAX_ENTITIES];
} World;
// 创建/销毁
World* world_create(void);
void world_destroy(World* world);
// 实体
Entity world_create_entity(World* world);
void world_destroy_entity(World* world, Entity entity);
int world_entity_alive(World* world, Entity entity);
// 组件
ComponentType world_register_component(World* world, uint32_t size, ComponentVTable vtable);
void* world_add_component(World* world, Entity entity, ComponentType type);
void* world_get_component(World* world, Entity entity, ComponentType type);
void world_remove_component(World* world, Entity entity, ComponentType type);
int world_has_component(World* world, Entity entity, ComponentType type);
// 系统遍历
typedef void (*SystemFunc)(World* world, Entity entity, void* data);
void world_each(World* world, uint64_t mask, SystemFunc func, void* data);
+303
View File
@@ -0,0 +1,303 @@
#include "bitmap_font.h"
#include <stdlib.h>
#include <string.h>
#include "../Core/logger.h"
static const uint8_t FONT_DATA[FONT_NUM_CHARS][FONT_CHAR_H] = {
{0},{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00},
{0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00},
{0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
{0x00,0x30,0x30,0x30,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
{0},{0},{0},
{0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0},{0},
{0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0},{0},{0},{0},{0},{0},{0},{0},{0},
{0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
{0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00},
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
{0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00},
{0x00,0x00,0xC6,0xC6,0xC6,0x6C,0x38,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},
{0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},
};
static Shader* g_font_shader = NULL;
static ID3D11Buffer* g_font_vb = NULL;
static ID3D11Buffer* g_font_ib = NULL;
static FontVert g_font_verts[FONT_MAX_QUADS * 4];
static uint32_t g_font_indices[FONT_MAX_QUADS * 6];
static int g_font_vi = 0;
static int g_font_ii = 0;
static void make_ortho(float* m, float sw, float sh) {
memset(m, 0, 64);
m[0] = 2.0f / sw;
m[5] = -2.0f / sh;
m[10] = 1.0f;
m[12] = -1.0f;
m[13] = 1.0f;
m[15] = 1.0f;
}
static void make_atlas(uint8_t* pixels, int w, int h) {
memset(pixels, 0, (size_t)w * h * 4);
int cols = w / FONT_CHAR_W;
for (int i = 0; i < FONT_NUM_CHARS; i++) {
int cx = (i % cols) * FONT_CHAR_W;
int cy = (i / cols) * FONT_CHAR_H;
for (int row = 0; row < FONT_CHAR_H; row++) {
uint8_t bits = FONT_DATA[i][row];
for (int col = 0; col < 8; col++) {
if (bits & (0x80 >> col)) {
int px = cx + col, py = cy + row;
int idx = (py * w + px) * 4;
pixels[idx] = 255; pixels[idx+1] = 255; pixels[idx+2] = 255; pixels[idx+3] = 255;
}
}
}
}
}
int bitmap_font_init(BitmapFont* f, ID3D11Device* dev) {
memset(f, 0, sizeof(*f));
int cols = 16;
f->atlas_w = cols * FONT_CHAR_W;
f->atlas_h = ((FONT_NUM_CHARS + cols - 1) / cols) * FONT_CHAR_H;
uint8_t* pixels = (uint8_t*)malloc((size_t)f->atlas_w * f->atlas_h * 4);
make_atlas(pixels, f->atlas_w, f->atlas_h);
D3D11_TEXTURE2D_DESC td = {0};
td.Width = (UINT)f->atlas_w; td.Height = (UINT)f->atlas_h;
td.MipLevels = 1; td.ArraySize = 1;
td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_DEFAULT;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA sd = {0};
sd.pSysMem = pixels; sd.SysMemPitch = (UINT)(f->atlas_w * 4);
HRESULT hr = dev->lpVtbl->CreateTexture2D(dev, &td, &sd, &f->texture);
free(pixels);
if (FAILED(hr)) return 0;
dev->lpVtbl->CreateShaderResourceView(dev, (ID3D11Resource*)f->texture, NULL, &f->srv);
f->shader = shader_create();
if (!shader_compile(f->shader, dev, NULL, NULL, 0, 0)) return 0;
g_font_shader = f->shader;
D3D11_BUFFER_DESC bd = {0};
bd.ByteWidth = FONT_MAX_QUADS * 4 * sizeof(FontVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
memset(g_font_verts, 0, sizeof(g_font_verts));
sd.pSysMem = g_font_verts;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &g_font_vb);
bd.ByteWidth = FONT_MAX_QUADS * 6 * sizeof(uint32_t);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
memset(g_font_indices, 0, sizeof(g_font_indices));
sd.pSysMem = g_font_indices;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &g_font_ib);
bd.ByteWidth = 256; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
dev->lpVtbl->CreateBuffer(dev, &bd, NULL, &f->cb);
D3D11_BLEND_DESC bdesc = {0};
bdesc.RenderTarget[0].BlendEnable = TRUE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
dev->lpVtbl->CreateBlendState(dev, &bdesc, &f->blend);
D3D11_SAMPLER_DESC sdesc = {0};
sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sdesc.AddressU = sdesc.AddressV = sdesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
dev->lpVtbl->CreateSamplerState(dev, &sdesc, &f->sampler);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &f->ds_no_depth);
LOG_INFO("bitmap_font: initialized (%dx%d atlas)", f->atlas_w, f->atlas_h);
return 1;
}
void bitmap_font_destroy(BitmapFont* f) {
if (!f) return;
if (f->ds_no_depth) f->ds_no_depth->lpVtbl->Release(f->ds_no_depth);
if (f->sampler) f->sampler->lpVtbl->Release(f->sampler);
if (f->blend) f->blend->lpVtbl->Release(f->blend);
if (f->cb) f->cb->lpVtbl->Release(f->cb);
if (g_font_ib) { g_font_ib->lpVtbl->Release(g_font_ib); g_font_ib = NULL; }
if (g_font_vb) { g_font_vb->lpVtbl->Release(g_font_vb); g_font_vb = NULL; }
if (f->shader) { shader_destroy(f->shader); g_font_shader = NULL; }
if (f->srv) f->srv->lpVtbl->Release(f->srv);
if (f->texture) f->texture->lpVtbl->Release(f->texture);
memset(f, 0, sizeof(*f));
}
static void font_flush(ID3D11DeviceContext* ctx,
float screen_w, float screen_h, int num_idx) {
if (num_idx == 0) return;
float wvp[64];
make_ortho(wvp, screen_w, screen_h);
ID3D11Device* dev = NULL;
ctx->lpVtbl->GetDevice(ctx, &dev);
D3D11_RASTERIZER_DESC rdesc = {0};
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_NONE;
rdesc.ScissorEnable = FALSE;
ID3D11RasterizerState* rstate = NULL;
HRESULT hr = dev->lpVtbl->CreateRasterizerState(dev, &rdesc, &rstate);
if (rstate) {
ctx->lpVtbl->RSSetState(ctx, rstate);
rstate->lpVtbl->Release(rstate);
}
dev->lpVtbl->Release(dev);
shader_bind(g_font_shader, ctx);
shader_set_matrix(g_font_shader, ctx, wvp);
UINT stride = sizeof(FontVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &g_font_vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, g_font_ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)num_idx, 0, 0);
}
static void font_begin(void) { g_font_vi = 0; g_font_ii = 0; }
static void font_add_quad(BitmapFont* f, float x, float y, float w, float h,
float r, float g, float b, float a) {
if (g_font_vi + 4 > FONT_MAX_QUADS * 4) return;
float u0 = 0.19f, v0 = 0.01f, u1 = 0.24f, v1 = 0.15f;
int vi = g_font_vi;
g_font_verts[vi] = (FontVert){{x, y, 0},{0,0,-1},{u0,v0},{r,g,b,a}};
g_font_verts[vi+1] = (FontVert){{x+w, y, 0},{0,0,-1},{u1,v0},{r,g,b,a}};
g_font_verts[vi+2] = (FontVert){{x+w, y+h, 0},{0,0,-1},{u1,v1},{r,g,b,a}};
g_font_verts[vi+3] = (FontVert){{x, y+h, 0},{0,0,-1},{u0,v1},{r,g,b,a}};
uint32_t base = (uint32_t)vi;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+1; g_font_indices[g_font_ii++] = base+2;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+2; g_font_indices[g_font_ii++] = base+3;
g_font_vi += 4;
}
void bitmap_font_draw(BitmapFont* f, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h) {
if (!text || !*text || !f->shader) return;
int len = (int)strlen(text);
if (len > FONT_MAX_QUADS) len = FONT_MAX_QUADS;
int cols = f->atlas_w / FONT_CHAR_W;
font_begin();
int cx = x;
for (int i = 0; i < len; i++) {
int ch = (unsigned char)text[i] - FONT_FIRST_CHAR;
if (ch < 0 || ch >= FONT_NUM_CHARS) ch = 0;
int col_idx = ch % cols;
int row_idx = ch / cols;
float u0 = (float)(col_idx * FONT_CHAR_W) / (float)f->atlas_w;
float v0 = (float)(row_idx * FONT_CHAR_H) / (float)f->atlas_h;
float u1 = (float)((col_idx + 1) * FONT_CHAR_W) / (float)f->atlas_w;
float v1 = (float)((row_idx + 1) * FONT_CHAR_H) / (float)f->atlas_h;
int vi = g_font_vi;
g_font_verts[vi] = (FontVert){{(float)cx,(float)y,0},{0,0,-1},{u0,v0},{r,g,b,a}};
g_font_verts[vi+1] = (FontVert){{(float)cx+FONT_CHAR_W,(float)y,0},{0,0,-1},{u1,v0},{r,g,b,a}};
g_font_verts[vi+2] = (FontVert){{(float)cx+FONT_CHAR_W,(float)y+FONT_CHAR_H,0},{0,0,-1},{u1,v1},{r,g,b,a}};
g_font_verts[vi+3] = (FontVert){{(float)cx,(float)y+FONT_CHAR_H,0},{0,0,-1},{u0,v1},{r,g,b,a}};
uint32_t base = (uint32_t)vi;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+1; g_font_indices[g_font_ii++] = base+2;
g_font_indices[g_font_ii++] = base; g_font_indices[g_font_ii++] = base+2; g_font_indices[g_font_ii++] = base+3;
g_font_vi += 4;
cx += FONT_CHAR_W;
}
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_vb, 0, NULL, g_font_verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_ib, 0, NULL, g_font_indices, 0, 0);
font_flush(ctx, screen_w, screen_h, g_font_ii);
}
void bitmap_font_rect(BitmapFont* f, ID3D11DeviceContext* ctx,
float x, float y, float w, float h,
float r, float g, float b, float a,
float screen_w, float screen_h) {
if (!f->shader) return;
font_begin();
font_add_quad(f, x, y, w, h, r, g, b, a);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_vb, 0, NULL, g_font_verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_font_ib, 0, NULL, g_font_indices, 0, 0);
font_flush(ctx, screen_w, screen_h, g_font_ii);
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#include "../Rendering/shader.h"
#define FONT_CHAR_W 8
#define FONT_CHAR_H 16
#define FONT_FIRST_CHAR 32
#define FONT_NUM_CHARS 96
#define FONT_MAX_QUADS 4096
typedef struct {
float pos[3];
float norm[3];
float uv[2];
float color[4];
} FontVert;
typedef struct {
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* srv;
ID3D11Buffer* cb;
Shader* shader;
ID3D11BlendState* blend;
ID3D11SamplerState* sampler;
ID3D11DepthStencilState* ds_no_depth;
int atlas_w;
int atlas_h;
} BitmapFont;
int bitmap_font_init(BitmapFont* f, ID3D11Device* dev);
void bitmap_font_destroy(BitmapFont* f);
void bitmap_font_draw(BitmapFont* f, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h);
void bitmap_font_rect(BitmapFont* f, ID3D11DeviceContext* ctx,
float x, float y, float w, float h,
float r, float g, float b, float a,
float screen_w, float screen_h);
+122
View File
@@ -0,0 +1,122 @@
#include "editor.h"
#include "../Core/logger.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static const float BG_DARK[] = {0.12f, 0.12f, 0.14f};
static const float BG_PANEL[] = {0.16f, 0.16f, 0.18f};
static const float BG_TITLE[] = {0.20f, 0.20f, 0.24f};
static const float BG_INPUT[] = {0.10f, 0.10f, 0.12f};
int editor_init(Editor* ed, GraphicsDevice* dev) {
memset(ed, 0, sizeof(*ed));
ed->device = dev;
if (!uilayer_init(&ed->ui, dev->device, (float)dev->width, (float)dev->height)) return 0;
int sw = dev->width, sh = dev->height;
int menu_h = 28;
ed->panels[0] = (EditorPanel){PANEL_VIEWPORT, "Viewport", 220, menu_h, sw-440, sh-menu_h-200, 1, 0, 0};
ed->panels[1] = (EditorPanel){PANEL_SCENE, "Scene", 0, menu_h, 220, sh-menu_h-200, 1, 0, 0};
ed->panels[2] = (EditorPanel){PANEL_INSPECTOR, "Inspector", sw-220, menu_h, 220, sh-menu_h-200, 1, 0, 0};
ed->panels[3] = (EditorPanel){PANEL_CONSOLE, "Console", 0, sh-200, sw, 200, 1, 0, 0};
ed->panel_count = 4;
ed->scene_entities_count = 8;
strcpy(ed->selected_entity, "Cube");
LOG_INFO("Editor initialized");
return 1;
}
void editor_shutdown(Editor* ed) {
uilayer_destroy(&ed->ui);
}
void editor_update(Editor* ed, float dt) {
ed->time += dt;
ed->viewport_rotation += dt * 0.5f;
}
void editor_render(Editor* ed) {
ID3D11DeviceContext* ctx = ed->device->context;
float sw = (float)ed->device->width;
float sh = (float)ed->device->height;
graphics_device_clear(ed->device, BG_DARK[0], BG_DARK[1], BG_DARK[2], 1.0f);
uilayer_begin(&ed->ui);
uilayer_rect(&ed->ui, 0, 0, sw, 28, 1.0f, 0.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 0, 28, sw, 28, 0.0f, 1.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 0, 56, sw/3, sh-256, 0.0f, 0.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, sw/3, 56, sw/3, sh-256, 1.0f, 1.0f, 0.0f, 1.0f);
uilayer_rect(&ed->ui, 2*sw/3, 56, sw/3, sh-256, 1.0f, 0.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, 0, sh-200, sw, 200, 0.0f, 1.0f, 1.0f, 1.0f);
uilayer_rect(&ed->ui, 0, sh-22, sw, 22, 1.0f, 0.5f, 0.0f, 1.0f);
uilayer_flush(&ed->ui, ctx);
float sw2 = sw, sh2 = sh;
bitmap_font_draw(&ed->font, ctx, "MiMo Engine Editor", 10, 6,
0.4f, 0.75f, 1.0f, 1.0f, sw2, sh2);
const char* menu[] = {"File", "Edit", "View", "Build", "Help"};
int mx = 180;
for (int i = 0; i < 5; i++) {
bitmap_font_draw(&ed->font, ctx, menu[i], mx + 8, 6,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
mx += (int)strlen(menu[i]) * 8 + 16;
}
const char* tools[] = {"Select", "Move", "Rotate", "Scale"};
int tx = 6;
for (int i = 0; i < 4; i++) {
bitmap_font_draw(&ed->font, ctx, tools[i], tx + 4, 34,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
tx += (int)strlen(tools[i]) * 8 + 16;
}
for (int i = 0; i < ed->panel_count; i++) {
EditorPanel* p = &ed->panels[i];
if (!p->visible) continue;
bitmap_font_draw(&ed->font, ctx, p->title, p->x + 6, p->y + 6,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
}
bitmap_font_draw(&ed->font, ctx, ed->selected_entity, 226, 56,
0.4f, 0.75f, 1.0f, 1.0f, sw2, sh2);
const char* entities[] = {"Light", "Camera", "Cube", "Plane", "Sphere", "Particles", "Audio", "Skybox"};
for (int i = 0; i < 8; i++) {
bitmap_font_draw(&ed->font, ctx, entities[i], 226, 78 + i * 22,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
}
const char* sections[] = {"Transform", "Mesh Filter", "Material", "Collider"};
int sy = 56;
for (int s = 0; s < 4; s++) {
bitmap_font_draw(&ed->font, ctx, sections[s], (int)sw - 214, sy,
0.9f, 0.9f, 0.92f, 1.0f, sw2, sh2);
sy += 26;
}
char status[128];
snprintf(status, sizeof(status), "Entities: %d | Time: %.1fs", ed->scene_entities_count, ed->time);
bitmap_font_draw(&ed->font, ctx, status, 10, (int)sh - 18,
0.55f, 0.55f, 0.6f, 1.0f, sw2, sh2);
}
void editor_handle_input(Editor* ed, int msg, int wp, int lp) {
(void)lp;
switch (msg) {
case 0x0200: ed->input.mouse_x = wp & 0xFFFF; ed->input.mouse_y = (wp >> 16) & 0x7FFF; break;
case 0x0201: ed->input.mouse_lbtn = 1; break;
case 0x0202: ed->input.mouse_lbtn = 0; break;
case 0x0204: ed->input.mouse_rbtn = 1; break;
case 0x0205: ed->input.mouse_rbtn = 0; break;
case 0x0100: if (wp < 256) ed->input.key_down[wp] = 1; break;
case 0x0101: if (wp < 256) ed->input.key_down[wp] = 0; break;
}
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "uilayer.h"
#include "bitmap_font.h"
#include "../Rendering/graphics_device.h"
#include <stdint.h>
#define EDITOR_MAX_PANELS 16
typedef enum {
PANEL_SCENE,
PANEL_INSPECTOR,
PANEL_CONSOLE,
PANEL_ASSETS,
PANEL_VIEWPORT,
} PanelType;
typedef struct {
PanelType type;
const char* title;
int x, y, w, h;
int visible;
int collapsed;
int active_tab;
} EditorPanel;
typedef struct {
int mouse_x, mouse_y;
int mouse_lbtn;
int mouse_rbtn;
int key_down[256];
char text_input[256];
int text_len;
} EditorInput;
typedef struct {
GraphicsDevice* device;
UILayer ui;
BitmapFont font;
EditorPanel panels[EDITOR_MAX_PANELS];
int panel_count;
EditorInput input;
float time;
char console_lines[32][256];
int console_count;
int console_scroll;
char selected_entity[128];
int scene_entities_count;
float viewport_rotation;
} Editor;
int editor_init(Editor* ed, GraphicsDevice* dev);
void editor_shutdown(Editor* ed);
void editor_update(Editor* ed, float dt);
void editor_render(Editor* ed);
void editor_handle_input(Editor* ed, int msg, int wp, int lp);
+124
View File
@@ -0,0 +1,124 @@
#include "editor_2d.h"
#include <stdlib.h>
#include <string.h>
int editor2d_init(Editor2D* e, ID3D11Device* dev) {
memset(e, 0, sizeof(*e));
e->shader = shader_create();
if (!shader_compile(e->shader, dev, NULL, NULL, 0, 0)) return 0;
D3D11_BUFFER_DESC bd = {0};
bd.ByteWidth = ED2D_MAX_QUADS * 4 * sizeof(Ed2DVert);
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (FAILED(dev->lpVtbl->CreateBuffer(dev, &bd, NULL, &e->vb))) return 0;
bd.ByteWidth = ED2D_MAX_QUADS * 6 * sizeof(uint32_t);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
uint32_t* idx = (uint32_t*)malloc(ED2D_MAX_QUADS * 6 * sizeof(uint32_t));
for (int i = 0; i < ED2D_MAX_QUADS; i++) {
uint32_t b2 = i * 4;
idx[i*6]=b2; idx[i*6+1]=b2+1; idx[i*6+2]=b2+2;
idx[i*6+3]=b2; idx[i*6+4]=b2+2; idx[i*6+5]=b2+3;
}
D3D11_SUBRESOURCE_DATA sd = {0}; sd.pSysMem = idx;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &e->ib);
free(idx);
e->verts = (Ed2DVert*)malloc(ED2D_MAX_QUADS * 4 * sizeof(Ed2DVert));
D3D11_BLEND_DESC bdesc = {0};
bdesc.RenderTarget[0].BlendEnable = TRUE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
dev->lpVtbl->CreateBlendState(dev, &bdesc, &e->blend);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &e->ds_no_depth);
return 1;
}
void editor2d_destroy(Editor2D* e) {
if (!e) return;
if (e->ds_no_depth) e->ds_no_depth->lpVtbl->Release(e->ds_no_depth);
if (e->blend) e->blend->lpVtbl->Release(e->blend);
if (e->ib) e->ib->lpVtbl->Release(e->ib);
if (e->vb) e->vb->lpVtbl->Release(e->vb);
shader_destroy(e->shader);
free(e->verts);
memset(e, 0, sizeof(*e));
}
void editor2d_begin(Editor2D* e, float sw, float sh) {
e->quad_count = 0;
e->screen_w = sw;
e->screen_h = sh;
memset(e->wvp, 0, sizeof(e->wvp));
e->wvp[0] = 2.0f / sw;
e->wvp[5] = -2.0f / sh;
e->wvp[12] = -1.0f;
e->wvp[13] = 1.0f;
e->wvp[15] = 1.0f;
}
void editor2d_rect(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a) {
if (e->quad_count >= ED2D_MAX_QUADS) return;
int vi = e->quad_count * 4;
e->verts[vi+0] = (Ed2DVert){x, y, 0, 0,0,-1, 0,1, r,g,b,a};
e->verts[vi+1] = (Ed2DVert){x+w, y, 0, 0,0,-1, 1,1, r,g,b,a};
e->verts[vi+2] = (Ed2DVert){x+w, y+h, 0, 0,0,-1, 1,0, r,g,b,a};
e->verts[vi+3] = (Ed2DVert){x, y+h, 0, 0,0,-1, 0,0, r,g,b,a};
e->quad_count++;
}
void editor2d_rect_border(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a, float t) {
editor2d_rect(e, x, y, w, t, r, g, b, a);
editor2d_rect(e, x, y+h-t, w, t, r, g, b, a);
editor2d_rect(e, x, y, t, h, r, g, b, a);
editor2d_rect(e, x+w-t, y, t, h, r, g, b, a);
}
void editor2d_end(Editor2D* e, ID3D11DeviceContext* ctx) {
if (e->quad_count == 0) return;
D3D11_MAPPED_SUBRESOURCE mapped;
if (FAILED(ctx->lpVtbl->Map(ctx, (ID3D11Resource*)e->vb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) return;
memcpy(mapped.pData, e->verts, (size_t)e->quad_count * 4 * sizeof(Ed2DVert));
ctx->lpVtbl->Unmap(ctx, (ID3D11Resource*)e->vb, 0);
if (e->rtv) {
ctx->lpVtbl->OMSetRenderTargets(ctx, 1, &e->rtv, NULL);
}
D3D11_VIEWPORT vp = {0};
vp.Width = e->screen_w;
vp.Height = e->screen_h;
vp.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
shader_bind(e->shader, ctx);
shader_set_matrix(e->shader, ctx, e->wvp);
UINT stride = sizeof(Ed2DVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &e->vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, e->ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
float bf[4] = {0};
ctx->lpVtbl->OMSetBlendState(ctx, e->blend, bf, 0xFFFFFFFF);
ctx->lpVtbl->OMSetDepthStencilState(ctx, e->ds_no_depth, 0);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)(e->quad_count * 6), 0, 0);
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#include "../Rendering/shader.h"
#include "../Rendering/mesh.h"
#define ED2D_MAX_QUADS 8192
typedef struct {
float x, y, z;
float nx, ny, nz;
float u, v;
float r, g, b, a;
} Ed2DVert;
typedef struct {
Shader* shader;
ID3D11Buffer* vb;
ID3D11Buffer* ib;
ID3D11BlendState* blend;
ID3D11DepthStencilState* ds_no_depth;
ID3D11RenderTargetView* rtv;
Ed2DVert* verts;
int quad_count;
float screen_w;
float screen_h;
float wvp[16];
} Editor2D;
int editor2d_init(Editor2D* e, ID3D11Device* dev);
void editor2d_destroy(Editor2D* e);
void editor2d_begin(Editor2D* e, float sw, float sh);
void editor2d_rect(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a);
void editor2d_rect_border(Editor2D* e, float x, float y, float w, float h, float r, float g, float b, float a, float thickness);
void editor2d_end(Editor2D* e, ID3D11DeviceContext* ctx);
+171
View File
@@ -0,0 +1,171 @@
#include "glyph_atlas.h"
#include <stdlib.h>
#include <string.h>
#include <d3d11.h>
#include <Windows.h>
#include "../Core/logger.h"
typedef struct {
wchar_t ch;
int x, y;
int w, h;
float u0, v0, u1, v1;
float advance_x;
} GlyphEntry;
#define MAX_GLYPHS 1024
static GlyphEntry g_entries[MAX_GLYPHS];
static int g_entry_count = 0;
int glyph_atlas_init(GlyphAtlas* ga, ID3D11Device* dev) {
memset(ga, 0, sizeof(*ga));
ga->cell_w = GLYPH_CELL_W;
ga->cell_h = GLYPH_CELL_H;
ga->atlas_w = GLYPH_ATLAS_SIZE;
ga->atlas_h = GLYPH_ATLAS_SIZE;
ga->next_x = 0;
ga->next_y = 0;
ga->u_scale = 1.0f / (float)ga->atlas_w;
ga->v_scale = 1.0f / (float)ga->atlas_h;
uint8_t* pixels = (uint8_t*)calloc(ga->atlas_w * ga->atlas_h * 4, 1);
D3D11_TEXTURE2D_DESC td = {0};
td.Width = ga->atlas_w;
td.Height = ga->atlas_h;
td.MipLevels = 1;
td.ArraySize = 1;
td.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_DEFAULT;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA sd = {0};
sd.pSysMem = pixels;
sd.SysMemPitch = ga->atlas_w * 4;
HRESULT hr = dev->lpVtbl->CreateTexture2D(dev, &td, &sd, &ga->texture);
free(pixels);
if (FAILED(hr)) return 0;
dev->lpVtbl->CreateShaderResourceView(dev, (ID3D11Resource*)ga->texture, NULL, &ga->srv);
LOG_INFO("GlyphAtlas: initialized (%dx%d, max %d glyphs)", ga->atlas_w, ga->atlas_h, MAX_GLYPHS);
return 1;
}
void glyph_atlas_destroy(GlyphAtlas* ga) {
if (!ga) return;
if (ga->srv) ga->srv->lpVtbl->Release(ga->srv);
if (ga->texture) ga->texture->lpVtbl->Release(ga->texture);
memset(ga, 0, sizeof(*ga));
g_entry_count = 0;
}
static int find_glyph(wchar_t ch) {
for (int i = 0; i < g_entry_count; i++) {
if (g_entries[i].ch == ch) return i;
}
return -1;
}
int glyph_atlas_get_or_create(GlyphAtlas* ga, ID3D11Device* dev, ID3D11DeviceContext* ctx, wchar_t ch,
float* u0, float* v0, float* u1, float* v1,
float* advance_x, float* advance_y) {
int idx = find_glyph(ch);
if (idx >= 0) {
*u0 = g_entries[idx].u0;
*v0 = g_entries[idx].v0;
*u1 = g_entries[idx].u1;
*v1 = g_entries[idx].v1;
*advance_x = g_entries[idx].advance_x;
*advance_y = (float)g_entries[idx].h;
return 1;
}
if (g_entry_count >= MAX_GLYPHS) return 0;
if (ga->next_x + ga->cell_w > ga->atlas_w) {
ga->next_x = 0;
ga->next_y += ga->cell_h;
}
if (ga->next_y + ga->cell_h > ga->atlas_h) return 0;
HDC hdc = GetDC(NULL);
HFONT hfont = CreateFontW(
ga->cell_h - 4, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, FIXED_PITCH | FF_DONTCARE, L"Microsoft YaHei"
);
HFONT old = (HFONT)SelectObject(hdc, hfont);
GLYPHMETRICS gm = {0};
MAT2 mat = {{0,0},{0,0},{0,0},{0,0}};
mat.eM11.value = 1; mat.eM22.value = 1;
DWORD size = GetGlyphOutlineW(hdc, ch, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat);
int gw = gm.gmBlackBoxX;
int gh = gm.gmBlackBoxY;
int gx = ga->next_x;
int gy = ga->next_y;
if (size > 0 && gw > 0 && gh > 0) {
uint8_t* buf = (uint8_t*)malloc(size);
GetGlyphOutlineW(hdc, ch, GGO_GRAY8_BITMAP, &gm, size, buf, &mat);
uint8_t* pixels = (uint8_t*)calloc(gw * gh * 4, 1);
int row_bytes = ((gw + 3) / 4) * 4;
for (int row = 0; row < gh; row++) {
for (int col = 0; col < gw; col++) {
int src_idx = row * row_bytes + col;
if (src_idx < (int)size) {
uint8_t gray = buf[src_idx];
uint8_t alpha = (gray > 200) ? 255 : (gray > 100) ? 200 : (gray > 30) ? 128 : 0;
int idx = (row * gw + col) * 4;
pixels[idx] = 255;
pixels[idx + 1] = 255;
pixels[idx + 2] = 255;
pixels[idx + 3] = alpha;
}
}
}
D3D11_BOX box = {0};
box.left = gx;
box.top = gy;
box.front = 0;
box.right = gx + gw;
box.bottom = gy + gh;
box.back = 1;
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)ga->texture, 0, &box, pixels, gw * 4, 0);
free(buf);
free(pixels);
}
SelectObject(hdc, old);
DeleteObject(hfont);
ReleaseDC(NULL, hdc);
GlyphEntry* e = &g_entries[g_entry_count++];
e->ch = ch;
e->x = gx;
e->y = gy;
e->w = gw > 0 ? gw : ga->cell_w / 2;
e->h = gh > 0 ? gh : ga->cell_h;
e->u0 = (float)gx * ga->u_scale;
e->v0 = (float)gy * ga->v_scale;
e->u1 = (float)(gx + e->w) * ga->u_scale;
e->v1 = (float)(gy + e->h) * ga->v_scale;
e->advance_x = (float)(gm.gmCellIncX > 0 ? gm.gmCellIncX : ga->cell_w / 2);
ga->next_x += ga->cell_w;
*u0 = e->u0;
*v0 = e->v0;
*u1 = e->u1;
*v1 = e->v1;
*advance_x = e->advance_x;
*advance_y = (float)e->h;
return 1;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
#define GLYPH_CELL_W 32
#define GLYPH_CELL_H 32
#define GLYPH_ATLAS_COLS 16
#define GLYPH_ATLAS_ROWS 16
#define GLYPH_ATLAS_SIZE (GLYPH_ATLAS_COLS * GLYPH_CELL_W)
typedef struct {
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* srv;
int atlas_w;
int atlas_h;
int next_x;
int next_y;
int cell_w;
int cell_h;
float u_scale;
float v_scale;
} GlyphAtlas;
int glyph_atlas_init(GlyphAtlas* ga, ID3D11Device* dev);
void glyph_atlas_destroy(GlyphAtlas* ga);
int glyph_atlas_get_or_create(GlyphAtlas* ga, ID3D11Device* dev, ID3D11DeviceContext* ctx, wchar_t ch,
float* u0, float* v0, float* u1, float* v1,
float* advance_x, float* advance_y);
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "uilayer.h"
#include "bitmap_font.h"
int textlayer_init(TextLayer* t, ID3D11Device* dev, BitmapFont* font, UILayer* ui);
void textlayer_destroy(TextLayer* t);
void textlayer_draw(TextLayer* t, ID3D11DeviceContext* ctx,
const char* text, int x, int y,
float r, float g, float b, float a,
float screen_w, float screen_h);
+252
View File
@@ -0,0 +1,252 @@
#include "uilayer.h"
#include <stdlib.h>
#include <string.h>
#include "../Core/logger.h"
#define UI_MAX_VERTS (UI_MAX_QUADS * 4)
#define UI_MAX_IDXS (UI_MAX_QUADS * 6)
typedef struct { float p[3], n[3], uv[2], c[4]; } UIVert;
static UIVert g_verts[UI_MAX_VERTS];
static uint32_t g_indices[UI_MAX_IDXS];
static int g_vi = 0;
static int g_ii = 0;
static UIVert g_text_verts[UI_MAX_VERTS];
static uint32_t g_text_indices[UI_MAX_IDXS];
static int g_tvi = 0;
static int g_tii = 0;
static ID3D11ShaderResourceView* g_text_srv = NULL;
static void screen_to_world(float sx, float sy, float sw, float sh, float z, float* wx, float* wy) {
*wx = sx - sw * 0.5f;
*wy = -(sy - sh * 0.5f);
}
int uilayer_init(UILayer* u, ID3D11Device* dev, float screen_w, float screen_h) {
memset(u, 0, sizeof(*u));
u->screen_w = screen_w;
u->screen_h = screen_h;
u->z_plane = 0.0f;
u->camera = camera_orthographic(screen_w, screen_h, 0.1f, 200.0f);
u->camera.position = (Vec3){0, 0, 100};
u->camera.target = (Vec3){0, 0, 0};
u->camera.dirty = 1;
camera_update(&u->camera);
u->shader = shader_create();
if (!shader_compile(u->shader, dev, NULL, NULL, 0, 0)) {
LOG_ERROR("UILayer: shader compile failed");
return 0;
}
D3D11_BUFFER_DESC bd = {0};
D3D11_SUBRESOURCE_DATA sd = {0};
UIVert* empty = (UIVert*)calloc(UI_MAX_VERTS, sizeof(UIVert));
bd.ByteWidth = UI_MAX_VERTS * sizeof(UIVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
sd.pSysMem = empty;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->vb);
free(empty);
uint32_t* eidx = (uint32_t*)calloc(UI_MAX_IDXS, sizeof(uint32_t));
bd.ByteWidth = UI_MAX_IDXS * sizeof(uint32_t);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
sd.pSysMem = eidx;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->ib);
free(eidx);
UIVert* empty2 = (UIVert*)calloc(UI_MAX_VERTS, sizeof(UIVert));
bd.ByteWidth = UI_MAX_VERTS * sizeof(UIVert);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
sd.pSysMem = empty2;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->text_vb);
free(empty2);
uint32_t* eidx2 = (uint32_t*)calloc(UI_MAX_IDXS, sizeof(uint32_t));
bd.ByteWidth = UI_MAX_IDXS * sizeof(uint32_t);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
sd.pSysMem = eidx2;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &u->text_ib);
free(eidx2);
D3D11_RASTERIZER_DESC rdesc = {0};
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_NONE;
dev->lpVtbl->CreateRasterizerState(dev, &rdesc, &u->rstate);
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
dsdesc.DepthEnable = FALSE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dev->lpVtbl->CreateDepthStencilState(dev, &dsdesc, &u->ds_state);
D3D11_BLEND_DESC bdesc = {0};
bdesc.RenderTarget[0].BlendEnable = TRUE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
dev->lpVtbl->CreateBlendState(dev, &bdesc, &u->text_blend);
D3D11_SAMPLER_DESC sdesc = {0};
sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sdesc.AddressU = sdesc.AddressV = sdesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
dev->lpVtbl->CreateSamplerState(dev, &sdesc, &u->text_sampler);
const char* text_vs_src =
"cbuffer CB:register(b0){float4x4 WVP;};"
"struct VS_IN{float4 pos:POSITION;float3 n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
"struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};"
"PS_IN main(VS_IN i){PS_IN o;o.pos=mul(i.pos,WVP);o.uv=i.uv;o.col=i.col;return o;}";
const char* text_ps_src =
"Texture2D tex:register(t0);SamplerState smp:register(s0);"
"struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};"
"float4 main(PS_IN i):SV_TARGET{float a=tex.Sample(smp,i.uv).a;return float4(i.col.rgb,i.col.a*a);}";
ID3DBlob *vsb = NULL, *psb = NULL;
D3DCompile(text_vs_src, (UINT)strlen(text_vs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vsb, NULL);
D3DCompile(text_ps_src, (UINT)strlen(text_ps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &psb, NULL);
if (vsb && psb) {
dev->lpVtbl->CreateVertexShader(dev, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), NULL, &u->text_vs);
dev->lpVtbl->CreatePixelShader(dev, psb->lpVtbl->GetBufferPointer(psb), psb->lpVtbl->GetBufferSize(psb), NULL, &u->text_ps);
D3D11_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
};
dev->lpVtbl->CreateInputLayout(dev, layout, 4, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), &u->text_layout);
vsb->lpVtbl->Release(vsb);
psb->lpVtbl->Release(psb);
}
LOG_INFO("UILayer: initialized (%.0fx%.0f)", screen_w, screen_h);
return 1;
}
void uilayer_destroy(UILayer* u) {
if (!u) return;
if (u->text_sampler) u->text_sampler->lpVtbl->Release(u->text_sampler);
if (u->text_blend) u->text_blend->lpVtbl->Release(u->text_blend);
if (u->text_layout) u->text_layout->lpVtbl->Release(u->text_layout);
if (u->text_ps) u->text_ps->lpVtbl->Release(u->text_ps);
if (u->text_vs) u->text_vs->lpVtbl->Release(u->text_vs);
if (u->text_ib) u->text_ib->lpVtbl->Release(u->text_ib);
if (u->text_vb) u->text_vb->lpVtbl->Release(u->text_vb);
if (u->ds_state) u->ds_state->lpVtbl->Release(u->ds_state);
if (u->rstate) u->rstate->lpVtbl->Release(u->rstate);
if (u->ib) u->ib->lpVtbl->Release(u->ib);
if (u->vb) u->vb->lpVtbl->Release(u->vb);
if (u->shader) shader_destroy(u->shader);
memset(u, 0, sizeof(*u));
}
void uilayer_begin(UILayer* u) {
(void)u;
g_vi = 0; g_ii = 0;
g_tvi = 0; g_tii = 0;
g_text_srv = NULL;
}
void uilayer_rect(UILayer* u, float x, float y, float w, float h,
float r, float g, float b, float a) {
if (g_vi + 4 > UI_MAX_VERTS) return;
float x0, y0, x1, y1;
screen_to_world(x, y, u->screen_w, u->screen_h, u->z_plane, &x0, &y0);
screen_to_world(x + w, y + h, u->screen_w, u->screen_h, u->z_plane, &x1, &y1);
float z = u->z_plane;
uint32_t base = (uint32_t)g_vi;
g_verts[g_vi] = (UIVert){{x0,y0,z},{0,0,1},{0,0},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x1,y0,z},{0,0,1},{1,0},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x1,y1,z},{0,0,1},{1,1},{r,g,b,a}}; g_vi++;
g_verts[g_vi] = (UIVert){{x0,y1,z},{0,0,1},{0,1},{r,g,b,a}}; g_vi++;
g_indices[g_ii++] = base; g_indices[g_ii++] = base+1; g_indices[g_ii++] = base+2;
g_indices[g_ii++] = base; g_indices[g_ii++] = base+2; g_indices[g_ii++] = base+3;
}
void uilayer_textured_rect(UILayer* u, ID3D11DeviceContext* ctx,
ID3D11ShaderResourceView* srv,
float x, float y, float w, float h,
float u0, float v0, float u1, float v1,
float r, float g, float b, float a) {
(void)ctx;
if (!srv || g_tvi + 4 > UI_MAX_VERTS) return;
float x0, y0, x1, y1;
screen_to_world(x, y, u->screen_w, u->screen_h, u->z_plane, &x0, &y0);
screen_to_world(x + w, y + h, u->screen_w, u->screen_h, u->z_plane, &x1, &y1);
float z = u->z_plane;
uint32_t base = (uint32_t)g_tvi;
g_text_verts[g_tvi] = (UIVert){{x0,y0,z},{0,0,1},{u0,v0},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x1,y0,z},{0,0,1},{u1,v0},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x1,y1,z},{0,0,1},{u1,v1},{r,g,b,a}}; g_tvi++;
g_text_verts[g_tvi] = (UIVert){{x0,y1,z},{0,0,1},{u0,v1},{r,g,b,a}}; g_tvi++;
g_text_indices[g_tii++] = base; g_text_indices[g_tii++] = base+1; g_text_indices[g_tii++] = base+2;
g_text_indices[g_tii++] = base; g_text_indices[g_tii++] = base+2; g_text_indices[g_tii++] = base+3;
g_text_srv = srv;
}
static void flush_batch(ID3D11DeviceContext* ctx, UIVert* verts, uint32_t* indices,
int num_idx, ID3D11Buffer* vb, ID3D11Buffer* ib) {
if (num_idx == 0) return;
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)vb, 0, NULL, verts, 0, 0);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)ib, 0, NULL, indices, 0, 0);
UINT stride = sizeof(UIVert), offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &vb, &stride, &offset);
ctx->lpVtbl->IASetIndexBuffer(ctx, ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->DrawIndexed(ctx, (UINT)num_idx, 0, 0);
}
void uilayer_flush(UILayer* u, ID3D11DeviceContext* ctx) {
if (g_ii == 0) return;
Mat4 view = u->camera.view;
Mat4 proj = u->camera.projection;
Mat4 vp, vp_t;
mat4_multiply(&view, &proj, &vp);
mat4_transpose(&vp, &vp_t);
D3D11_VIEWPORT vport = {0};
vport.Width = u->screen_w; vport.Height = u->screen_h; vport.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
ctx->lpVtbl->RSSetState(ctx, u->rstate);
ctx->lpVtbl->OMSetDepthStencilState(ctx, u->ds_state, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
shader_bind(u->shader, ctx);
shader_set_matrix(u->shader, ctx, (float*)&vp_t);
flush_batch(ctx, g_verts, g_indices, g_ii, u->vb, u->ib);
}
void uilayer_flush_text(UILayer* u, ID3D11DeviceContext* ctx) {
if (g_tii == 0 || !g_text_srv || !u->text_vs || !u->text_ps) return;
Mat4 view = u->camera.view;
Mat4 proj = u->camera.projection;
Mat4 vp, vp_t;
mat4_multiply(&view, &proj, &vp);
mat4_transpose(&vp, &vp_t);
D3D11_VIEWPORT vport = {0};
vport.Width = u->screen_w; vport.Height = u->screen_h; vport.MaxDepth = 1.0f;
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
ctx->lpVtbl->RSSetState(ctx, u->rstate);
ctx->lpVtbl->OMSetDepthStencilState(ctx, u->ds_state, 0);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->lpVtbl->VSSetShader(ctx, u->text_vs, NULL, 0);
ctx->lpVtbl->PSSetShader(ctx, u->text_ps, NULL, 0);
ctx->lpVtbl->IASetInputLayout(ctx, u->text_layout);
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)u->shader->cb, 0, NULL, &vp_t, 0, 0);
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &u->shader->cb);
float bf[4] = {0};
ctx->lpVtbl->OMSetBlendState(ctx, u->text_blend, bf, 0xFFFFFFFF);
ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_text_srv);
ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &u->text_sampler);
flush_batch(ctx, g_text_verts, g_text_indices, g_tii, u->text_vb, u->text_ib);
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include "../Rendering/camera.h"
#include "../Rendering/shader.h"
#include "../Rendering/mesh.h"
#include "../Rendering/graphics_device.h"
#include "../ASM/math_c_fallback.h"
#define UI_MAX_QUADS 8192
typedef struct {
Camera camera;
Shader* shader;
ID3D11Buffer* vb;
ID3D11Buffer* ib;
ID3D11Buffer* text_vb;
ID3D11Buffer* text_ib;
ID3D11RasterizerState* rstate;
ID3D11DepthStencilState* ds_state;
ID3D11VertexShader* text_vs;
ID3D11PixelShader* text_ps;
ID3D11InputLayout* text_layout;
ID3D11BlendState* text_blend;
ID3D11SamplerState* text_sampler;
float screen_w;
float screen_h;
float z_plane;
} UILayer;
int uilayer_init(UILayer* u, ID3D11Device* dev, float screen_w, float screen_h);
void uilayer_destroy(UILayer* u);
void uilayer_begin(UILayer* u);
void uilayer_rect(UILayer* u,
float x, float y, float w, float h,
float r, float g, float b, float a);
void uilayer_textured_rect(UILayer* u, ID3D11DeviceContext* ctx,
ID3D11ShaderResourceView* srv,
float x, float y, float w, float h,
float u0, float v0, float u1, float v1,
float r, float g, float b, float a);
void uilayer_flush(UILayer* u, ID3D11DeviceContext* ctx);
void uilayer_flush_text(UILayer* u, ID3D11DeviceContext* ctx);
+124
View File
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{B5C5B5B5-5B5B-5B5B-5B5B-5B5B5B5B5B5B}</ProjectGuid>
<RootNamespace>Engine</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdc17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
</ClCompile>
<Lib>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdc17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
</ClCompile>
<Lib>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<MASM Include="ASM\math.asm" />
<MASM Include="ASM\memory.asm" />
<MASM Include="ASM\string_ops.asm" />
<MASM Include="ASM\profiling.asm" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Core\engine.c" />
<ClCompile Include="Core\logger.c" />
<ClCompile Include="Core\timer.c" />
<ClCompile Include="Window\window.c" />
<ClCompile Include="Rendering\graphics_device.c" />
<ClCompile Include="Rendering\renderer.c" />
<ClCompile Include="Rendering\shader.c" />
<ClCompile Include="Rendering\mesh.c" />
<ClCompile Include="Rendering\texture.c" />
<ClCompile Include="Rendering\camera.c" />
<ClCompile Include="ECS\world.c" />
<ClCompile Include="Input\input.c" />
<ClCompile Include="Physics\physics.c" />
<ClCompile Include="Audio\audio.c" />
<ClCompile Include="UI\ui.c" />
<ClCompile Include="Scripting\lua_engine.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Core\engine.h" />
<ClInclude Include="Core\logger.h" />
<ClInclude Include="Core\timer.h" />
<ClInclude Include="Window\window.h" />
<ClInclude Include="include\engine_api.h" />
<ClInclude Include="include\asm_macros.inc" />
<ClInclude Include="Rendering\graphics_device.h" />
<ClInclude Include="Rendering\renderer.h" />
<ClInclude Include="Rendering\shader.h" />
<ClInclude Include="Rendering\mesh.h" />
<ClInclude Include="Rendering\texture.h" />
<ClInclude Include="Rendering\camera.h" />
<ClInclude Include="ECS\world.h" />
<ClInclude Include="Input\input.h" />
<ClInclude Include="Physics\physics.h" />
<ClInclude Include="Audio\audio.h" />
<ClInclude Include="UI\ui.h" />
<ClInclude Include="Scripting\lua_engine.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
+137
View File
@@ -0,0 +1,137 @@
#include "input.h"
#include <stdlib.h>
#include <string.h>
static float normalize_trigger(BYTE value) {
return value / 255.0f;
}
static float normalize_axis(SHORT value) {
if (value > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
return (value - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) / (32767.0f - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
} else if (value < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
return (value + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) / (32767.0f - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
}
return 0.0f;
}
Input* input_create(void) {
Input* input = (Input*)calloc(1, sizeof(Input));
input->deadzone = 0.2f;
return input;
}
void input_destroy(Input* input) {
free(input);
}
void input_update(Input* input) {
memcpy(input->key_prev, input->key_states, sizeof(int) * MAX_KEYS);
memcpy(input->mouse_prev, input->mouse_buttons, sizeof(int) * 3);
input->mouse_dx = 0;
input->mouse_dy = 0;
input->mouse_scroll = 0;
memcpy(&input->gamepad_prev, &input->gamepad_state, sizeof(XINPUT_STATE));
input->gamepad_connected = (XInputGetState(0, &input->gamepad_state) == ERROR_SUCCESS);
}
void input_process_key(Input* input, int key, int down) {
if (key >= 0 && key < MAX_KEYS) {
input->key_states[key] = down;
}
}
void input_process_mouse_move(Input* input, int x, int y) {
input->mouse_dx = x - input->mouse_x;
input->mouse_dy = y - input->mouse_y;
input->mouse_x = x;
input->mouse_y = y;
}
void input_process_mouse_button(Input* input, int button, int down) {
if (button >= 0 && button < 3) {
input->mouse_buttons[button] = down;
}
}
void input_process_mouse_wheel(Input* input, int delta) {
input->mouse_scroll += delta;
}
int input_key_down(Input* input, int key) {
return (key >= 0 && key < MAX_KEYS) ? input->key_states[key] : 0;
}
int input_key_pressed(Input* input, int key) {
return (key >= 0 && key < MAX_KEYS) ? (input->key_states[key] && !input->key_prev[key]) : 0;
}
int input_key_released(Input* input, int key) {
return (key >= 0 && key < MAX_KEYS) ? (!input->key_states[key] && input->key_prev[key]) : 0;
}
int input_mouse_button(Input* input, int button) {
return (button >= 0 && button < 3) ? input->mouse_buttons[button] : 0;
}
int input_mouse_button_pressed(Input* input, int button) {
return (button >= 0 && button < 3) ? (input->mouse_buttons[button] && !input->mouse_prev[button]) : 0;
}
void input_get_mouse_pos(Input* input, int* x, int* y) {
if (x) *x = input->mouse_x;
if (y) *y = input->mouse_y;
}
void input_get_mouse_delta(Input* input, int* dx, int* dy) {
if (dx) *dx = input->mouse_dx;
if (dy) *dy = input->mouse_dy;
}
int input_get_mouse_scroll(Input* input) {
return input->mouse_scroll;
}
int input_gamepad_connected(Input* input) {
return input->gamepad_connected;
}
float input_gamepad_axis_lx(Input* input) {
float v = normalize_axis(input->gamepad_state.Gamepad.sThumbLX);
return fabsf(v) < input->deadzone ? 0.0f : v;
}
float input_gamepad_axis_ly(Input* input) {
float v = normalize_axis(input->gamepad_state.Gamepad.sThumbLY);
return fabsf(v) < input->deadzone ? 0.0f : v;
}
float input_gamepad_axis_rx(Input* input) {
float v = normalize_axis(input->gamepad_state.Gamepad.sThumbRX);
return fabsf(v) < input->deadzone ? 0.0f : v;
}
float input_gamepad_axis_ry(Input* input) {
float v = normalize_axis(input->gamepad_state.Gamepad.sThumbRY);
return fabsf(v) < input->deadzone ? 0.0f : v;
}
float input_gamepad_trigger_l(Input* input) {
return normalize_trigger(input->gamepad_state.Gamepad.bLeftTrigger);
}
float input_gamepad_trigger_r(Input* input) {
return normalize_trigger(input->gamepad_state.Gamepad.bRightTrigger);
}
int input_gamepad_button(Input* input, uint16_t button) {
return (input->gamepad_state.Gamepad.wButtons & button) != 0;
}
int input_gamepad_button_pressed(Input* input, uint16_t button) {
return (input->gamepad_state.Gamepad.wButtons & button) != 0 &&
(input->gamepad_prev.Gamepad.wButtons & button) == 0;
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
// ============================================================================
// input.h - 输入管理 (键盘/鼠标/手柄)
// ============================================================================
#include <Windows.h>
#include <Xinput.h>
#include <stdint.h>
#pragma comment(lib, "xinput.lib")
// 键盘状态
#define MAX_KEYS 256
// 鼠标按钮
#define MOUSE_LEFT 0
#define MOUSE_RIGHT 1
#define MOUSE_MIDDLE 2
// 手柄按钮
#define GAMEPAD_A XINPUT_GAMEPAD_A
#define GAMEPAD_B XINPUT_GAMEPAD_B
#define GAMEPAD_X XINPUT_GAMEPAD_X
#define GAMEPAD_Y XINPUT_GAMEPAD_Y
#define GAMEPAD_START XINPUT_GAMEPAD_START
#define GAMEPAD_BACK XINPUT_GAMEPAD_BACK
#define GAMEPAD_LB XINPUT_GAMEPAD_LEFT_SHOULDER
#define GAMEPAD_RB XINPUT_GAMEPAD_RIGHT_SHOULDER
#define GAMEPAD_LTHUMB XINPUT_GAMEPAD_LEFT_THUMB
#define GAMEPAD_RTHUMB XINPUT_GAMEPAD_RIGHT_THUMB
#define GAMEPAD_UP XINPUT_GAMEPAD_DPAD_UP
#define GAMEPAD_DOWN XINPUT_GAMEPAD_DPAD_DOWN
#define GAMEPAD_LEFT XINPUT_GAMEPAD_DPAD_LEFT
#define GAMEPAD_RIGHT XINPUT_GAMEPAD_DPAD_RIGHT
typedef struct {
int key_states[MAX_KEYS];
int key_prev[MAX_KEYS];
int mouse_x, mouse_y;
int mouse_dx, mouse_dy;
int mouse_scroll;
int mouse_buttons[3];
int mouse_prev[3];
XINPUT_STATE gamepad_state;
XINPUT_STATE gamepad_prev;
int gamepad_connected;
float deadzone;
} Input;
// 创建/销毁
Input* input_create(void);
void input_destroy(Input* input);
// 更新 (每帧调用)
void input_update(Input* input);
// Win32 消息处理
void input_process_key(Input* input, int key, int down);
void input_process_mouse_move(Input* input, int x, int y);
void input_process_mouse_button(Input* input, int button, int down);
void input_process_mouse_wheel(Input* input, int delta);
// 键盘查询
int input_key_down(Input* input, int key);
int input_key_pressed(Input* input, int key);
int input_key_released(Input* input, int key);
// 鼠标查询
int input_mouse_button(Input* input, int button);
int input_mouse_button_pressed(Input* input, int button);
void input_get_mouse_pos(Input* input, int* x, int* y);
void input_get_mouse_delta(Input* input, int* dx, int* dy);
int input_get_mouse_scroll(Input* input);
// 手柄查询
int input_gamepad_connected(Input* input);
float input_gamepad_axis_lx(Input* input);
float input_gamepad_axis_ly(Input* input);
float input_gamepad_axis_rx(Input* input);
float input_gamepad_axis_ry(Input* input);
float input_gamepad_trigger_l(Input* input);
float input_gamepad_trigger_r(Input* input);
int input_gamepad_button(Input* input, uint16_t button);
int input_gamepad_button_pressed(Input* input, uint16_t button);
+8
View File
@@ -0,0 +1,8 @@
// math_impl.c - 数学函数实现 (C fallback)
// 当 MASM 不可用时使用
#include "math_c_fallback.h"
// 由于函数是 static inline,它们应该被内联
// 但如果编译器没有内联,这些函数将提供实现
// 这个文件确保链接器能找到符号
+202
View File
@@ -0,0 +1,202 @@
#include "physics.h"
#include <stdlib.h>
#include <math.h>
#include <float.h>
PhysicsWorld* physics_create(void) {
PhysicsWorld* w = (PhysicsWorld*)calloc(1, sizeof(PhysicsWorld));
w->gravity_enabled = 1;
w->gravity = (Vec3){0, -9.81f, 0};
return w;
}
void physics_destroy(PhysicsWorld* world) {
free(world);
}
uint32_t physics_add_aabb(PhysicsWorld* world, uint32_t entity, Vec3 min, Vec3 max) {
uint32_t idx = world->collider_count++;
Collider* c = &world->colliders[idx];
c->entity_id = entity;
c->type = COLLIDER_AABB;
c->aabb.min = min;
c->aabb.max = max;
c->is_trigger = 0;
c->is_static = 0;
return idx;
}
uint32_t physics_add_sphere(PhysicsWorld* world, uint32_t entity, Vec3 center, float radius) {
uint32_t idx = world->collider_count++;
Collider* c = &world->colliders[idx];
c->entity_id = entity;
c->type = COLLIDER_SPHERE;
c->sphere.center = center;
c->sphere.radius = radius;
return idx;
}
uint32_t physics_add_plane(PhysicsWorld* world, uint32_t entity, Vec3 normal, float distance) {
uint32_t idx = world->collider_count++;
Collider* c = &world->colliders[idx];
c->entity_id = entity;
c->type = COLLIDER_PLANE;
vec3_normalize(&normal, &c->plane.normal);
c->plane.distance = distance;
c->is_static = 1;
return idx;
}
void physics_remove_collider(PhysicsWorld* world, uint32_t index) {
if (index < world->collider_count) {
world->colliders[index] = world->colliders[--world->collider_count];
}
}
void physics_update_collider(PhysicsWorld* world, uint32_t index, Vec3 position) {
Collider* c = &world->colliders[index];
if (c->type == COLLIDER_SPHERE) {
c->sphere.center = position;
}
}
static int aabb_vs_aabb(const Collider* a, const Collider* b, Vec3* normal, float* depth) {
Vec3 diff;
Vec3 centerA = {(a->aabb.min.x + a->aabb.max.x) * 0.5f, (a->aabb.min.y + a->aabb.max.y) * 0.5f, (a->aabb.min.z + a->aabb.max.z) * 0.5f};
Vec3 centerB = {(b->aabb.min.x + b->aabb.max.x) * 0.5f, (b->aabb.min.y + b->aabb.max.y) * 0.5f, (b->aabb.min.z + b->aabb.max.z) * 0.5f};
vec3_sub(&centerA, &centerB, &diff);
Vec3 half_a, half_b, size;
vec3_sub(&a->aabb.max, &a->aabb.min, &half_a);
vec3_scale(&half_a, 0.5f, &half_a);
vec3_sub(&b->aabb.max, &b->aabb.min, &half_b);
vec3_scale(&half_b, 0.5f, &half_b);
float dx = fabsf(diff.x) - (half_a.x + half_b.x);
float dy = fabsf(diff.y) - (half_a.y + half_b.y);
float dz = fabsf(diff.z) - (half_a.z + half_b.z);
if (dx < 0 && dy < 0 && dz < 0) {
*depth = -fmaxf(fmaxf(dx, dy), dz);
if (dx > dy && dx > dz) normal = &(Vec3){copysignf(1, diff.x), 0, 0};
else if (dy > dz) { normal->x = 0; normal->y = copysignf(1, diff.y); normal->z = 0; }
else { normal->x = 0; normal->y = 0; normal->z = copysignf(1, diff.z); }
return 1;
}
return 0;
}
static int sphere_vs_sphere(const Collider* a, const Collider* b, Vec3* normal, float* depth) {
Vec3 diff;
vec3_sub(&a->sphere.center, &b->sphere.center, &diff);
float dist = vec3_length(&diff);
float radii = a->sphere.radius + b->sphere.radius;
if (dist < radii) {
*depth = radii - dist;
if (dist > 0.0001f) {
vec3_normalize(&diff, normal);
} else {
*normal = (Vec3){0, 1, 0};
}
return 1;
}
return 0;
}
static int sphere_vs_aabb(const Collider* sphere, const Collider* aabb, Vec3* normal, float* depth) {
Vec3 closest;
closest.x = fmaxf(aabb->aabb.min.x, fminf(sphere->sphere.center.x, aabb->aabb.max.x));
closest.y = fmaxf(aabb->aabb.min.y, fminf(sphere->sphere.center.y, aabb->aabb.max.y));
closest.z = fmaxf(aabb->aabb.min.z, fminf(sphere->sphere.center.z, aabb->aabb.max.z));
Vec3 diff;
vec3_sub(&sphere->sphere.center, &closest, &diff);
float dist_sq = vec3_dot(&diff, &diff);
if (dist_sq < sphere->sphere.radius * sphere->sphere.radius) {
float dist = sqrtf(dist_sq);
*depth = sphere->sphere.radius - dist;
if (dist > 0.0001f) {
vec3_normalize(&diff, normal);
} else {
*normal = (Vec3){0, 1, 0};
}
return 1;
}
return 0;
}
static int sphere_vs_plane(const Collider* sphere, const Collider* plane, Vec3* normal, float* depth) {
float dist = vec3_dot(&sphere->sphere.center, &plane->plane.normal) - plane->plane.distance;
if (dist < sphere->sphere.radius) {
*depth = sphere->sphere.radius - dist;
*normal = plane->plane.normal;
return 1;
}
return 0;
}
int physics_check_collision(const Collider* a, const Collider* b, Vec3* normal, float* depth) {
if (a->type == COLLIDER_AABB && b->type == COLLIDER_AABB)
return aabb_vs_aabb(a, b, normal, depth);
if (a->type == COLLIDER_SPHERE && b->type == COLLIDER_SPHERE)
return sphere_vs_sphere(a, b, normal, depth);
if (a->type == COLLIDER_SPHERE && b->type == COLLIDER_AABB)
return sphere_vs_aabb(a, b, normal, depth);
if (a->type == COLLIDER_AABB && b->type == COLLIDER_SPHERE) {
int hit = sphere_vs_aabb(b, a, normal, depth);
if (hit) { normal->x = -normal->x; normal->y = -normal->y; normal->z = -normal->z; }
return hit;
}
if (a->type == COLLIDER_SPHERE && b->type == COLLIDER_PLANE)
return sphere_vs_plane(a, b, normal, depth);
if (a->type == COLLIDER_PLANE && b->type == COLLIDER_SPHERE) {
int hit = sphere_vs_plane(b, a, normal, depth);
if (hit) { normal->x = -normal->x; normal->y = -normal->y; normal->z = -normal->z; }
return hit;
}
return 0;
}
int physics_raycast(PhysicsWorld* world, Vec3 origin, Vec3 direction, float max_dist,
uint32_t* hit_entity, Vec3* hit_point, Vec3* hit_normal) {
vec3_normalize(&direction, &direction);
float closest_t = max_dist;
int hit = 0;
for (uint32_t i = 0; i < world->collider_count; i++) {
Collider* c = &world->colliders[i];
if (c->type == COLLIDER_SPHERE) {
Vec3 oc;
vec3_sub(&origin, &c->sphere.center, &oc);
float a = vec3_dot(&direction, &direction);
float b = 2.0f * vec3_dot(&oc, &direction);
float cc = vec3_dot(&oc, &oc) - c->sphere.radius * c->sphere.radius;
float disc = b * b - 4 * a * cc;
if (disc >= 0) {
float t = (-b - sqrtf(disc)) / (2 * a);
if (t > 0 && t < closest_t) {
closest_t = t;
*hit_entity = c->entity_id;
Vec3 scaled;
vec3_scale(&direction, t, &scaled);
vec3_add(&origin, &scaled, hit_point);
vec3_sub(hit_point, &c->sphere.center, hit_normal);
vec3_normalize(hit_normal, hit_normal);
hit = 1;
}
}
}
}
return hit;
}
void physics_step(PhysicsWorld* world, float dt) {
(void)world;
(void)dt;
}
void physics_set_gravity(PhysicsWorld* world, Vec3 gravity) {
world->gravity = gravity;
}
+68
View File
@@ -0,0 +1,68 @@
#pragma once
// ============================================================================
// physics.h - 物理引擎 (碰撞检测, 调用ASM数学)
// ============================================================================
#include "../include/engine_api.h"
#include "../ASM/math_c_fallback.h"
#include <stdint.h>
#define MAX_COLLIDERS 1024
typedef enum {
COLLIDER_AABB,
COLLIDER_SPHERE,
COLLIDER_PLANE,
} ColliderType;
typedef struct {
uint32_t entity_id;
ColliderType type;
union {
struct { Vec3 min; Vec3 max; } aabb;
struct { Vec3 center; float radius; } sphere;
struct { Vec3 normal; float distance; } plane;
};
int is_trigger;
int is_static;
} Collider;
typedef struct {
Vec3 velocity;
Vec3 acceleration;
float mass;
float restitution;
float friction;
int is_kinematic;
} RigidBody;
typedef struct {
Collider colliders[MAX_COLLIDERS];
uint32_t collider_count;
int gravity_enabled;
Vec3 gravity;
} PhysicsWorld;
// 碰撞回调
typedef void (*CollisionCallback)(uint32_t entity_a, uint32_t entity_b, Vec3 normal, float depth);
// 创建/销毁
PhysicsWorld* physics_create(void);
void physics_destroy(PhysicsWorld* world);
// 碰撞体
uint32_t physics_add_aabb(PhysicsWorld* world, uint32_t entity, Vec3 min, Vec3 max);
uint32_t physics_add_sphere(PhysicsWorld* world, uint32_t entity, Vec3 center, float radius);
uint32_t physics_add_plane(PhysicsWorld* world, uint32_t entity, Vec3 normal, float distance);
void physics_remove_collider(PhysicsWorld* world, uint32_t index);
void physics_update_collider(PhysicsWorld* world, uint32_t index, Vec3 position);
// 碰撞检测
int physics_check_collision(const Collider* a, const Collider* b, Vec3* normal, float* depth);
int physics_raycast(PhysicsWorld* world, Vec3 origin, Vec3 direction, float max_dist,
uint32_t* hit_entity, Vec3* hit_point, Vec3* hit_normal);
// 模拟
void physics_step(PhysicsWorld* world, float dt);
void physics_set_gravity(PhysicsWorld* world, Vec3 gravity);
+135
View File
@@ -0,0 +1,135 @@
#include "camera.h"
#include <math.h>
#include <string.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
Camera camera_perspective(float fov_y, float aspect, float near_z, float far_z) {
Camera cam = {0};
cam.type = CAMERA_PERSPECTIVE;
cam.position = (Vec3){0, 0, -5};
cam.target = (Vec3){0, 0, 0};
cam.up = (Vec3){0, 1, 0};
cam.fov_y = fov_y;
cam.aspect = aspect;
cam.near_z = near_z;
cam.far_z = far_z;
cam.dirty = 1;
return cam;
}
Camera camera_orthographic(float width, float height, float near_z, float far_z) {
Camera cam = {0};
cam.type = CAMERA_ORTHOGRAPHIC;
cam.position = (Vec3){0, 0, -5};
cam.target = (Vec3){0, 0, 0};
cam.up = (Vec3){0, 1, 0};
cam.ortho_width = width;
cam.ortho_height = height;
cam.near_z = near_z;
cam.far_z = far_z;
cam.dirty = 1;
return cam;
}
void camera_update(Camera* camera) {
if (!camera->dirty) return;
mat4_lookat(&camera->position, &camera->target, &camera->up, &camera->view);
if (camera->type == CAMERA_PERSPECTIVE) {
mat4_perspective(camera->fov_y, camera->aspect, camera->near_z, camera->far_z, &camera->projection);
} else {
mat4_orthographic(camera->ortho_width, camera->ortho_height, camera->near_z, camera->far_z, &camera->projection);
}
camera->dirty = 0;
}
const Mat4* camera_get_view(Camera* camera) {
camera_update(camera);
return &camera->view;
}
const Mat4* camera_get_projection(Camera* camera) {
camera_update(camera);
return &camera->projection;
}
void camera_move_forward(Camera* camera, float distance) {
Vec3 dir;
vec3_sub(&camera->target, &camera->position, &dir);
vec3_normalize(&dir, &dir);
Vec3 move;
vec3_scale(&dir, distance, &move);
vec3_add(&camera->position, &move, &camera->position);
vec3_add(&camera->target, &move, &camera->target);
camera->dirty = 1;
}
void camera_move_right(Camera* camera, float distance) {
Vec3 forward, right;
vec3_sub(&camera->target, &camera->position, &forward);
vec3_normalize(&forward, &forward);
vec3_cross(&forward, &camera->up, &right);
vec3_normalize(&right, &right);
Vec3 move;
vec3_scale(&right, distance, &move);
vec3_add(&camera->position, &move, &camera->position);
vec3_add(&camera->target, &move, &camera->target);
camera->dirty = 1;
}
void camera_move_up(Camera* camera, float distance) {
Vec3 move;
vec3_scale(&camera->up, distance, &move);
vec3_add(&camera->position, &move, &camera->position);
vec3_add(&camera->target, &move, &camera->target);
camera->dirty = 1;
}
void camera_rotate_yaw(Camera* camera, float angle) {
Vec3 forward;
vec3_sub(&camera->target, &camera->position, &forward);
float cs = cosf(angle), sn = sinf(angle);
Vec3 right;
vec3_cross(&forward, &camera->up, &right);
vec3_normalize(&right, &right);
Vec3 new_forward = {
forward.x * cs + right.x * sn,
forward.y * cs + right.y * sn,
forward.z * cs + right.z * sn,
};
vec3_add(&camera->position, &new_forward, &camera->target);
camera->dirty = 1;
}
void camera_rotate_pitch(Camera* camera, float angle) {
Vec3 forward;
vec3_sub(&camera->target, &camera->position, &forward);
Vec3 right;
vec3_cross(&forward, &camera->up, &right);
vec3_normalize(&right, &right);
float cs = cosf(angle), sn = sinf(angle);
Vec3 new_forward = {
forward.x * cs + camera->up.x * sn,
forward.y * cs + camera->up.y * sn,
forward.z * cs + camera->up.z * sn,
};
Vec3 new_up;
vec3_cross(&right, &new_forward, &new_up);
camera->up = new_up;
vec3_add(&camera->position, &new_forward, &camera->target);
camera->dirty = 1;
}
void camera_look_at(Camera* camera, Vec3 target) {
camera->target = target;
camera->dirty = 1;
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
// ============================================================================
// camera.h - 摄像机
// ============================================================================
#include "../include/engine_api.h"
#include "../ASM/math_c_fallback.h"
typedef enum {
CAMERA_PERSPECTIVE,
CAMERA_ORTHOGRAPHIC,
} CameraType;
typedef struct {
CameraType type;
Vec3 position;
Vec3 target;
Vec3 up;
float fov_y;
float aspect;
float near_z;
float far_z;
float ortho_width;
float ortho_height;
Mat4 view;
Mat4 projection;
int dirty;
} Camera;
// 创建默认透视摄像机
Camera camera_perspective(float fov_y, float aspect, float near_z, float far_z);
// 创建正交摄像机
Camera camera_orthographic(float width, float height, float near_z, float far_z);
// 更新矩阵
void camera_update(Camera* camera);
// 获取矩阵
const Mat4* camera_get_view(Camera* camera);
const Mat4* camera_get_projection(Camera* camera);
// 移动
void camera_move_forward(Camera* camera, float distance);
void camera_move_right(Camera* camera, float distance);
void camera_move_up(Camera* camera, float distance);
// 旋转
void camera_rotate_yaw(Camera* camera, float angle);
void camera_rotate_pitch(Camera* camera, float angle);
// 设置目标
void camera_look_at(Camera* camera, Vec3 target);
+98
View File
@@ -0,0 +1,98 @@
#include "graphics_device.h"
#include <stdlib.h>
#include <string.h>
GraphicsDevice* graphics_device_create(void) {
return (GraphicsDevice*)calloc(1, sizeof(GraphicsDevice));
}
void graphics_device_destroy(GraphicsDevice* d) {
if (!d) return;
if (d->depth_stencil) d->depth_stencil->lpVtbl->Release(d->depth_stencil);
if (d->depth_texture) d->depth_texture->lpVtbl->Release(d->depth_texture);
if (d->render_target) d->render_target->lpVtbl->Release(d->render_target);
if (d->swap_chain) d->swap_chain->lpVtbl->Release(d->swap_chain);
if (d->context) d->context->lpVtbl->Release(d->context);
if (d->device) d->device->lpVtbl->Release(d->device);
free(d);
}
static int create_depth_stencil(GraphicsDevice* d, uint32_t w, uint32_t h) {
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = w; desc.Height = h;
desc.MipLevels = 1; desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
HRESULT hr = d->device->lpVtbl->CreateTexture2D(d->device, &desc, NULL, &d->depth_texture);
if (FAILED(hr)) return 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsv = {0};
dsv.Format = desc.Format;
dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
hr = d->device->lpVtbl->CreateDepthStencilView(d->device, (ID3D11Resource*)d->depth_texture, &dsv, &d->depth_stencil);
return SUCCEEDED(hr);
}
int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h, int vsync) {
d->width = w; d->height = h; d->vsync = vsync;
DXGI_SWAP_CHAIN_DESC scd = {0};
scd.BufferCount = 1;
scd.BufferDesc.Width = w;
scd.BufferDesc.Height = h;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferDesc.RefreshRate.Numerator = 60;
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = (HWND)hwnd;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D_FEATURE_LEVEL levels[] = {D3D_FEATURE_LEVEL_11_0};
UINT flags = 0;
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, 1, D3D11_SDK_VERSION, &scd, &d->swap_chain, &d->device, NULL, &d->context);
if (FAILED(hr)) return 0;
ID3D11Texture2D* back_buffer = NULL;
d->swap_chain->lpVtbl->GetBuffer(d->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back_buffer);
d->device->lpVtbl->CreateRenderTargetView(d->device, (ID3D11Resource*)back_buffer, NULL, &d->render_target);
if (back_buffer) back_buffer->lpVtbl->Release(back_buffer);
create_depth_stencil(d, w, h);
d->context->lpVtbl->OMSetRenderTargets(d->context, 1, &d->render_target, d->depth_stencil);
D3D11_VIEWPORT vp = {0};
vp.Width = (float)w; vp.Height = (float)h;
vp.MaxDepth = 1.0f;
d->context->lpVtbl->RSSetViewports(d->context, 1, &vp);
return 1;
}
void graphics_device_resize(GraphicsDevice* d, uint32_t w, uint32_t h) {
if (w == 0 || h == 0) return;
d->context->lpVtbl->OMSetRenderTargets(d->context, 0, NULL, NULL);
if (d->render_target) { d->render_target->lpVtbl->Release(d->render_target); d->render_target = NULL; }
if (d->depth_stencil) { d->depth_stencil->lpVtbl->Release(d->depth_stencil); d->depth_stencil = NULL; }
if (d->depth_texture) { d->depth_texture->lpVtbl->Release(d->depth_texture); d->depth_texture = NULL; }
d->swap_chain->lpVtbl->ResizeBuffers(d->swap_chain, 0, w, h, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D* back_buffer = NULL;
d->swap_chain->lpVtbl->GetBuffer(d->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back_buffer);
d->device->lpVtbl->CreateRenderTargetView(d->device, (ID3D11Resource*)back_buffer, NULL, &d->render_target);
if (back_buffer) back_buffer->lpVtbl->Release(back_buffer);
create_depth_stencil(d, w, h);
d->context->lpVtbl->OMSetRenderTargets(d->context, 1, &d->render_target, d->depth_stencil);
D3D11_VIEWPORT vp = {0};
vp.Width = (float)w; vp.Height = (float)h; vp.MaxDepth = 1.0f;
d->context->lpVtbl->RSSetViewports(d->context, 1, &vp);
d->width = w; d->height = h;
}
void graphics_device_clear(GraphicsDevice* d, float r, float g, float b, float a) {
float color[4] = {r, g, b, a};
d->context->lpVtbl->ClearRenderTargetView(d->context, d->render_target, color);
d->context->lpVtbl->ClearDepthStencilView(d->context, d->depth_stencil, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
void graphics_device_present(GraphicsDevice* d) {
d->swap_chain->lpVtbl->Present(d->swap_chain, d->vsync ? 1 : 0, 0);
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <d3d11.h>
#include <dxgi.h>
#include <stdint.h>
typedef struct {
ID3D11Device* device;
ID3D11DeviceContext* context;
IDXGISwapChain* swap_chain;
ID3D11RenderTargetView* render_target;
ID3D11DepthStencilView* depth_stencil;
ID3D11Texture2D* depth_texture;
uint32_t width;
uint32_t height;
int vsync;
} GraphicsDevice;
GraphicsDevice* graphics_device_create(void);
void graphics_device_destroy(GraphicsDevice* d);
int graphics_device_init(GraphicsDevice* d, void* hwnd, uint32_t w, uint32_t h, int vsync);
void graphics_device_resize(GraphicsDevice* d, uint32_t w, uint32_t h);
void graphics_device_clear(GraphicsDevice* d, float r, float g, float b, float a);
void graphics_device_present(GraphicsDevice* d);
+110
View File
@@ -0,0 +1,110 @@
#include "mesh.h"
#include <stdlib.h>
#include <math.h>
#ifndef MATH_ASM_AVAILABLE
#include "../ASM/math_c_fallback.h"
#endif
#define POS(n,x,y,z,nx,ny,nz,u,v,r,g,b,a) {x,y,z, nx,ny,nz, u,v, r,g,b,a}
static Mesh* create_mesh(ID3D11Device* dev, const void* verts, uint32_t vc, const uint32_t* idx, uint32_t ic, uint32_t stride) {
Mesh* m = (Mesh*)calloc(1, sizeof(Mesh));
m->stride = stride; m->vcount = vc; m->icount = ic;
D3D11_BUFFER_DESC bd = {0};
D3D11_SUBRESOURCE_DATA sd = {0};
bd.ByteWidth = stride * vc; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
sd.pSysMem = verts;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &m->vb);
if (idx && ic > 0) {
bd.ByteWidth = sizeof(uint32_t) * ic; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
sd.pSysMem = idx;
dev->lpVtbl->CreateBuffer(dev, &bd, &sd, &m->ib);
}
return m;
}
void mesh_destroy(Mesh* m) {
if (!m) return;
if (m->ib) m->ib->lpVtbl->Release(m->ib);
if (m->vb) m->vb->lpVtbl->Release(m->vb);
free(m);
}
void mesh_draw(Mesh* m, ID3D11DeviceContext* ctx) {
UINT stride = m->stride, offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &m->vb, &stride, &offset);
if (m->ib) {
ctx->lpVtbl->IASetIndexBuffer(ctx, m->ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->DrawIndexed(ctx, m->icount, 0, 0);
} else {
ctx->lpVtbl->Draw(ctx, m->vcount, 0);
}
}
Mesh* mesh_create_cube(ID3D11Device* dev) {
typedef struct { float p[3], n[3], uv[2], c[4]; } V;
V v[24] = {
POS(0,-.5f,-.5f,-.5f, 0,0,-1, 0,1, 1,1,1,1), POS(1, .5f,-.5f,-.5f, 0,0,-1, 1,1, 1,1,1,1),
POS(2, .5f, .5f,-.5f, 0,0,-1, 1,0, 1,1,1,1), POS(3,-.5f, .5f,-.5f, 0,0,-1, 0,0, 1,1,1,1),
POS(4, .5f,-.5f, .5f, 0,0, 1, 0,1, 1,1,1,1), POS(5,-.5f,-.5f, .5f, 0,0, 1, 1,1, 1,1,1,1),
POS(6,-.5f, .5f, .5f, 0,0, 1, 1,0, 1,1,1,1), POS(7, .5f, .5f, .5f, 0,0, 1, 0,0, 1,1,1,1),
POS(8,-.5f, .5f,-.5f, 0,1, 0, 0,1, 1,1,1,1), POS(9, .5f, .5f,-.5f, 0,1, 0, 1,1, 1,1,1,1),
POS(10,.5f, .5f, .5f, 0,1, 0, 1,0, 1,1,1,1), POS(11,-.5f, .5f, .5f, 0,1, 0, 0,0, 1,1,1,1),
POS(12,-.5f,-.5f, .5f, 0,-1,0, 0,1, 1,1,1,1), POS(13,.5f,-.5f, .5f, 0,-1,0, 1,1, 1,1,1,1),
POS(14,.5f,-.5f,-.5f, 0,-1,0, 1,0, 1,1,1,1), POS(15,-.5f,-.5f,-.5f, 0,-1,0, 0,0, 1,1,1,1),
POS(16,.5f,-.5f,-.5f, 1,0, 0, 0,1, 1,1,1,1), POS(17,.5f,-.5f, .5f, 1,0, 0, 1,1, 1,1,1,1),
POS(18,.5f, .5f, .5f, 1,0, 0, 1,0, 1,1,1,1), POS(19,.5f, .5f,-.5f, 1,0, 0, 0,0, 1,1,1,1),
POS(20,-.5f,-.5f, .5f, -1,0,0, 0,1, 1,1,1,1), POS(21,-.5f,-.5f,-.5f, -1,0,0, 1,1, 1,1,1,1),
POS(22,-.5f, .5f,-.5f, -1,0,0, 1,0, 1,1,1,1), POS(23,-.5f, .5f, .5f, -1,0,0, 0,0, 1,1,1,1),
};
uint32_t idx[36];
for (int i = 0; i < 6; i++) { int b = i*4; idx[i*6]=b; idx[i*6+1]=b+1; idx[i*6+2]=b+2; idx[i*6+3]=b; idx[i*6+4]=b+2; idx[i*6+5]=b+3; }
return create_mesh(dev, v, 24, idx, 36, sizeof(V));
}
Mesh* mesh_create_plane(ID3D11Device* dev, float size) {
typedef struct { float p[3], n[3], uv[2], c[4]; } V;
float h = size * 0.5f;
V v[4] = {
{{-h,0,h},{0,1,0},{0,1},{1,1,1,1}},
{{ h,0,h},{0,1,0},{1,1},{1,1,1,1}},
{{ h,0,-h},{0,1,0},{1,0},{1,1,1,1}},
{{-h,0,-h},{0,1,0},{0,0},{1,1,1,1}},
};
uint32_t idx[6] = {0,1,2,0,2,3};
return create_mesh(dev, v, 4, idx, 6, sizeof(V));
}
Mesh* mesh_create_sphere(ID3D11Device* dev, float r, int seg) {
typedef struct { float p[3], n[3], uv[2], c[4]; } V;
int vc = (seg+1)*(seg+1);
V* v = (V*)malloc(vc * sizeof(V));
int vi = 0;
for (int lat = 0; lat <= seg; lat++) {
float theta = 3.14159265f * lat / seg;
float st = sinf(theta), ct = cosf(theta);
for (int lon = 0; lon <= seg; lon++) {
float phi = 2.0f * 3.14159265f * lon / seg;
float sp = sinf(phi), cp = cosf(phi);
float nx = cp*st, ny = ct, nz = sp*st;
v[vi].p[0] = nx*r; v[vi].p[1] = ny*r; v[vi].p[2] = nz*r;
v[vi].n[0] = nx; v[vi].n[1] = ny; v[vi].n[2] = nz;
v[vi].uv[0] = (float)lon/seg; v[vi].uv[1] = (float)lat/seg;
v[vi].c[0]=1; v[vi].c[1]=1; v[vi].c[2]=1; v[vi].c[3]=1;
vi++;
}
}
int ic = seg*seg*6;
uint32_t* idx = (uint32_t*)malloc(ic * sizeof(uint32_t));
int ii = 0;
for (int lat = 0; lat < seg; lat++) {
for (int lon = 0; lon < seg; lon++) {
uint32_t f = lat*(seg+1)+lon, s = f+seg+1;
idx[ii++]=f; idx[ii++]=s; idx[ii++]=f+1;
idx[ii++]=s; idx[ii++]=s+1; idx[ii++]=f+1;
}
}
Mesh* m = create_mesh(dev, v, vc, idx, ic, sizeof(V));
free(v); free(idx);
return m;
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
typedef struct {
float pos[3];
float norm[3];
float uv[2];
float color[4];
} Vertex;
typedef struct {
ID3D11Buffer* vb;
ID3D11Buffer* ib;
uint32_t vcount;
uint32_t icount;
uint32_t stride;
} Mesh;
Mesh* mesh_create_cube(ID3D11Device* dev);
Mesh* mesh_create_plane(ID3D11Device* dev, float size);
Mesh* mesh_create_sphere(ID3D11Device* dev, float r, int seg);
void mesh_destroy(Mesh* m);
void mesh_draw(Mesh* m, ID3D11DeviceContext* ctx);
+55
View File
@@ -0,0 +1,55 @@
#include "renderer.h"
#include <stdlib.h>
Renderer* renderer_create(GraphicsDevice* device) {
Renderer* r = (Renderer*)calloc(1, sizeof(Renderer));
r->device = device;
mat4_identity(&r->view);
mat4_identity(&r->projection);
r->light_dir = (Vec3){0.5f, -1.0f, 0.3f};
r->light_color = (Vec4){1,1,1,1};
r->ambient_color = (Vec4){0.2f,0.2f,0.3f,1};
return r;
}
void renderer_destroy(Renderer* r) { free(r); }
void renderer_begin_frame(Renderer* r) {
graphics_device_clear(r->device, 0.1f, 0.1f, 0.15f, 1.0f);
}
void renderer_end_frame(Renderer* r) {
graphics_device_present(r->device);
}
void renderer_draw_mesh(Renderer* r, Mesh* m) {
if (!m) return;
ID3D11DeviceContext* ctx = r->device->context;
UINT stride = sizeof(Vertex);
UINT offset = 0;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &m->vb, &stride, &offset);
if (m->ib) {
ctx->lpVtbl->IASetIndexBuffer(ctx, m->ib, DXGI_FORMAT_R32_UINT, 0);
ctx->lpVtbl->DrawIndexed(ctx, m->icount, 0, 0);
} else {
ctx->lpVtbl->Draw(ctx, m->vcount, 0);
}
}
void renderer_draw_mesh_with_shader(Renderer* r, Mesh* m, Shader* s, const Mat4* world, Texture* t) {
if (!m || !s) return;
ID3D11DeviceContext* ctx = r->device->context;
shader_bind(s, ctx);
renderer_draw_mesh(r, m);
}
void renderer_set_view(Renderer* r, const Mat4* v) { r->view = *v; }
void renderer_set_projection(Renderer* r, const Mat4* p) { r->projection = *p; }
void renderer_set_light(Renderer* r, Vec3 d, Vec4 c, Vec4 a) { r->light_dir=d; r->light_color=c; r->ambient_color=a; }
GraphicsDevice* renderer_get_device(Renderer* r) { return r ? r->device : NULL; }
void renderer_resize(Renderer* r, int width, int height) {
if (r && r->device && width > 0 && height > 0) {
graphics_device_resize(r->device, width, height);
}
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "graphics_device.h"
#include "shader.h"
#include "mesh.h"
#include "texture.h"
#include "camera.h"
#include "../include/engine_api.h"
#include "../ASM/math_c_fallback.h"
typedef struct {
GraphicsDevice* device;
Shader* current_shader;
Mat4 view;
Mat4 projection;
Vec3 light_dir;
Vec4 light_color;
Vec4 ambient_color;
} Renderer;
Renderer* renderer_create(GraphicsDevice* device);
void renderer_destroy(Renderer* renderer);
void renderer_begin_frame(Renderer* renderer);
void renderer_end_frame(Renderer* renderer);
void renderer_draw_mesh(Renderer* renderer, Mesh* mesh);
void renderer_draw_mesh_with_shader(Renderer* renderer, Mesh* mesh, Shader* shader, const Mat4* world, Texture* tex);
void renderer_set_view(Renderer* renderer, const Mat4* view);
void renderer_set_projection(Renderer* renderer, const Mat4* projection);
void renderer_set_light(Renderer* renderer, Vec3 dir, Vec4 color, Vec4 ambient);
GraphicsDevice* renderer_get_device(Renderer* renderer);
void renderer_resize(Renderer* renderer, int width, int height);
+74
View File
@@ -0,0 +1,74 @@
#include "shader.h"
#include <d3dcompiler.h>
#include <stdlib.h>
#include <string.h>
static const char* default_vs =
"struct VS_IN{float3 pos:POSITION;float3 n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};"
"struct PS_IN{float4 pos:SV_POSITION;float4 col:COLOR;};"
"cbuffer CB:register(b0){float4x4 WVP;};"
"PS_IN main(VS_IN i){PS_IN o;o.pos=mul(float4(i.pos,1),WVP);o.col=i.col;return o;}";
static const char* default_ps =
"struct PS_IN{float4 pos:SV_POSITION;float4 col:COLOR;};"
"float4 main(PS_IN i):SV_TARGET{return i.col;}";
static ID3DBlob* compile_shader(const char* code, uint32_t len, const char* target) {
ID3DBlob *blob = NULL, *err = NULL;
D3DCompile(code, len, NULL, NULL, NULL, "main", target, D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &blob, &err);
if (err) err->lpVtbl->Release(err);
return blob;
}
Shader* shader_create(void) {
return (Shader*)calloc(1, sizeof(Shader));
}
void shader_destroy(Shader* s) {
if (!s) return;
if (s->cb) s->cb->lpVtbl->Release(s->cb);
if (s->layout) s->layout->lpVtbl->Release(s->layout);
if (s->ps) s->ps->lpVtbl->Release(s->ps);
if (s->vs) s->vs->lpVtbl->Release(s->vs);
free(s);
}
int shader_compile(Shader* s, ID3D11Device* dev, const char* vs_code, const char* ps_code, uint32_t vs_len, uint32_t ps_len) {
if (!vs_code || !ps_code) {
vs_code = default_vs; ps_code = default_ps;
vs_len = (uint32_t)strlen(default_vs); ps_len = (uint32_t)strlen(default_ps);
}
ID3DBlob* vs_blob = compile_shader(vs_code, vs_len, "vs_5_0");
ID3DBlob* ps_blob = compile_shader(ps_code, ps_len, "ps_5_0");
if (!vs_blob || !ps_blob) {
if (vs_blob) vs_blob->lpVtbl->Release(vs_blob);
if (ps_blob) ps_blob->lpVtbl->Release(ps_blob);
return 0;
}
dev->lpVtbl->CreateVertexShader(dev, vs_blob->lpVtbl->GetBufferPointer(vs_blob), vs_blob->lpVtbl->GetBufferSize(vs_blob), NULL, &s->vs);
dev->lpVtbl->CreatePixelShader(dev, ps_blob->lpVtbl->GetBufferPointer(ps_blob), ps_blob->lpVtbl->GetBufferSize(ps_blob), NULL, &s->ps);
D3D11_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
};
dev->lpVtbl->CreateInputLayout(dev, layout, 4, vs_blob->lpVtbl->GetBufferPointer(vs_blob), vs_blob->lpVtbl->GetBufferSize(vs_blob), &s->layout);
D3D11_BUFFER_DESC bd = {0};
bd.ByteWidth = 256; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
dev->lpVtbl->CreateBuffer(dev, &bd, NULL, &s->cb);
vs_blob->lpVtbl->Release(vs_blob);
ps_blob->lpVtbl->Release(ps_blob);
return 1;
}
void shader_bind(Shader* s, ID3D11DeviceContext* ctx) {
ctx->lpVtbl->VSSetShader(ctx, s->vs, NULL, 0);
ctx->lpVtbl->PSSetShader(ctx, s->ps, NULL, 0);
ctx->lpVtbl->IASetInputLayout(ctx, s->layout);
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &s->cb);
}
void shader_set_matrix(Shader* s, ID3D11DeviceContext* ctx, const float* data) {
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)s->cb, 0, NULL, data, 0, 0);
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <d3d11.h>
#include <stdint.h>
typedef struct {
ID3D11VertexShader* vs;
ID3D11PixelShader* ps;
ID3D11InputLayout* layout;
ID3D11Buffer* cb;
} Shader;
Shader* shader_create(void);
void shader_destroy(Shader* s);
int shader_compile(Shader* s, ID3D11Device* dev, const char* vs_code, const char* ps_code, uint32_t vs_len, uint32_t ps_len);
void shader_bind(Shader* s, ID3D11DeviceContext* ctx);
void shader_set_matrix(Shader* s, ID3D11DeviceContext* ctx, const float* data);
+188
View File
@@ -0,0 +1,188 @@
#include "texture.h"
#include <wincodec.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "windowscodecs.lib")
static IWICImagingFactory* wic_factory = NULL;
static HRESULT ensure_wic(void) {
if (wic_factory) return S_OK;
return CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICImagingFactory, (void**)&wic_factory);
}
Texture* texture_create(void) {
return (Texture*)calloc(1, sizeof(Texture));
}
void texture_destroy(Texture* texture) {
if (!texture) return;
if (texture->srv) ID3D11ShaderResourceView_Release(texture->srv);
if (texture->texture) ID3D11Texture2D_Release(texture->texture);
free(texture);
}
static Texture* create_from_wic(ID3D11Device* device, IWICBitmapDecoder* decoder) {
IWICBitmapFrameDecode* frame = NULL;
IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
uint32_t w, h;
IWICBitmapFrameDecode_GetSize(frame, &w, &h);
IWICFormatConverter* converter = NULL;
IWICImagingFactory_CreateFormatConverter(wic_factory, &converter);
IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame,
&GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, NULL, 0.0, WICBitmapPaletteTypeCustom);
uint8_t* pixels = (uint8_t*)malloc(w * h * 4);
IWICFormatConverter_CopyPixels(converter, NULL, w * 4, w * h * 4, pixels);
IWICFormatConverter_Release(converter);
IWICBitmapFrameDecode_Release(frame);
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA init = {pixels, w * 4, 0};
Texture* tex = texture_create();
ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture);
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0};
srvd.Format = desc.Format;
srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvd.Texture2D.MipLevels = 1;
ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv);
tex->width = w;
tex->height = h;
tex->mip_levels = 1;
free(pixels);
return tex;
}
Texture* texture_load_from_file(ID3D11Device* device, const char* path) {
if (FAILED(ensure_wic())) return NULL;
IWICBitmapDecoder* decoder = NULL;
wchar_t wpath[512];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, 512);
HRESULT hr = IWICImagingFactory_CreateDecoderFromFilename(wic_factory, wpath, NULL,
GENERIC_READ, WICDecodeMetadataCacheOnLoad, &decoder);
if (FAILED(hr)) return NULL;
Texture* tex = create_from_wic(device, decoder);
IWICBitmapDecoder_Release(decoder);
return tex;
}
Texture* texture_load_from_memory(ID3D11Device* device, const uint8_t* data, uint32_t size) {
if (FAILED(ensure_wic())) return NULL;
IWICStream* stream = NULL;
IWICImagingFactory_CreateStream(wic_factory, &stream);
IWICStream_InitializeFromMemory(stream, (BYTE*)data, size);
IWICBitmapDecoder* decoder = NULL;
IWICImagingFactory_CreateDecoderFromStream(wic_factory, (IStream*)stream, NULL,
WICDecodeMetadataCacheOnLoad, &decoder);
IWICStream_Release(stream);
if (!decoder) return NULL;
Texture* tex = create_from_wic(device, decoder);
IWICBitmapDecoder_Release(decoder);
return tex;
}
Texture* texture_create_solid(ID3D11Device* device, uint32_t w, uint32_t h,
uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
uint8_t* pixels = (uint8_t*)malloc(w * h * 4);
for (uint32_t i = 0; i < w * h; i++) {
pixels[i * 4 + 0] = r;
pixels[i * 4 + 1] = g;
pixels[i * 4 + 2] = b;
pixels[i * 4 + 3] = a;
}
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA init = {pixels, w * 4, 0};
Texture* tex = texture_create();
ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture);
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0};
srvd.Format = desc.Format;
srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvd.Texture2D.MipLevels = 1;
ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv);
tex->width = w;
tex->height = h;
free(pixels);
return tex;
}
Texture* texture_create_checkerboard(ID3D11Device* device, uint32_t size, uint32_t checks) {
uint8_t* pixels = (uint8_t*)malloc(size * size * 4);
uint32_t cell = size / checks;
for (uint32_t y = 0; y < size; y++) {
for (uint32_t x = 0; x < size; x++) {
uint8_t c = ((x / cell) + (y / cell)) % 2 ? 200 : 55;
uint32_t i = (y * size + x) * 4;
pixels[i] = pixels[i + 1] = pixels[i + 2] = c;
pixels[i + 3] = 255;
}
}
D3D11_TEXTURE2D_DESC desc = {0};
desc.Width = size;
desc.Height = size;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
D3D11_SUBRESOURCE_DATA init = {pixels, size * 4, 0};
Texture* tex = texture_create();
ID3D11Device_CreateTexture2D(device, &desc, &init, &tex->texture);
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = {0};
srvd.Format = desc.Format;
srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvd.Texture2D.MipLevels = 1;
ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource*)tex->texture, &srvd, &tex->srv);
tex->width = size;
tex->height = size;
free(pixels);
return tex;
}
void texture_bind(Texture* texture, ID3D11DeviceContext* ctx, uint32_t slot) {
if (!texture || !texture->srv) return;
ID3D11DeviceContext_PSSetShaderResources(ctx, slot, 1, &texture->srv);
ID3D11DeviceContext_PSSetSamplers(ctx, slot, 1, &(ID3D11SamplerState*){NULL});
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
// ============================================================================
// texture.h - 纹理加载 (WIC)
// ============================================================================
#include <d3d11.h>
#include <stdint.h>
typedef struct {
ID3D11Texture2D* texture;
ID3D11ShaderResourceView* srv;
uint32_t width;
uint32_t height;
uint32_t mip_levels;
} Texture;
// 创建/销毁
Texture* texture_create(void);
void texture_destroy(Texture* texture);
// 从文件加载
Texture* texture_load_from_file(ID3D11Device* device, const char* path);
// 从内存加载
Texture* texture_load_from_memory(ID3D11Device* device,
const uint8_t* data, uint32_t size);
// 创建纯色纹理
Texture* texture_create_solid(ID3D11Device* device, uint32_t w, uint32_t h,
uint8_t r, uint8_t g, uint8_t b, uint8_t a);
// 创建棋盘格
Texture* texture_create_checkerboard(ID3D11Device* device, uint32_t size, uint32_t checks);
// 绑定
void texture_bind(Texture* texture, ID3D11DeviceContext* ctx, uint32_t slot);
+60
View File
@@ -0,0 +1,60 @@
#include "lua_engine.h"
#include <stdlib.h>
#include <stdio.h>
// Lua头文件 (需要单独下载或集成)
// #include <lua.h>
// #include <lualib.h>
// #include <lauxlib.h>
// 由于Lua需要单独集成,这里提供占位实现
// 实际使用时取消注释并链接Lua库
typedef struct lua_State lua_State;
static lua_State* luaL_newstate(void) { return NULL; }
static void luaL_openlibs(lua_State* L) { (void)L; }
static int luaL_dofile(lua_State* L, const char* fn) { (void)L; (void)fn; return -1; }
static int luaL_dostring(lua_State* L, const char* s) { (void)L; (void)s; return -1; }
static void lua_close(lua_State* L) { (void)L; }
LuaEngine* lua_engine_create(void) {
return (LuaEngine*)calloc(1, sizeof(LuaEngine));
}
void lua_engine_destroy(LuaEngine* engine) {
if (!engine) return;
if (engine->L) lua_close(engine->L);
free(engine);
}
int lua_engine_init(LuaEngine* engine) {
engine->L = luaL_newstate();
if (!engine->L) return -1;
luaL_openlibs(engine->L);
engine->initialized = 1;
return 0;
}
int lua_engine_do_file(LuaEngine* engine, const char* path) {
if (!engine->L) return -1;
return luaL_dofile(engine->L, path);
}
int lua_engine_do_string(LuaEngine* engine, const char* code) {
if (!engine->L) return -1;
return luaL_dostring(engine->L, code);
}
void lua_engine_register_function(LuaEngine* engine, const char* name, void* func) {
(void)engine;
(void)name;
(void)func;
// lua_pushcfunction(engine->L, func);
// lua_setglobal(engine->L, name);
}
lua_State* lua_engine_get_state(LuaEngine* engine) {
return engine->L;
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
// ============================================================================
// lua_engine.h - Lua脚本引擎
// ============================================================================
#include <stdint.h>
// 前向声明
struct lua_State;
typedef struct {
struct lua_State* L;
int initialized;
} LuaEngine;
// 创建/销毁
LuaEngine* lua_engine_create(void);
void lua_engine_destroy(LuaEngine* engine);
// 初始化
int lua_engine_init(LuaEngine* engine);
// 执行
int lua_engine_do_file(LuaEngine* engine, const char* path);
int lua_engine_do_string(LuaEngine* engine, const char* code);
// 注册C函数
void lua_engine_register_function(LuaEngine* engine, const char* name, void* func);
// 获取状态
struct lua_State* lua_engine_get_state(LuaEngine* engine);
+212
View File
@@ -0,0 +1,212 @@
#include "ui.h"
#include <stdlib.h>
#include <string.h>
static const char* ui_vs = R"(
struct VS_INPUT { float2 Pos : POSITION; float2 UV : TEXCOORD0; uint Color : COLOR0; };
struct VS_OUTPUT { float4 Pos : SV_POSITION; float2 UV : TEXCOORD0; float4 Color : COLOR0; };
VS_OUTPUT main(VS_INPUT input) {
VS_OUTPUT output;
output.Pos = float4(input.Pos.x, input.Pos.y, 0, 1);
output.UV = input.UV;
output.Color = float4((input.Color & 0xFF) / 255.0, ((input.Color >> 8) & 0xFF) / 255.0,
((input.Color >> 16) & 0xFF) / 255.0, ((input.Color >> 24) & 0xFF) / 255.0);
return output;
}
)";
static const char* ui_ps = R"(
struct PS_INPUT { float4 Pos : SV_POSITION; float2 UV : TEXCOORD0; float4 Color : COLOR0; };
float4 main(PS_INPUT input) : SV_TARGET { return input.Color; }
)";
UI* ui_create(ID3D11Device* device) {
UI* ui = (UI*)calloc(1, sizeof(UI));
ui->font_size = 14.0f;
ui->text_color = 0xFFFFFFFF;
ui->bg_color = 0xFF333333;
ui->border_color = 0xFF666666;
ui->padding = 4.0f;
D3D11_BUFFER_DESC vbd = {0};
vbd.ByteWidth = sizeof(UIVertex) * UI_MAX_VERTICES;
vbd.Usage = D3D11_USAGE_DYNAMIC;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
ID3D11Device_CreateBuffer(device, &vbd, NULL, &ui->vertex_buffer);
D3D11_BUFFER_DESC ibd = {0};
ibd.ByteWidth = sizeof(uint32_t) * UI_MAX_INDICES;
ibd.Usage = D3D11_USAGE_DYNAMIC;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
ID3D11Device_CreateBuffer(device, &ibd, NULL, &ui->index_buffer);
// 编译着色器
ID3DBlob* vs_blob = NULL, *ps_blob = NULL, *err = NULL;
D3DCompile(ui_vs, strlen(ui_vs), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vs_blob, &err);
D3DCompile(ui_ps, strlen(ui_ps), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &ps_blob, &err);
if (vs_blob && ps_blob) {
ID3D11Device_CreateVertexShader(device, ID3D10Blob_GetBufferPointer(vs_blob),
ID3D10Blob_GetBufferSize(vs_blob), NULL, &ui->vertex_shader);
ID3D11Device_CreatePixelShader(device, ID3D10Blob_GetBufferPointer(ps_blob),
ID3D10Blob_GetBufferSize(ps_blob), NULL, &ui->pixel_shader);
D3D11_INPUT_ELEMENT_DESC layout[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
ID3D11Device_CreateInputLayout(device, layout, 3,
ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), &ui->input_layout);
ID3D10Blob_Release(vs_blob);
ID3D10Blob_Release(ps_blob);
}
D3D11_BLEND_DESC bd = {0};
bd.RenderTarget[0].BlendEnable = TRUE;
bd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
ID3D11Device_CreateBlendState(device, &bd, &ui->blend_state);
D3D11_RASTERIZER_DESC rd = {0};
rd.FillMode = D3D11_FILL_SOLID;
rd.CullMode = D3D11_CULL_NONE;
rd.ScissorEnable = TRUE;
ID3D11Device_CreateRasterizerState(device, &rd, &ui->rasterizer);
return ui;
}
void ui_destroy(UI* ui) {
if (!ui) return;
if (ui->rasterizer) ID3D11RasterizerState_Release(ui->rasterizer);
if (ui->blend_state) ID3D11BlendState_Release(ui->blend_state);
if (ui->input_layout) ID3D11InputLayout_Release(ui->input_layout);
if (ui->pixel_shader) ID3D11PixelShader_Release(ui->pixel_shader);
if (ui->vertex_shader) ID3D11VertexShader_Release(ui->vertex_shader);
if (ui->index_buffer) ID3D11Buffer_Release(ui->index_buffer);
if (ui->vertex_buffer) ID3D11Buffer_Release(ui->vertex_buffer);
free(ui);
}
void ui_begin(UI* ui, float mx, float my, int md, int mp, int mr) {
ui->mouse_x = mx;
ui->mouse_y = my;
ui->mouse_down = md;
ui->mouse_pressed = mp;
ui->mouse_released = mr;
ui->vertex_count = 0;
ui->index_count = 0;
}
void ui_end(UI* ui) {
(void)ui;
}
void ui_draw_rect(UI* ui, float x, float y, float w, float h, uint32_t color) {
uint32_t base = ui->vertex_count;
ui->vertices[ui->vertex_count++] = (UIVertex){x, y, 0, 0, color};
ui->vertices[ui->vertex_count++] = (UIVertex){x + w, y, 1, 0, color};
ui->vertices[ui->vertex_count++] = (UIVertex){x + w, y + h, 1, 1, color};
ui->vertices[ui->vertex_count++] = (UIVertex){x, y + h, 0, 1, color};
ui->indices[ui->index_count++] = base;
ui->indices[ui->index_count++] = base + 1;
ui->indices[ui->index_count++] = base + 2;
ui->indices[ui->index_count++] = base;
ui->indices[ui->index_count++] = base + 2;
ui->indices[ui->index_count++] = base + 3;
}
void ui_draw_rect_border(UI* ui, float x, float y, float w, float h,
uint32_t fill, uint32_t border, float thickness) {
ui_draw_rect(ui, x, y, w, h, fill);
ui_draw_rect(ui, x, y, w, thickness, border);
ui_draw_rect(ui, x, y + h - thickness, w, thickness, border);
ui_draw_rect(ui, x, y, thickness, h, border);
ui_draw_rect(ui, x + w - thickness, y, thickness, h, border);
}
int ui_button(UI* ui, float x, float y, float w, float h, const char* text) {
(void)text;
int hover = ui->mouse_x >= x && ui->mouse_x <= x + w &&
ui->mouse_y >= y && ui->mouse_y <= y + h;
uint32_t color = hover ? 0xFF555555 : 0xFF444444;
if (hover && ui->mouse_pressed) color = 0xFF666666;
ui_draw_rect_border(ui, x, y, w, h, color, 0xFF888888, 1);
return hover && ui->mouse_pressed;
}
float ui_slider(UI* ui, float x, float y, float w, float h, float value, float min_val, float max_val) {
ui_draw_rect_border(ui, x, y, w, h, 0xFF333333, 0xFF666666, 1);
int hover = ui->mouse_x >= x && ui->mouse_x <= x + w &&
ui->mouse_y >= y && ui->mouse_y <= y + h;
if (hover && ui->mouse_down) {
float t = (ui->mouse_x - x) / w;
value = min_val + t * (max_val - min_val);
if (value < min_val) value = min_val;
if (value > max_val) value = max_val;
}
float knob_x = x + ((value - min_val) / (max_val - min_val)) * (w - h);
ui_draw_rect(ui, knob_x, y, h, h, 0xFF0078D4);
return value;
}
int ui_checkbox(UI* ui, float x, float y, const char* text, int checked) {
(void)text;
float s = 16.0f;
ui_draw_rect_border(ui, x, y, s, s, checked ? 0xFF0078D4 : 0xFF333333, 0xFF666666, 1);
if (ui->mouse_x >= x && ui->mouse_x <= x + s &&
ui->mouse_y >= y && ui->mouse_y <= y + s && ui->mouse_pressed) {
return !checked;
}
return checked;
}
void ui_label(UI* ui, float x, float y, const char* text) {
(void)text;
ui_draw_rect(ui, x, y, (float)(strlen(text) * 8), ui->font_size, 0x00000000);
}
void ui_render(UI* ui, ID3D11DeviceContext* ctx) {
if (ui->vertex_count == 0) return;
D3D11_MAPPED_SUBRESOURCE mapped;
if (SUCCEEDED(ID3D11DeviceContext_Map(ctx, (ID3D11Resource*)ui->vertex_buffer, 0,
D3D11_MAP_WRITE_DISCARD, 0, &mapped))) {
memcpy(mapped.pData, ui->vertices, sizeof(UIVertex) * ui->vertex_count);
ID3D11DeviceContext_Unmap(ctx, (ID3D11Resource*)ui->vertex_buffer, 0);
}
if (SUCCEEDED(ID3D11DeviceContext_Map(ctx, (ID3D11Resource*)ui->index_buffer, 0,
D3D11_MAP_WRITE_DISCARD, 0, &mapped))) {
memcpy(mapped.pData, ui->indices, sizeof(uint32_t) * ui->index_count);
ID3D11DeviceContext_Unmap(ctx, (ID3D11Resource*)ui->index_buffer, 0);
}
UINT stride = sizeof(UIVertex);
UINT offset = 0;
ID3D11DeviceContext_IASetVertexBuffers(ctx, 0, 1, &ui->vertex_buffer, &stride, &offset);
ID3D11DeviceContext_IASetIndexBuffer(ctx, ui->index_buffer, DXGI_FORMAT_R32_UINT, 0);
ID3D11DeviceContext_IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D11DeviceContext_IASetInputLayout(ctx, ui->input_layout);
ID3D11DeviceContext_VSSetShader(ctx, ui->vertex_shader, NULL, 0);
ID3D11DeviceContext_PSSetShader(ctx, ui->pixel_shader, NULL, 0);
float blend[4] = {1, 1, 1, 1};
ID3D11DeviceContext_OMSetBlendState(ctx, ui->blend_state, blend, 0xFFFFFFFF);
ID3D11DeviceContext_RSSetState(ctx, ui->rasterizer);
ID3D11DeviceContext_DrawIndexed(ctx, ui->index_count, 0, 0);
ID3D11DeviceContext_OMSetBlendState(ctx, NULL, blend, 0xFFFFFFFF);
ID3D11DeviceContext_RSSetState(ctx, NULL);
}
+69
View File
@@ -0,0 +1,69 @@
#pragma once
// ============================================================================
// ui.h - 立即模式UI
// ============================================================================
#include <d3d11.h>
#include <stdint.h>
#define UI_MAX_VERTICES 16384
#define UI_MAX_INDICES 32768
#define UI_MAX_WIDGETS 256
typedef struct {
float x, y;
float u, v;
uint32_t color;
} UIVertex;
typedef struct {
float x, y, w, h;
uint32_t color;
int visible;
} UIRect;
typedef struct {
ID3D11Buffer* vertex_buffer;
ID3D11Buffer* index_buffer;
ID3D11VertexShader* vertex_shader;
ID3D11PixelShader* pixel_shader;
ID3D11InputLayout* input_layout;
ID3D11BlendState* blend_state;
ID3D11RasterizerState* rasterizer;
UIVertex vertices[UI_MAX_VERTICES];
uint32_t indices[UI_MAX_INDICES];
uint32_t vertex_count;
uint32_t index_count;
float mouse_x, mouse_y;
int mouse_down;
int mouse_pressed;
int mouse_released;
float font_size;
uint32_t text_color;
uint32_t bg_color;
uint32_t border_color;
float padding;
} UI;
// 创建/销毁
UI* ui_create(ID3D11Device* device);
void ui_destroy(UI* ui);
// 帧操作
void ui_begin(UI* ui, float mouse_x, float mouse_y, int mouse_down, int mouse_pressed, int mouse_released);
void ui_end(UI* ui);
void ui_render(UI* ui, ID3D11DeviceContext* ctx);
// 基础绘制
void ui_draw_rect(UI* ui, float x, float y, float w, float h, uint32_t color);
void ui_draw_rect_border(UI* ui, float x, float y, float w, float h, uint32_t fill, uint32_t border, float thickness);
// 控件
int ui_button(UI* ui, float x, float y, float w, float h, const char* text);
float ui_slider(UI* ui, float x, float y, float w, float h, float value, float min_val, float max_val);
int ui_checkbox(UI* ui, float x, float y, const char* text, int checked);
void ui_label(UI* ui, float x, float y, const char* text);
+135
View File
@@ -0,0 +1,135 @@
// ============================================================================
// block_core.c - 积木核心操作
// ============================================================================
#include "block_core.h"
#include <stdlib.h>
#include <string.h>
// 创建积木
Block* block_create(BlockType type, float x, float y) {
Block* block = (Block*)calloc(1, sizeof(Block));
if (!block) return NULL;
block->type = type;
block->x = x;
block->y = y;
block->width = 200;
block->height = 60;
// 初始化槽位
block->input_count = 0;
block->output_count = 0;
for (int i = 0; i < MAX_BLOCK_INPUTS; i++) {
block->inputs[i].owner = block;
block->inputs[i].id = i;
}
for (int i = 0; i < MAX_BLOCK_OUTPUTS; i++) {
block->outputs[i].owner = block;
block->outputs[i].id = i;
}
return block;
}
// 销毁积木
void block_destroy(Block* block) {
if (!block) return;
free(block);
}
// 添加输入槽位
BlockSlot* block_add_input(Block* block, SlotKind kind, SlotValueType value_type, const char* label) {
if (block->input_count >= MAX_BLOCK_INPUTS) return NULL;
BlockSlot* slot = &block->inputs[block->input_count];
slot->kind = kind;
slot->value_type = value_type;
if (label) strncpy(slot->label, label, MAX_BLOCK_LABEL - 1);
slot->value.type = value_type;
block->input_count++;
return slot;
}
// 添加输出槽位
BlockSlot* block_add_output(Block* block, SlotKind kind, SlotValueType value_type, const char* label) {
if (block->output_count >= MAX_BLOCK_OUTPUTS) return NULL;
BlockSlot* slot = &block->outputs[block->output_count];
slot->kind = kind;
slot->value_type = value_type;
if (label) strncpy(slot->label, label, MAX_BLOCK_LABEL - 1);
block->output_count++;
return slot;
}
// 连接两个槽位
bool block_connect(BlockSlot* from, BlockSlot* to) {
if (!from || !to) return false;
if (from->owner == to->owner) return false; // 不能自连
// 断开旧连接
if (from->connected) from->connected->connected = NULL;
if (to->connected) to->connected->connected = NULL;
from->connected = to;
to->connected = from;
return true;
}
// 断开槽位
void block_disconnect(BlockSlot* slot) {
if (!slot || !slot->connected) return;
slot->connected->connected = NULL;
slot->connected = NULL;
}
// 检查槽位是否已连接
bool block_slot_connected(BlockSlot* slot) {
return slot && slot->connected != NULL;
}
// 获取槽位的值
SlotValue block_slot_get_value(BlockSlot* slot) {
if (!slot) {
SlotValue empty = {0};
return empty;
}
// 如果有连接,从连接的积木获取值
if (slot->connected && slot->connected->owner) {
Block* source = slot->connected->owner;
// 从源积木的输出槽位获取值
for (int i = 0; i < source->output_count; i++) {
if (&source->outputs[i] == slot->connected) {
return source->outputs[i].value;
}
}
}
return slot->value;
}
// 设置槽位的值
void block_slot_set_value(BlockSlot* slot, SlotValue value) {
if (slot) slot->value = value;
}
// 积木是否包含点
bool block_contains_point(Block* block, float px, float py) {
return px >= block->x && px <= block->x + block->width
&& py >= block->y && py <= block->y + block->height;
}
// 获取槽位的世界位置
void block_slot_world_pos(BlockSlot* slot, float* wx, float* wy) {
if (!slot || !slot->owner) {
*wx = 0; *wy = 0;
return;
}
*wx = slot->owner->x + slot->x;
*wy = slot->owner->y + slot->y;
}
+182
View File
@@ -0,0 +1,182 @@
#pragma once
// ============================================================================
// block_core.h - 积木核心数据结构
// ============================================================================
#include <stdint.h>
#include <stdbool.h>
#define MAX_BLOCK_INPUTS 8
#define MAX_BLOCK_OUTPUTS 8
#define MAX_BLOCK_LABEL 64
// 颜色
typedef struct {
float r, g, b, a;
} Color;
typedef Color BlockColor;
// 预定义颜色
#define BLOCK_COLOR_EVENT {0.9f, 0.2f, 0.2f, 1.0f} // 红
#define BLOCK_COLOR_ACTION {0.2f, 0.5f, 0.9f, 1.0f} // 蓝
#define BLOCK_COLOR_CONTROL {0.2f, 0.7f, 0.3f, 1.0f} // 绿
#define BLOCK_COLOR_OPERATOR {0.9f, 0.6f, 0.1f, 1.0f} // 橙
#define BLOCK_COLOR_VARIABLE {0.7f, 0.3f, 0.8f, 1.0f} // 紫
#define BLOCK_COLOR_FUNCTION {0.9f, 0.8f, 0.2f, 1.0f} // 黄
#define BLOCK_COLOR_DATA {0.4f, 0.7f, 0.9f, 1.0f} // 浅蓝
// 槽位值类型
typedef enum {
SLOT_VALUE_NUMBER = 0,
SLOT_VALUE_STRING,
SLOT_VALUE_BOOLEAN,
SLOT_VALUE_VECTOR3,
SLOT_VALUE_ANY
} SlotValueType;
// 槽位值
typedef struct {
SlotValueType type;
union {
double number;
char string[256];
int boolean;
struct { float x, y, z; } vector3;
} as;
} SlotValue;
// 槽位类型
typedef enum {
SLOT_STATEMENT = 0, // 语句槽位 (执行流)
SLOT_VALUE // 值槽位 (数据流)
} SlotKind;
// 槽位
typedef struct BlockSlot {
int id;
SlotKind kind;
SlotValueType value_type;
char label[MAX_BLOCK_LABEL];
struct Block* owner; // 所属积木
struct BlockSlot* connected; // 连接的槽位
SlotValue value; // 当前值 (仅值槽位)
float x, y; // 相对于积木的位置
float width, height; // 槽位尺寸
} BlockSlot;
// 积木类型
typedef enum {
// 事件
BLOCK_EVENT_START = 0,
BLOCK_EVENT_UPDATE,
BLOCK_EVENT_COLLISION,
BLOCK_EVENT_KEY_PRESSED,
BLOCK_EVENT_MOUSE_CLICK,
BLOCK_EVENT_TIMER,
// 动作
BLOCK_ACTION_MOVE,
BLOCK_ACTION_ROTATE,
BLOCK_ACTION_SCALE,
BLOCK_ACTION_SET_POSITION,
BLOCK_ACTION_SET_ROTATION,
BLOCK_ACTION_PLAY_SOUND,
BLOCK_ACTION_DESTROY,
BLOCK_ACTION_INSTANTIATE,
// 控制
BLOCK_CONTROL_IF,
BLOCK_CONTROL_IF_ELSE,
BLOCK_CONTROL_REPEAT,
BLOCK_CONTROL_REPEAT_TIMES,
BLOCK_CONTROL_WHILE,
BLOCK_CONTROL_WAIT,
BLOCK_CONTROL_FUNCTION_DEF,
// 运算
BLOCK_OP_ADD,
BLOCK_OP_SUB,
BLOCK_OP_MUL,
BLOCK_OP_DIV,
BLOCK_OP_MOD,
BLOCK_OP_EQUALS,
BLOCK_OP_NOT_EQUALS,
BLOCK_OP_GREATER,
BLOCK_OP_LESS,
BLOCK_OP_AND,
BLOCK_OP_OR,
BLOCK_OP_NOT,
// 变量
BLOCK_VAR_GET,
BLOCK_VAR_SET,
BLOCK_VAR_CREATE,
// 函数
BLOCK_FUNC_CALL,
BLOCK_FUNC_RETURN,
BLOCK_TYPE_COUNT
} BlockType;
// 积木类型信息
typedef struct {
BlockType type;
const char* name;
const char* label;
const char* category;
BlockColor color;
int input_count;
int output_count;
SlotValueType input_types[MAX_BLOCK_INPUTS];
SlotValueType output_types[MAX_BLOCK_OUTPUTS];
const char* input_labels[MAX_BLOCK_INPUTS];
const char* output_labels[MAX_BLOCK_OUTPUTS];
} BlockTypeInfo;
// 积木
typedef struct Block {
int id;
BlockType type;
char label[MAX_BLOCK_LABEL];
float x, y; // 画布位置
float width, height; // 尺寸
Color color; // 颜色
BlockSlot inputs[MAX_BLOCK_INPUTS];
int input_count;
BlockSlot outputs[MAX_BLOCK_OUTPUTS];
int output_count;
struct Block* next; // 下一个积木 (堆叠)
struct Block* parent_if; // 所属 if 块 (用于子语句)
struct BlockWorkspace* workspace;
void* user_data;
} Block;
// 连接
typedef struct BlockConnection {
BlockSlot* from;
BlockSlot* to;
float points[8]; // 贝塞尔曲线控制点
} BlockConnection;
// 函数声明
Block* block_create(BlockType type, float x, float y);
void block_destroy(Block* block);
BlockSlot* block_add_input(Block* block, SlotKind kind, SlotValueType value_type, const char* label);
BlockSlot* block_add_output(Block* block, SlotKind kind, SlotValueType value_type, const char* label);
bool block_connect(BlockSlot* from, BlockSlot* to);
void block_disconnect(BlockSlot* slot);
SlotValue block_slot_get_value(BlockSlot* slot);
void block_slot_set_value(BlockSlot* slot, SlotValue value);
bool block_contains_point(Block* block, float px, float py);
void block_slot_world_pos(BlockSlot* slot, float* wx, float* wy);
+225
View File
@@ -0,0 +1,225 @@
// ============================================================================
// block_editor.c - 编辑器主界面实现
// ============================================================================
#include "block_editor.h"
#include "block_types.h"
#include <stdlib.h>
#include <string.h>
int block_editor_init(BlockEditor* editor, void* device, void* context, int width, int height) {
memset(editor, 0, sizeof(BlockEditor));
editor->width = width;
editor->height = height;
editor->toolbar_height = 30;
editor->properties_width = 200;
editor->visible = 0;
// 创建工作区
editor->workspace = workspace_create();
if (!editor->workspace) return 0;
// 初始化渲染器
if (!block_renderer_init(&editor->renderer, device, context)) {
workspace_destroy(editor->workspace);
return 0;
}
// 初始化交互
interaction_init(&editor->interaction);
// 初始化面板
palette_init(&editor->palette);
editor->palette.x = 0;
editor->palette.y = editor->toolbar_height;
// 创建执行器
editor->executor = executor_create(editor->workspace);
return 1;
}
void block_editor_shutdown(BlockEditor* editor) {
if (editor->executor) executor_destroy(editor->executor);
block_renderer_shutdown(&editor->renderer);
if (editor->workspace) workspace_destroy(editor->workspace);
}
void block_editor_show(BlockEditor* editor) {
editor->visible = 1;
}
void block_editor_hide(BlockEditor* editor) {
editor->visible = 0;
}
int block_editor_is_visible(BlockEditor* editor) {
return editor->visible;
}
void block_editor_update(BlockEditor* editor, double delta_time) {
if (!editor->visible) return;
// 更新交互
interaction_update(&editor->interaction, editor->workspace);
// 更新执行器
if (editor->executor->state == EXEC_RUNNING) {
executor_update(editor->executor, delta_time);
}
}
void block_editor_render(BlockEditor* editor) {
if (!editor->visible) return;
block_renderer_begin(&editor->renderer);
// 绘制工具栏
block_renderer_add_quad(&editor->renderer, 0, 0, (float)editor->width, (float)editor->toolbar_height,
0.2f, 0.2f, 0.25f, 1.0f);
block_renderer_draw_text(&editor->renderer, "积木编辑器", 5, 5, 1.0f, 1.0f, 1.0f);
// 绘制面板
palette_render(&editor->palette, &editor->renderer);
// 绘制工作区积木
float ws_x = editor->palette.width;
float ws_y = editor->toolbar_height;
float ws_w = (float)editor->width - editor->palette.width - editor->properties_width;
float ws_h = (float)editor->height - editor->toolbar_height;
// 工作区背景
block_renderer_add_quad(&editor->renderer, ws_x, ws_y, ws_w, ws_h,
0.12f, 0.12f, 0.15f, 1.0f);
// 绘制连接线
for (int i = 0; i < editor->workspace->connection_count; i++) {
BlockConnection* conn = &editor->workspace->connections[i];
if (conn->from && conn->to) {
block_renderer_draw_connection(&editor->renderer, conn->from, conn->to,
editor->workspace->view_x, editor->workspace->view_y, editor->workspace->zoom);
}
}
// 绘制积木
for (int i = 0; i < editor->workspace->block_count; i++) {
Block* block = editor->workspace->blocks[i];
block_renderer_draw_block(&editor->renderer, block,
editor->workspace->view_x, editor->workspace->view_y, editor->workspace->zoom);
// 高亮选中的积木
if (block == editor->workspace->selected_block) {
float x = (block->x - editor->workspace->view_x) * editor->workspace->zoom;
float y = (block->y - editor->workspace->view_y) * editor->workspace->zoom;
float w = block->width * editor->workspace->zoom;
float h = block->height * editor->workspace->zoom;
block_renderer_add_quad(&editor->renderer, x - 2, y - 2, w + 4, h + 4,
1.0f, 1.0f, 0.0f, 0.3f);
}
}
// 绘制正在拖拽的连接线
if (editor->interaction.connecting_from) {
float x1, y1;
block_slot_world_pos(editor->interaction.connecting_from, &x1, &y1);
x1 = (x1 - editor->workspace->view_x) * editor->workspace->zoom;
y1 = (y1 - editor->workspace->view_y) * editor->workspace->zoom;
float x2 = (float)editor->interaction.mouse_x;
float y2 = (float)editor->interaction.mouse_y;
block_renderer_add_line(&editor->renderer, x1, y1, x2, y2, 1.0f, 1.0f, 0.0f, 0.8f);
}
block_renderer_end(&editor->renderer);
}
void block_editor_on_mouse_move(BlockEditor* editor, int x, int y) {
if (!editor->visible) return;
interaction_mouse_move(&editor->interaction, editor->workspace, x, y);
}
void block_editor_on_mouse_down(BlockEditor* editor, int button) {
if (!editor->visible) return;
int x = editor->interaction.mouse_x;
int y = editor->interaction.mouse_y;
// 检查面板点击
if (x < editor->palette.width && y >= editor->toolbar_height) {
BlockType type = palette_handle_click(&editor->palette, (float)x, (float)y);
if (type >= 0) {
block_editor_create_block_from_palette(editor, type, 300, 100);
}
return;
}
interaction_mouse_down(&editor->interaction, editor->workspace, button);
}
void block_editor_on_mouse_up(BlockEditor* editor, int button) {
if (!editor->visible) return;
interaction_mouse_up(&editor->interaction, editor->workspace, button);
}
void block_editor_on_mouse_wheel(BlockEditor* editor, int delta) {
if (!editor->visible) return;
interaction_mouse_wheel(&editor->interaction, editor->workspace, delta);
}
void block_editor_on_key(BlockEditor* editor, int key) {
if (!editor->visible) return;
interaction_key_down(&editor->interaction, editor->workspace, key);
}
void block_editor_on_resize(BlockEditor* editor, int width, int height) {
editor->width = width;
editor->height = height;
}
void block_editor_create_block_from_palette(BlockEditor* editor, BlockType type, float x, float y) {
Block* block = block_create(type, x, y);
if (!block) return;
const BlockTypeInfo* info = block_type_get_info(type);
if (info) {
strncpy(block->label, info->label, MAX_BLOCK_LABEL - 1);
// 创建输入槽位
for (int i = 0; i < info->input_count; i++) {
block_add_input(block,
i == 0 ? SLOT_STATEMENT : SLOT_VALUE,
info->input_types[i],
info->input_labels[i]);
}
// 创建输出槽位
for (int i = 0; i < info->output_count; i++) {
block_add_output(block,
info->output_types[i] == SLOT_VALUE_ANY ? SLOT_STATEMENT : SLOT_VALUE,
info->output_types[i],
info->output_labels[i]);
}
}
workspace_add_block(editor->workspace, block);
}
int block_editor_save(BlockEditor* editor, const char* filepath) {
return serializer_save(editor->workspace, filepath);
}
int block_editor_load(BlockEditor* editor, const char* filepath) {
return serializer_load(editor->workspace, filepath);
}
void block_editor_run(BlockEditor* editor) {
executor_start(editor->executor);
}
void block_editor_stop(BlockEditor* editor) {
executor_stop(editor->executor);
}
void block_editor_pause(BlockEditor* editor) {
executor_pause(editor->executor);
}
+63
View File
@@ -0,0 +1,63 @@
#pragma once
// ============================================================================
// block_editor.h - 编辑器主界面
// ============================================================================
#include "block_workspace.h"
#include "block_renderer.h"
#include "block_interaction.h"
#include "block_palette.h"
#include "block_executor.h"
#include "block_serializer.h"
typedef struct BlockEditor {
BlockWorkspace* workspace;
BlockRenderer renderer;
BlockInteraction interaction;
BlockPalette palette;
BlockExecutor* executor;
int width, height;
int visible;
// 工具栏
int toolbar_height;
// 属性面板
int properties_width;
Block* selected_block;
} BlockEditor;
// 初始化/销毁
int block_editor_init(BlockEditor* editor, void* device, void* context, int width, int height);
void block_editor_shutdown(BlockEditor* editor);
// 显示/隐藏
void block_editor_show(BlockEditor* editor);
void block_editor_hide(BlockEditor* editor);
int block_editor_is_visible(BlockEditor* editor);
// 更新/渲染
void block_editor_update(BlockEditor* editor, double delta_time);
void block_editor_render(BlockEditor* editor);
// 输入处理
void block_editor_on_mouse_move(BlockEditor* editor, int x, int y);
void block_editor_on_mouse_down(BlockEditor* editor, int button);
void block_editor_on_mouse_up(BlockEditor* editor, int button);
void block_editor_on_mouse_wheel(BlockEditor* editor, int delta);
void block_editor_on_key(BlockEditor* editor, int key);
void block_editor_on_resize(BlockEditor* editor, int width, int height);
// 从面板拖拽创建积木
void block_editor_create_block_from_palette(BlockEditor* editor, BlockType type, float x, float y);
// 保存/加载
int block_editor_save(BlockEditor* editor, const char* filepath);
int block_editor_load(BlockEditor* editor, const char* filepath);
// 运行控制
void block_editor_run(BlockEditor* editor);
void block_editor_stop(BlockEditor* editor);
void block_editor_pause(BlockEditor* editor);
+191
View File
@@ -0,0 +1,191 @@
// ============================================================================
// block_executor.c - 积木执行引擎实现
// ============================================================================
#include "block_executor.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
BlockExecutor* executor_create(BlockWorkspace* ws) {
BlockExecutor* exec = (BlockExecutor*)calloc(1, sizeof(BlockExecutor));
if (!exec) return NULL;
exec->workspace = ws;
return exec;
}
void executor_destroy(BlockExecutor* exec) {
free(exec);
}
void executor_start(BlockExecutor* exec) {
exec->state = EXEC_RUNNING;
exec->call_stack_top = 0;
exec->current_block = NULL;
// 找到 on_start 事件积木
for (int i = 0; i < exec->workspace->block_count; i++) {
Block* block = exec->workspace->blocks[i];
if (block->type == BLOCK_EVENT_START) {
exec->current_block = block;
break;
}
}
}
void executor_stop(BlockExecutor* exec) {
exec->state = EXEC_IDLE;
exec->current_block = NULL;
}
void executor_pause(BlockExecutor* exec) {
if (exec->state == EXEC_RUNNING) {
exec->state = EXEC_PAUSED;
}
}
void executor_resume(BlockExecutor* exec) {
if (exec->state == EXEC_PAUSED) {
exec->state = EXEC_RUNNING;
}
}
void executor_step(BlockExecutor* exec) {
if (!exec->current_block) return;
// 执行当前积木
Block* current = exec->current_block;
Block* next = NULL;
switch (current->type) {
case BLOCK_EVENT_START:
case BLOCK_EVENT_UPDATE:
// 执行语句输出连接的积木
if (current->output_count > 0) {
BlockSlot* out = &current->outputs[0];
if (out->connected && out->connected->owner) {
next = out->connected->owner;
}
}
break;
case BLOCK_ACTION_MOVE:
// 获取参数
if (current->input_count >= 4) {
SlotValue x = block_slot_get_value(&current->inputs[1]);
SlotValue y = block_slot_get_value(&current->inputs[2]);
SlotValue z = block_slot_get_value(&current->inputs[3]);
// TODO: 实际移动物体
}
next = current->next;
break;
case BLOCK_CONTROL_IF:
if (current->input_count >= 2) {
SlotValue cond = block_slot_get_value(&current->inputs[1]);
if (cond.as.boolean) {
// 执行 Then 分支
if (current->output_count > 0) {
BlockSlot* out = &current->outputs[0];
if (out->connected && out->connected->owner) {
next = out->connected->owner;
}
}
} else {
// 执行 Else 分支
if (current->output_count > 1) {
BlockSlot* out = &current->outputs[1];
if (out->connected && out->connected->owner) {
next = out->connected->owner;
}
}
}
}
break;
case BLOCK_OP_ADD:
if (current->input_count >= 2) {
SlotValue a = block_slot_get_value(&current->inputs[0]);
SlotValue b = block_slot_get_value(&current->inputs[1]);
SlotValue result;
result.type = SLOT_VALUE_NUMBER;
result.as.number = a.as.number + b.as.number;
if (current->output_count > 0) {
current->outputs[0].value = result;
}
}
break;
case BLOCK_VAR_SET:
if (current->input_count >= 2) {
SlotValue val = block_slot_get_value(&current->inputs[1]);
// TODO: 获取变量名
}
next = current->next;
break;
default:
next = current->next;
break;
}
exec->current_block = next;
if (!exec->current_block) {
exec->state = EXEC_IDLE;
}
}
void executor_update(BlockExecutor* exec, double delta_time) {
if (exec->state != EXEC_RUNNING) return;
// 处理等待
if (exec->state == EXEC_WAITING) {
exec->wait_timer -= delta_time;
if (exec->wait_timer <= 0) {
exec->state = EXEC_RUNNING;
}
return;
}
// 执行多步以避免卡顿
int steps = 0;
while (exec->current_block && steps < 100) {
executor_step(exec);
steps++;
}
}
void executor_set_variable(BlockExecutor* exec, const char* name, SlotValue value) {
// 查找现有变量
for (int i = 0; i < exec->variable_count; i++) {
if (strcmp(exec->variables[i].name, name) == 0) {
exec->variables[i].value = value;
return;
}
}
// 创建新变量
if (exec->variable_count < MAX_VARIABLES) {
Variable* var = &exec->variables[exec->variable_count++];
strncpy(var->name, name, 63);
var->value = value;
var->used = 1;
}
}
SlotValue executor_get_variable(BlockExecutor* exec, const char* name) {
for (int i = 0; i < exec->variable_count; i++) {
if (strcmp(exec->variables[i].name, name) == 0) {
return exec->variables[i].value;
}
}
SlotValue empty = {0};
return empty;
}
void executor_create_variable(BlockExecutor* exec, const char* name) {
SlotValue val = {0};
val.type = SLOT_VALUE_NUMBER;
val.as.number = 0;
executor_set_variable(exec, name, val);
}
+70
View File
@@ -0,0 +1,70 @@
#pragma once
// ============================================================================
// block_executor.h - 积木执行引擎
// ============================================================================
#include "block_workspace.h"
#define MAX_VARIABLES 256
#define MAX_CALL_STACK 32
#define MAX_EXEC_STACK 1024
// 变量
typedef struct {
char name[64];
SlotValue value;
int used;
} Variable;
// 调用帧
typedef struct {
Block* block;
Block* return_block;
} CallFrame;
// 执行状态
typedef enum {
EXEC_IDLE = 0,
EXEC_RUNNING,
EXEC_WAITING,
EXEC_PAUSED,
EXEC_ERROR
} ExecState;
// 执行器
typedef struct BlockExecutor {
BlockWorkspace* workspace;
ExecState state;
Variable variables[MAX_VARIABLES];
int variable_count;
CallFrame call_stack[MAX_CALL_STACK];
int call_stack_top;
Block* current_block;
double wait_timer;
int breakpoint_enabled;
Block* breakpoint_block;
} BlockExecutor;
// 初始化/销毁
BlockExecutor* executor_create(BlockWorkspace* ws);
void executor_destroy(BlockExecutor* exec);
// 控制
void executor_start(BlockExecutor* exec);
void executor_stop(BlockExecutor* exec);
void executor_pause(BlockExecutor* exec);
void executor_resume(BlockExecutor* exec);
void executor_step(BlockExecutor* exec);
// 更新 (每帧调用)
void executor_update(BlockExecutor* exec, double delta_time);
// 变量操作
void executor_set_variable(BlockExecutor* exec, const char* name, SlotValue value);
SlotValue executor_get_variable(BlockExecutor* exec, const char* name);
void executor_create_variable(BlockExecutor* exec, const char* name);
+137
View File
@@ -0,0 +1,137 @@
// ============================================================================
// block_interaction.c - 交互系统实现
// ============================================================================
#include "block_interaction.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <Windows.h>
void interaction_init(BlockInteraction* inter) {
memset(inter, 0, sizeof(BlockInteraction));
}
void interaction_mouse_move(BlockInteraction* inter, BlockWorkspace* ws, int x, int y) {
inter->mouse_x = x;
inter->mouse_y = y;
// 拖拽积木
if (inter->dragging_block) {
float wx, wy;
workspace_screen_to_world(ws, (float)x, (float)y, &wx, &wy);
inter->dragging_block->x = wx - inter->drag_offset_x;
inter->dragging_block->y = wy - inter->drag_offset_y;
}
// 平移画布
if (inter->panning) {
float dx = (x - inter->pan_start_x) / ws->zoom;
float dy = (y - inter->pan_start_y) / ws->zoom;
ws->view_x = inter->view_start_x - dx;
ws->view_y = inter->view_start_y - dy;
}
}
void interaction_mouse_down(BlockInteraction* inter, BlockWorkspace* ws, int button) {
inter->mouse_down = 1;
inter->mouse_button = button;
float wx, wy;
workspace_screen_to_world(ws, (float)inter->mouse_x, (float)inter->mouse_y, &wx, &wy);
if (button == 0) { // 左键
// 检查是否点击槽位
BlockSlot* slot = workspace_find_slot_at(ws, wx, wy);
if (slot) {
// 开始连接
inter->connecting_from = slot;
inter->connect_start_x = wx;
inter->connect_start_y = wy;
return;
}
// 检查是否点击积木
Block* block = workspace_find_block_at(ws, wx, wy);
if (block) {
inter->dragging_block = block;
inter->drag_offset_x = wx - block->x;
inter->drag_offset_y = wy - block->y;
inter->selected_block = block;
ws->selected_block = block;
return;
}
// 点击空白区域: 取消选择
inter->selected_block = NULL;
ws->selected_block = NULL;
}
if (button == 1 || button == 2) { // 右键/中键: 平移
inter->panning = 1;
inter->pan_start_x = (float)inter->mouse_x;
inter->pan_start_y = (float)inter->mouse_y;
inter->view_start_x = ws->view_x;
inter->view_start_y = ws->view_y;
}
}
void interaction_mouse_up(BlockInteraction* inter, BlockWorkspace* ws, int button) {
inter->mouse_down = 0;
if (button == 0) {
// 结束拖拽积木
inter->dragging_block = NULL;
// 结束连接
if (inter->connecting_from) {
float wx, wy;
workspace_screen_to_world(ws, (float)inter->mouse_x, (float)inter->mouse_y, &wx, &wy);
BlockSlot* target = workspace_find_slot_at(ws, wx, wy);
if (target && target != inter->connecting_from) {
// 尝试建立连接
workspace_add_connection(ws, inter->connecting_from, target);
}
inter->connecting_from = NULL;
}
}
if (button == 1 || button == 2) {
inter->panning = 0;
}
}
void interaction_key_down(BlockInteraction* inter, BlockWorkspace* ws, int key) {
inter->key = key;
inter->key_pressed = 1;
// 删除选中的积木
if (key == 46 || key == 8) { // DELETE 或 BACKSPACE
if (inter->selected_block) {
workspace_remove_block(ws, inter->selected_block->id);
inter->selected_block = NULL;
ws->selected_block = NULL;
}
}
// 复制/粘贴 (Ctrl+C / Ctrl+V)
if (key == 'C' && (GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
// TODO: 复制到剪贴板
}
if (key == 'V' && (GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
// TODO: 从剪贴板粘贴
}
}
void interaction_mouse_wheel(BlockInteraction* inter, BlockWorkspace* ws, int delta) {
float zoom_factor = delta > 0 ? 1.1f : 0.9f;
ws->zoom *= zoom_factor;
if (ws->zoom < 0.25f) ws->zoom = 0.25f;
if (ws->zoom > 4.0f) ws->zoom = 4.0f;
}
void interaction_update(BlockInteraction* inter, BlockWorkspace* ws) {
inter->key_pressed = 0;
(void)ws;
}
+44
View File
@@ -0,0 +1,44 @@
#pragma once
// ============================================================================
// block_interaction.h - 交互系统
// ============================================================================
#include "block_workspace.h"
typedef struct {
int mouse_x, mouse_y;
int mouse_down;
int mouse_button; // 0=left, 1=right, 2=middle
int key;
int key_pressed;
// 拖拽状态
Block* dragging_block;
float drag_offset_x, drag_offset_y;
// 连接状态
BlockSlot* connecting_from;
float connect_start_x, connect_start_y;
// 选择状态
Block* selected_block;
// 平移状态
int panning;
float pan_start_x, pan_start_y;
float view_start_x, view_start_y;
} BlockInteraction;
// 初始化
void interaction_init(BlockInteraction* inter);
// 处理输入事件
void interaction_mouse_move(BlockInteraction* inter, BlockWorkspace* ws, int x, int y);
void interaction_mouse_down(BlockInteraction* inter, BlockWorkspace* ws, int button);
void interaction_mouse_up(BlockInteraction* inter, BlockWorkspace* ws, int button);
void interaction_key_down(BlockInteraction* inter, BlockWorkspace* ws, int key);
void interaction_mouse_wheel(BlockInteraction* inter, BlockWorkspace* ws, int delta);
// 更新 (每帧调用)
void interaction_update(BlockInteraction* inter, BlockWorkspace* ws);
+140
View File
@@ -0,0 +1,140 @@
// ============================================================================
// block_palette.c - 积木面板实现
// ============================================================================
#include "block_palette.h"
#include "block_renderer.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void palette_init(BlockPalette* palette) {
memset(palette, 0, sizeof(BlockPalette));
palette->width = 200;
palette->height = 600;
// 添加所有积木类型
int count;
const BlockTypeInfo* all = block_type_get_all(&count);
for (int i = 0; i < count; i++) {
palette_add_block(palette, all[i].type);
}
}
void palette_add_block(BlockPalette* palette, BlockType type) {
const BlockTypeInfo* info = block_type_get_info(type);
if (!info) return;
// 查找或创建分类
for (int i = 0; i < palette->category_count; i++) {
if (strcmp(palette->categories[i].name, info->category) == 0) {
palette->categories[i].blocks[palette->categories[i].block_count++] = type;
return;
}
}
// 创建新分类
if (palette->category_count < MAX_PALETTE_CATEGORIES) {
PaletteCategory* cat = &palette->categories[palette->category_count++];
strncpy(cat->name, info->category, 63);
cat->blocks[cat->block_count++] = type;
cat->expanded = 1;
}
}
void palette_render(BlockPalette* palette, BlockRenderer* renderer) {
// 绘制背景
block_renderer_add_quad(renderer, palette->x, palette->y, palette->width, palette->height,
0.15f, 0.15f, 0.18f, 1.0f);
// 绘制标题
block_renderer_draw_text(renderer, "积木面板", palette->x + 5, palette->y + 5,
1.0f, 1.0f, 1.0f);
float y = palette->y + 25 - palette->scroll_y;
for (int c = 0; c < palette->category_count; c++) {
PaletteCategory* cat = &palette->categories[c];
// 绘制分类标题
block_renderer_add_quad(renderer, palette->x + 2, y, palette->width - 4, 20,
0.25f, 0.25f, 0.3f, 1.0f);
const char* arrow = cat->expanded ? "[-]" : "[+]";
char title[128];
snprintf(title, 128, "%s %s (%d)", arrow, cat->name, cat->block_count);
block_renderer_draw_text(renderer, title, palette->x + 5, y + 3,
0.9f, 0.9f, 0.9f);
y += 22;
if (!cat->expanded) continue;
// 绘制积木列表
for (int b = 0; b < cat->block_count; b++) {
const BlockTypeInfo* info = block_type_get_info(cat->blocks[b]);
if (!info) continue;
// 搜索过滤
if (palette->search_active && palette->search_text[0]) {
if (strstr(info->name, palette->search_text) == NULL &&
strstr(info->label, palette->search_text) == NULL) {
continue;
}
}
// 绘制积木预览
block_renderer_add_quad(renderer, palette->x + 5, y, palette->width - 10, 18,
info->color.r, info->color.g, info->color.b, info->color.a);
block_renderer_draw_text(renderer, info->label, palette->x + 10, y + 3,
1.0f, 1.0f, 1.0f);
y += 20;
}
y += 5;
}
}
BlockType palette_handle_click(BlockPalette* palette, float mx, float my) {
float y = palette->y + 25 - palette->scroll_y;
for (int c = 0; c < palette->category_count; c++) {
PaletteCategory* cat = &palette->categories[c];
// 检查分类标题点击
if (mx >= palette->x && mx <= palette->x + palette->width &&
my >= y && my <= y + 20) {
cat->expanded = !cat->expanded;
return -1;
}
y += 22;
if (!cat->expanded) continue;
// 检查积木点击
for (int b = 0; b < cat->block_count; b++) {
if (mx >= palette->x + 5 && mx <= palette->x + palette->width - 5 &&
my >= y && my <= y + 18) {
return cat->blocks[b];
}
y += 20;
}
y += 5;
}
return -1;
}
void palette_search(BlockPalette* palette, const char* text) {
if (text) {
strncpy(palette->search_text, text, 127);
palette->search_active = 1;
} else {
palette->search_text[0] = '\0';
palette->search_active = 0;
}
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
// ============================================================================
// block_palette.h - 积木面板
// ============================================================================
#include "block_types.h"
#include "block_workspace.h"
#define MAX_PALETTE_CATEGORIES 16
typedef struct {
char name[64];
BlockType blocks[64];
int block_count;
int expanded;
} PaletteCategory;
typedef struct BlockPalette {
PaletteCategory categories[MAX_PALETTE_CATEGORIES];
int category_count;
float x, y, width, height;
float scroll_y;
char search_text[128];
int search_active;
} BlockPalette;
// 初始化
void palette_init(BlockPalette* palette);
// 添加积木到面板 (按分类)
void palette_add_block(BlockPalette* palette, BlockType type);
struct BlockRenderer;
void palette_render(BlockPalette* palette, struct BlockRenderer* renderer);
// 处理点击
BlockType palette_handle_click(BlockPalette* palette, float mx, float my);
// 搜索
void palette_search(BlockPalette* palette, const char* text);
+142
View File
@@ -0,0 +1,142 @@
#include "block_renderer.h"
#include "block_core.h"
#include <stdlib.h>
#include <string.h>
int block_renderer_init(BlockRenderer* renderer, void* device, void* context) {
memset(renderer, 0, sizeof(BlockRenderer));
renderer->device = (ID3D11Device*)device;
renderer->context = (ID3D11DeviceContext*)context;
renderer->vertex_capacity = 65536;
renderer->vertex_data = (float*)malloc(renderer->vertex_capacity * 7 * sizeof(float));
renderer->index_capacity = 65536;
renderer->index_data = (uint32_t*)malloc(renderer->index_capacity * sizeof(uint32_t));
return 1;
}
void block_renderer_shutdown(BlockRenderer* renderer) {
if (renderer->vertex_data) free(renderer->vertex_data);
if (renderer->index_data) free(renderer->index_data);
if (renderer->vertex_buffer) renderer->vertex_buffer->lpVtbl->Release(renderer->vertex_buffer);
if (renderer->index_buffer) renderer->index_buffer->lpVtbl->Release(renderer->index_buffer);
if (renderer->vertex_shader) renderer->vertex_shader->lpVtbl->Release(renderer->vertex_shader);
if (renderer->pixel_shader) renderer->pixel_shader->lpVtbl->Release(renderer->pixel_shader);
if (renderer->input_layout) renderer->input_layout->lpVtbl->Release(renderer->input_layout);
memset(renderer, 0, sizeof(BlockRenderer));
}
void block_renderer_begin(BlockRenderer* renderer) {
renderer->vertex_count = 0;
renderer->index_count = 0;
}
void block_renderer_end(BlockRenderer* renderer) {
if (renderer->vertex_count == 0) return;
ID3D11DeviceContext* ctx = renderer->context;
D3D11_MAPPED_SUBRESOURCE mapped;
if (SUCCEEDED(ctx->lpVtbl->Map(ctx, (ID3D11Resource*)renderer->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) {
memcpy(mapped.pData, renderer->vertex_data, renderer->vertex_count * 7 * sizeof(float));
ctx->lpVtbl->Unmap(ctx, (ID3D11Resource*)renderer->vertex_buffer, 0);
}
if (renderer->index_count > 0) {
if (SUCCEEDED(ctx->lpVtbl->Map(ctx, (ID3D11Resource*)renderer->index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) {
memcpy(mapped.pData, renderer->index_data, renderer->index_count * sizeof(uint32_t));
ctx->lpVtbl->Unmap(ctx, (ID3D11Resource*)renderer->index_buffer, 0);
}
}
UINT stride = 7 * sizeof(float);
UINT offset = 0;
ID3D11Buffer* vb = renderer->vertex_buffer;
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &vb, &stride, &offset);
if (renderer->index_buffer) {
ctx->lpVtbl->IASetIndexBuffer(ctx, renderer->index_buffer, DXGI_FORMAT_R32_UINT, 0);
}
ctx->lpVtbl->IASetInputLayout(ctx, renderer->input_layout);
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->lpVtbl->VSSetShader(ctx, renderer->vertex_shader, NULL, 0);
ctx->lpVtbl->PSSetShader(ctx, renderer->pixel_shader, NULL, 0);
if (renderer->index_count > 0) {
ctx->lpVtbl->DrawIndexed(ctx, renderer->index_count, 0, 0);
} else {
ctx->lpVtbl->Draw(ctx, renderer->vertex_count, 0);
}
}
void block_renderer_add_quad(BlockRenderer* renderer, float x, float y, float w, float h, float r, float g, float b, float a) {
if (renderer->vertex_count + 4 > renderer->vertex_capacity) return;
if (renderer->index_count + 6 > renderer->index_capacity) return;
uint32_t base = renderer->vertex_count;
float* v = renderer->vertex_data + base * 7;
v[0*7+0] = x; v[0*7+1] = y; v[0*7+2] = 0; v[0*7+3] = r; v[0*7+4] = g; v[0*7+5] = b; v[0*7+6] = a;
v[1*7+0] = x + w; v[1*7+1] = y; v[1*7+2] = 0; v[1*7+3] = r; v[1*7+4] = g; v[1*7+5] = b; v[1*7+6] = a;
v[2*7+0] = x + w; v[2*7+1] = y + h; v[2*7+2] = 0; v[2*7+3] = r; v[2*7+4] = g; v[2*7+5] = b; v[2*7+6] = a;
v[3*7+0] = x; v[3*7+1] = y + h; v[3*7+2] = 0; v[3*7+3] = r; v[3*7+4] = g; v[3*7+5] = b; v[3*7+6] = a;
renderer->vertex_count += 4;
renderer->index_data[renderer->index_count++] = base + 0;
renderer->index_data[renderer->index_count++] = base + 1;
renderer->index_data[renderer->index_count++] = base + 2;
renderer->index_data[renderer->index_count++] = base + 0;
renderer->index_data[renderer->index_count++] = base + 2;
renderer->index_data[renderer->index_count++] = base + 3;
}
void block_renderer_add_line(BlockRenderer* renderer, float x1, float y1, float x2, float y2, float r, float g, float b, float a) {
float dx = x2 - x1;
float dy = y2 - y1;
float len = sqrtf(dx * dx + dy * dy);
if (len < 0.001f) return;
float nx = -dy / len;
float ny = dx / len;
block_renderer_add_quad(renderer, x1, y1, x2 - x1, y2 - y1, r, g, b, a);
}
static void block_renderer_add_bezier(BlockRenderer* renderer, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, float r, float g, float b, float a) {
int segments = 16;
float prev_x = x1, prev_y = y1;
for (int i = 1; i <= segments; i++) {
float t = (float)i / segments;
float mt = 1.0f - t;
float px = mt*mt*mt*x1 + 3*mt*mt*t*cx1 + 3*mt*t*t*cx2 + t*t*t*x2;
float py = mt*mt*mt*y1 + 3*mt*mt*t*cy1 + 3*mt*t*t*cy2 + t*t*t*y2;
block_renderer_add_line(renderer, prev_x, prev_y, px, py, r, g, b, a);
prev_x = px;
prev_y = py;
}
}
void block_renderer_draw_block(BlockRenderer* renderer, Block* block, float view_x, float view_y, float zoom) {
float x = (block->x - view_x) * zoom;
float y = (block->y - view_y) * zoom;
float w = block->width * zoom;
float h = block->height * zoom;
block_renderer_add_quad(renderer, x, y, w, h, 0.3f, 0.3f, 0.35f, 1.0f);
block_renderer_add_quad(renderer, x, y, w, 20 * zoom, 0.2f, 0.2f, 0.25f, 1.0f);
}
void block_renderer_draw_connection(BlockRenderer* renderer, BlockSlot* from, BlockSlot* to, float view_x, float view_y, float zoom) {
float x1 = (from->owner->x + from->x - view_x) * zoom;
float y1 = (from->owner->y + from->y - view_y) * zoom;
float x2 = (to->owner->x + to->x - view_x) * zoom;
float y2 = (to->owner->y + to->y - view_y) * zoom;
float dx = fabsf(x2 - x1) * 0.5f;
if (dx < 50.0f) dx = 50.0f;
block_renderer_add_bezier(renderer, x1, y1, x1 + dx, y1, x2 - dx, y2, x2, y2, 0.8f, 0.8f, 0.2f, 1.0f);
}
void block_renderer_draw_text(BlockRenderer* renderer, const char* text, float x, float y, float r, float g, float b) {
if (!text) return;
(void)renderer; (void)x; (void)y; (void)r; (void)g; (void)b;
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include "block_workspace.h"
#include <d3d11.h>
#include <stdint.h>
typedef struct BlockRenderer {
ID3D11Device* device;
ID3D11DeviceContext* context;
ID3D11Buffer* vertex_buffer;
ID3D11Buffer* index_buffer;
ID3D11VertexShader* vertex_shader;
ID3D11PixelShader* pixel_shader;
ID3D11InputLayout* input_layout;
float* vertex_data;
int vertex_count;
int vertex_capacity;
uint32_t* index_data;
int index_count;
int index_capacity;
} BlockRenderer;
int block_renderer_init(BlockRenderer* renderer, void* device, void* context);
void block_renderer_shutdown(BlockRenderer* renderer);
void block_renderer_begin(BlockRenderer* renderer);
void block_renderer_end(BlockRenderer* renderer);
void block_renderer_draw_block(BlockRenderer* renderer, Block* block, float view_x, float view_y, float zoom);
void block_renderer_draw_connection(BlockRenderer* renderer, BlockSlot* from, BlockSlot* to, float view_x, float view_y, float zoom);
void block_renderer_draw_text(BlockRenderer* renderer, const char* text, float x, float y, float r, float g, float b);
void block_renderer_add_quad(BlockRenderer* renderer, float x, float y, float w, float h, float r, float g, float b, float a);
void block_renderer_add_line(BlockRenderer* renderer, float x1, float y1, float x2, float y2, float r, float g, float b, float a);
+142
View File
@@ -0,0 +1,142 @@
// ============================================================================
// block_serializer.c - JSON 序列化实现
// ============================================================================
#include "block_serializer.h"
#include "block_types.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 简单的 JSON 生成器
typedef struct {
char* buffer;
size_t size;
size_t capacity;
} JsonBuffer;
static void json_init(JsonBuffer* buf) {
buf->capacity = 4096;
buf->buffer = (char*)malloc(buf->capacity);
buf->size = 0;
buf->buffer[0] = '\0';
}
static void json_append(JsonBuffer* buf, const char* str) {
size_t len = strlen(str);
if (buf->size + len + 1 > buf->capacity) {
buf->capacity = (buf->size + len + 1) * 2;
buf->buffer = (char*)realloc(buf->buffer, buf->capacity);
}
memcpy(buf->buffer + buf->size, str, len + 1);
buf->size += len;
}
static void json_free(JsonBuffer* buf) {
free(buf->buffer);
buf->buffer = NULL;
buf->size = 0;
}
int serializer_save(BlockWorkspace* ws, const char* filepath) {
char* json = serializer_save_to_string(ws);
if (!json) return 0;
FILE* f = fopen(filepath, "w");
if (!f) {
free(json);
return 0;
}
fprintf(f, "%s", json);
fclose(f);
free(json);
return 1;
}
int serializer_load(BlockWorkspace* ws, const char* filepath) {
FILE* f = fopen(filepath, "r");
if (!f) return 0;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char* json = (char*)malloc(size + 1);
fread(json, 1, size, f);
json[size] = '\0';
fclose(f);
int result = serializer_load_from_string(ws, json);
free(json);
return result;
}
char* serializer_save_to_string(BlockWorkspace* ws) {
JsonBuffer buf;
json_init(&buf);
json_append(&buf, "{\n");
json_append(&buf, " \"version\": \"1.0\",\n");
// 保存积木
json_append(&buf, " \"blocks\": [\n");
for (int i = 0; i < ws->block_count; i++) {
Block* block = ws->blocks[i];
const BlockTypeInfo* info = block_type_get_info(block->type);
char tmp[256];
snprintf(tmp, 256, " {\n");
json_append(&buf, tmp);
snprintf(tmp, 256, " \"id\": %d,\n", block->id);
json_append(&buf, tmp);
snprintf(tmp, 256, " \"type\": \"%s\",\n", info ? info->name : "unknown");
json_append(&buf, tmp);
snprintf(tmp, 256, " \"x\": %.1f,\n", block->x);
json_append(&buf, tmp);
snprintf(tmp, 256, " \"y\": %.1f\n", block->y);
json_append(&buf, tmp);
json_append(&buf, i < ws->block_count - 1 ? " },\n" : " }\n");
}
json_append(&buf, " ],\n");
// 保存连接
json_append(&buf, " \"connections\": [\n");
for (int i = 0; i < ws->connection_count; i++) {
BlockConnection* conn = &ws->connections[i];
char tmp[128];
snprintf(tmp, 128, " {\"from\": %d, \"to\": %d}%s\n",
conn->from ? conn->from->owner->id : 0,
conn->to ? conn->to->owner->id : 0,
i < ws->connection_count - 1 ? "," : "");
json_append(&buf, tmp);
}
json_append(&buf, " ]\n");
json_append(&buf, "}\n");
return buf.buffer;
}
int serializer_load_from_string(BlockWorkspace* ws, const char* json_str) {
// 简化的 JSON 解析
// 完整实现需要完整的 JSON 解析器
workspace_clear(ws);
// 查找 "blocks" 数组
const char* blocks_start = strstr(json_str, "\"blocks\"");
if (!blocks_start) return 0;
// 简化解析 - 只提取基本信息
// 实际项目中应使用 cJSON 或类似库
// TODO: 实现完整的 JSON 解析
return 1;
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
// ============================================================================
// block_serializer.h - JSON 序列化
// ============================================================================
#include "block_workspace.h"
// 保存工作区到文件
int serializer_save(BlockWorkspace* ws, const char* filepath);
// 从文件加载工作区
int serializer_load(BlockWorkspace* ws, const char* filepath);
// 保存到字符串
char* serializer_save_to_string(BlockWorkspace* ws);
// 从字符串加载
int serializer_load_from_string(BlockWorkspace* ws, const char* json_str);
+326
View File
@@ -0,0 +1,326 @@
// ============================================================================
// block_types.c - 积木类型注册
// ============================================================================
#include "block_types.h"
#include <string.h>
static BlockTypeInfo g_type_info[BLOCK_TYPE_COUNT];
static int g_types_initialized = 0;
void block_types_init(void) {
if (g_types_initialized) return;
int i = 0;
// === 事件积木 (红色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_START, "event_start", "on_start", "Events",
BLOCK_COLOR_EVENT, 0, 1,
{}, {SLOT_STATEMENT},
{}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_UPDATE, "event_update", "on_update", "Events",
BLOCK_COLOR_EVENT, 0, 1,
{}, {SLOT_STATEMENT},
{}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_COLLISION, "event_collision", "on_collision", "Events",
BLOCK_COLOR_EVENT, 1, 1,
{SLOT_VALUE_STRING}, {SLOT_STATEMENT},
{"碰撞对象"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_KEY_PRESSED, "event_key", "on_key_pressed", "Events",
BLOCK_COLOR_EVENT, 1, 1,
{SLOT_VALUE_STRING}, {SLOT_STATEMENT},
{"按键"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_MOUSE_CLICK, "event_mouse", "on_mouse_click", "Events",
BLOCK_COLOR_EVENT, 0, 1,
{}, {SLOT_STATEMENT},
{}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_EVENT_TIMER, "event_timer", "on_timer", "Events",
BLOCK_COLOR_EVENT, 1, 1,
{SLOT_VALUE_NUMBER}, {SLOT_STATEMENT},
{"间隔(秒)"}, {"执行"}
};
// === 动作积木 (蓝色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_MOVE, "action_move", "move", "Actions",
BLOCK_COLOR_ACTION, 4, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "X", "Y", "Z"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_ROTATE, "action_rotate", "rotate", "Actions",
BLOCK_COLOR_ACTION, 4, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "X", "Y", "Z"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_SCALE, "action_scale", "scale", "Actions",
BLOCK_COLOR_ACTION, 4, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "X", "Y", "Z"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_SET_POSITION, "action_setpos", "set_position", "Actions",
BLOCK_COLOR_ACTION, 4, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "X", "Y", "Z"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_SET_ROTATION, "action_setrot", "set_rotation", "Actions",
BLOCK_COLOR_ACTION, 4, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "X", "Y", "Z"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_PLAY_SOUND, "action_sound", "play_sound", "Actions",
BLOCK_COLOR_ACTION, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_STRING},
{SLOT_STATEMENT},
{"执行", "音效名"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_DESTROY, "action_destroy", "destroy", "Actions",
BLOCK_COLOR_ACTION, 1, 1,
{SLOT_STATEMENT},
{SLOT_STATEMENT},
{"执行"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_ACTION_INSTANTIATE, "action_instantiate", "instantiate", "Actions",
BLOCK_COLOR_ACTION, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_STRING},
{SLOT_STATEMENT},
{"执行", "预制体"}, {"执行"}
};
// === 控制积木 (绿色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_IF, "control_if", "if", "Control",
BLOCK_COLOR_CONTROL, 2, 2,
{SLOT_STATEMENT, SLOT_VALUE_BOOLEAN},
{SLOT_STATEMENT, SLOT_STATEMENT},
{"执行", "条件"}, {"Then", "Else"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_IF_ELSE, "control_ifelse", "if_else", "Control",
BLOCK_COLOR_CONTROL, 2, 2,
{SLOT_STATEMENT, SLOT_VALUE_BOOLEAN},
{SLOT_STATEMENT, SLOT_STATEMENT},
{"执行", "条件"}, {"Then", "Else"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_REPEAT, "control_repeat", "repeat", "Control",
BLOCK_COLOR_CONTROL, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_BOOLEAN},
{SLOT_STATEMENT},
{"执行", "条件"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_REPEAT_TIMES, "control_count", "repeat_times", "Control",
BLOCK_COLOR_CONTROL, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "次数"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_WHILE, "control_while", "while", "Control",
BLOCK_COLOR_CONTROL, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_BOOLEAN},
{SLOT_STATEMENT},
{"执行", "条件"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_WAIT, "control_wait", "wait", "Control",
BLOCK_COLOR_CONTROL, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_NUMBER},
{SLOT_STATEMENT},
{"执行", "秒数"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_CONTROL_FUNCTION_DEF, "control_funcdef", "function_def", "Control",
BLOCK_COLOR_CONTROL, 1, 1,
{SLOT_STATEMENT},
{SLOT_STATEMENT},
{"执行"}, {"执行"}
};
// === 运算积木 (橙色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_ADD, "op_add", "+", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_NUMBER},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_SUB, "op_sub", "-", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_NUMBER},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_MUL, "op_mul", "*", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_NUMBER},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_DIV, "op_div", "/", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_NUMBER},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_MOD, "op_mod", "%", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_NUMBER},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_EQUALS, "op_eq", "==", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_ANY, SLOT_VALUE_ANY},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_NOT_EQUALS, "op_neq", "!=", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_ANY, SLOT_VALUE_ANY},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_GREATER, "op_gt", ">", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_LESS, "op_lt", "<", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_NUMBER, SLOT_VALUE_NUMBER},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_AND, "op_and", "AND", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_BOOLEAN, SLOT_VALUE_BOOLEAN},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_OR, "op_or", "OR", "Operators",
BLOCK_COLOR_OPERATOR, 2, 1,
{SLOT_VALUE_BOOLEAN, SLOT_VALUE_BOOLEAN},
{SLOT_VALUE_BOOLEAN},
{"A", "B"}, {"结果"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_OP_NOT, "op_not", "NOT", "Operators",
BLOCK_COLOR_OPERATOR, 1, 1,
{SLOT_VALUE_BOOLEAN},
{SLOT_VALUE_BOOLEAN},
{"A"}, {"结果"}
};
// === 变量积木 (紫色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_VAR_GET, "var_get", "get_variable", "Variables",
BLOCK_COLOR_VARIABLE, 0, 1,
{}, {SLOT_VALUE_ANY},
{}, {"值"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_VAR_SET, "var_set", "set_variable", "Variables",
BLOCK_COLOR_VARIABLE, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_ANY},
{SLOT_STATEMENT},
{"执行", "值"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_VAR_CREATE, "var_create", "create_variable", "Variables",
BLOCK_COLOR_VARIABLE, 1, 1,
{SLOT_STATEMENT},
{SLOT_STATEMENT},
{"执行"}, {"执行"}
};
// === 函数积木 (黄色) ===
g_type_info[i++] = (BlockTypeInfo){
BLOCK_FUNC_CALL, "func_call", "call_function", "Functions",
BLOCK_COLOR_FUNCTION, 2, 1,
{SLOT_STATEMENT, SLOT_VALUE_STRING},
{SLOT_STATEMENT},
{"执行", "函数名"}, {"执行"}
};
g_type_info[i++] = (BlockTypeInfo){
BLOCK_FUNC_RETURN, "func_return", "return", "Functions",
BLOCK_COLOR_FUNCTION, 2, 0,
{SLOT_STATEMENT, SLOT_VALUE_ANY},
{},
{"执行", "返回值"}
};
g_types_initialized = 1;
}
const BlockTypeInfo* block_type_get_info(BlockType type) {
if (type < 0 || type >= BLOCK_TYPE_COUNT) return NULL;
return &g_type_info[type];
}
const BlockTypeInfo* block_type_get_all(int* count) {
*count = BLOCK_TYPE_COUNT;
return g_type_info;
}
BlockType block_type_find_by_name(const char* name) {
for (int i = 0; i < BLOCK_TYPE_COUNT; i++) {
if (strcmp(g_type_info[i].name, name) == 0) {
return g_type_info[i].type;
}
}
return -1;
}
const char** block_type_get_categories(int* count) {
static const char* categories[] = {
"Events", "Actions", "Control", "Operators", "Variables", "Functions"
};
*count = 6;
return categories;
}
const BlockType* block_type_get_by_category(const char* category, int* count) {
static BlockType buffer[BLOCK_TYPE_COUNT];
*count = 0;
for (int i = 0; i < BLOCK_TYPE_COUNT; i++) {
if (strcmp(g_type_info[i].category, category) == 0) {
buffer[(*count)++] = g_type_info[i].type;
}
}
return buffer;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
// ============================================================================
// block_types.h - 积木类型定义
// ============================================================================
#include "block_core.h"
// 获取积木类型信息
const BlockTypeInfo* block_type_get_info(BlockType type);
// 获取所有类型信息
const BlockTypeInfo* block_type_get_all(int* count);
// 按名称查找类型
BlockType block_type_find_by_name(const char* name);
// 按分类获取类型列表
const BlockType* block_type_get_by_category(const char* category, int* count);
// 获取所有分类
const char** block_type_get_categories(int* count);
// 初始化所有积木类型
void block_types_init(void);
+172
View File
@@ -0,0 +1,172 @@
// ============================================================================
// block_workspace.c - 工作区管理实现
// ============================================================================
#include "block_workspace.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
BlockWorkspace* workspace_create(void) {
BlockWorkspace* ws = (BlockWorkspace*)calloc(1, sizeof(BlockWorkspace));
if (!ws) return NULL;
ws->zoom = 1.0f;
ws->next_block_id = 1;
return ws;
}
void workspace_destroy(BlockWorkspace* ws) {
if (!ws) return;
workspace_clear(ws);
free(ws);
}
int workspace_add_block(BlockWorkspace* ws, Block* block) {
if (ws->block_count >= MAX_WORKSPACE_BLOCKS) return -1;
if (!block) return -1;
block->id = ws->next_block_id++;
block->workspace = ws;
ws->blocks[ws->block_count++] = block;
return block->id;
}
void workspace_remove_block(BlockWorkspace* ws, int block_id) {
// 先移除所有相关连接
for (int i = ws->connection_count - 1; i >= 0; i--) {
BlockSlot* from = ws->connections[i].from;
BlockSlot* to = ws->connections[i].to;
if (from && from->owner && from->owner->id == block_id) {
workspace_remove_connection(ws, from);
} else if (to && to->owner && to->owner->id == block_id) {
workspace_remove_connection(ws, to);
}
}
// 移除积木
for (int i = 0; i < ws->block_count; i++) {
if (ws->blocks[i]->id == block_id) {
block_destroy(ws->blocks[i]);
ws->blocks[i] = ws->blocks[ws->block_count - 1];
ws->block_count--;
return;
}
}
}
bool workspace_add_connection(BlockWorkspace* ws, BlockSlot* from, BlockSlot* to) {
if (ws->connection_count >= MAX_WORKSPACE_CONNECTIONS) return false;
if (!from || !to) return false;
// 检查是否已连接
for (int i = 0; i < ws->connection_count; i++) {
if (ws->connections[i].from == from || ws->connections[i].to == to) {
return false; // 已有连接
}
}
// 建立连接
block_connect(from, to);
BlockConnection* conn = &ws->connections[ws->connection_count++];
conn->from = from;
conn->to = to;
return true;
}
void workspace_remove_connection(BlockWorkspace* ws, BlockSlot* slot) {
for (int i = ws->connection_count - 1; i >= 0; i--) {
if (ws->connections[i].from == slot || ws->connections[i].to == slot) {
block_disconnect(ws->connections[i].from);
ws->connections[i] = ws->connections[ws->connection_count - 1];
ws->connection_count--;
}
}
}
void workspace_remove_all_connections(BlockWorkspace* ws, Block* block) {
if (!block) return;
for (int i = ws->connection_count - 1; i >= 0; i--) {
BlockSlot* from = ws->connections[i].from;
BlockSlot* to = ws->connections[i].to;
if ((from && from->owner == block) || (to && to->owner == block)) {
block_disconnect(from);
ws->connections[i] = ws->connections[ws->connection_count - 1];
ws->connection_count--;
}
}
}
Block* workspace_find_block(BlockWorkspace* ws, int block_id) {
for (int i = 0; i < ws->block_count; i++) {
if (ws->blocks[i]->id == block_id) return ws->blocks[i];
}
return NULL;
}
Block* workspace_find_block_at(BlockWorkspace* ws, float x, float y) {
// 从后往前找 (最后添加的在最上面)
for (int i = ws->block_count - 1; i >= 0; i--) {
if (block_contains_point(ws->blocks[i], x, y)) {
return ws->blocks[i];
}
}
return NULL;
}
BlockSlot* workspace_find_slot_at(BlockWorkspace* ws, float x, float y) {
float threshold = 10.0f;
for (int i = ws->block_count - 1; i >= 0; i--) {
Block* block = ws->blocks[i];
// 检查输出槽位
for (int j = 0; j < block->output_count; j++) {
BlockSlot* slot = &block->outputs[j];
float sx, sy;
block_slot_world_pos(slot, &sx, &sy);
float dx = x - sx;
float dy = y - sy;
if (dx * dx + dy * dy < threshold * threshold) {
return slot;
}
}
// 检查输入槽位
for (int j = 0; j < block->input_count; j++) {
BlockSlot* slot = &block->inputs[j];
float sx, sy;
block_slot_world_pos(slot, &sx, &sy);
float dx = x - sx;
float dy = y - sy;
if (dx * dx + dy * dy < threshold * threshold) {
return slot;
}
}
}
return NULL;
}
void workspace_screen_to_world(BlockWorkspace* ws, float sx, float sy, float* wx, float* wy) {
*wx = (sx / ws->zoom) + ws->view_x;
*wy = (sy / ws->zoom) + ws->view_y;
}
void workspace_world_to_screen(BlockWorkspace* ws, float wx, float wy, float* sx, float* sy) {
*sx = (wx - ws->view_x) * ws->zoom;
*sy = (wy - ws->view_y) * ws->zoom;
}
void workspace_clear(BlockWorkspace* ws) {
for (int i = 0; i < ws->block_count; i++) {
block_destroy(ws->blocks[i]);
}
ws->block_count = 0;
ws->connection_count = 0;
ws->selected_block = NULL;
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
// ============================================================================
// block_workspace.h - 工作区管理
// ============================================================================
#include "block_core.h"
#define MAX_WORKSPACE_BLOCKS 1024
#define MAX_WORKSPACE_CONNECTIONS 2048
typedef struct BlockWorkspace {
Block* blocks[MAX_WORKSPACE_BLOCKS];
int block_count;
BlockConnection connections[MAX_WORKSPACE_CONNECTIONS];
int connection_count;
float view_x, view_y;
float zoom;
Block* selected_block;
BlockSlot* dragging_from;
float drag_start_x, drag_start_y;
int next_block_id;
struct BlockPalette* palette;
} BlockWorkspace;
// 创建/销毁
BlockWorkspace* workspace_create(void);
void workspace_destroy(BlockWorkspace* ws);
// 添加/移除积木
int workspace_add_block(BlockWorkspace* ws, Block* block);
void workspace_remove_block(BlockWorkspace* ws, int block_id);
// 添加/移除连接
bool workspace_add_connection(BlockWorkspace* ws, BlockSlot* from, BlockSlot* to);
void workspace_remove_connection(BlockWorkspace* ws, BlockSlot* from);
void workspace_remove_all_connections(BlockWorkspace* ws, Block* block);
// 查找
Block* workspace_find_block(BlockWorkspace* ws, int block_id);
Block* workspace_find_block_at(BlockWorkspace* ws, float x, float y);
BlockSlot* workspace_find_slot_at(BlockWorkspace* ws, float x, float y);
// 视口变换
void workspace_screen_to_world(BlockWorkspace* ws, float sx, float sy, float* wx, float* wy);
void workspace_world_to_screen(BlockWorkspace* ws, float wx, float wy, float* sx, float* sy);
// 清空
void workspace_clear(BlockWorkspace* ws);
+192
View File
@@ -0,0 +1,192 @@
// ============================================================================
// window.c - Win32 窗口实现
// ============================================================================
#include "window.h"
#include "../Core/logger.h"
#include <stdlib.h>
#include <string.h>
// 窗口类名
static const wchar_t* WINDOW_CLASS = L"MiMoEngineWindow";
// 全局回调
static WindowKeyCallback g_key_callback = NULL;
static WindowResizeCallback g_resize_callback = NULL;
static WindowMouseMoveCallback g_mouse_move_callback = NULL;
static WindowMouseButtonCallback g_mouse_button_callback = NULL;
// 窗口过程
static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
Window* window = NULL;
if (msg == WM_NCCREATE) {
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
window = (Window*)cs->lpCreateParams;
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window);
} else {
window = (Window*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
}
if (window) {
switch (msg) {
case WM_SIZE:
window->width = LOWORD(lParam);
window->height = HIWORD(lParam);
window->minimized = (wParam == SIZE_MINIMIZED);
if (g_resize_callback && !window->minimized) {
g_resize_callback(window->width, window->height);
}
return 0;
case WM_PAINT:
ValidateRect(hwnd, NULL);
return 0;
case WM_ERASEBKGND:
return 1;
case WM_KEYDOWN:
if (g_key_callback) g_key_callback((int)wParam);
return 0;
case WM_KEYUP:
return 0;
case WM_MOUSEMOVE:
if (g_mouse_move_callback) g_mouse_move_callback(LOWORD(lParam), HIWORD(lParam));
return 0;
case WM_LBUTTONDOWN:
if (g_mouse_button_callback) g_mouse_button_callback(0);
return 0;
case WM_RBUTTONDOWN:
if (g_mouse_button_callback) g_mouse_button_callback(1);
return 0;
case WM_MBUTTONDOWN:
if (g_mouse_button_callback) g_mouse_button_callback(2);
return 0;
case WM_LBUTTONUP:
if (g_mouse_button_callback) g_mouse_button_callback(0);
return 0;
case WM_RBUTTONUP:
if (g_mouse_button_callback) g_mouse_button_callback(1);
return 0;
case WM_MBUTTONUP:
if (g_mouse_button_callback) g_mouse_button_callback(2);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
// 注册窗口类
static void register_window_class(void) {
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = window_proc;
wc.hInstance = GetModuleHandleW(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszClassName = WINDOW_CLASS;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassExW(&wc)) {
LOG_ERROR("Failed to register window class!");
}
}
Window* window_create(const char* title, int width, int height, int fullscreen) {
Window* window = (Window*)calloc(1, sizeof(Window));
if (!window) return NULL;
window->title = title;
window->width = width;
window->height = height;
window->fullscreen = fullscreen;
register_window_class();
DWORD style = WS_OVERLAPPEDWINDOW;
DWORD ex_style = WS_EX_APPWINDOW;
RECT rect = {0, 0, width, height};
AdjustWindowRectEx(&rect, style, FALSE, ex_style);
int adjusted_width = rect.right - rect.left;
int adjusted_height = rect.bottom - rect.top;
int screen_w = GetSystemMetrics(SM_CXSCREEN);
int screen_h = GetSystemMetrics(SM_CYSCREEN);
int pos_x = (screen_w - adjusted_width) / 2;
int pos_y = (screen_h - adjusted_height) / 2;
// 转换标题为宽字符
wchar_t w_title[256];
MultiByteToWideChar(CP_UTF8, 0, title, -1, w_title, 256);
window->hwnd = CreateWindowExW(
ex_style, WINDOW_CLASS, w_title, style,
pos_x, pos_y, adjusted_width, adjusted_height,
NULL, NULL, GetModuleHandleW(NULL), window
);
if (!window->hwnd) {
LOG_ERROR("Failed to create window! Error: %lu", GetLastError());
free(window);
return NULL;
}
ShowWindow(window->hwnd, SW_SHOW);
UpdateWindow(window->hwnd);
LOG_INFO("Window created: %dx%d", width, height);
return window;
}
void window_destroy(Window* window) {
if (window) {
if (window->hwnd) {
DestroyWindow(window->hwnd);
window->hwnd = NULL;
}
free(window);
}
}
void window_show(Window* window) {
if (window && window->hwnd) ShowWindow(window->hwnd, SW_SHOW);
}
void window_hide(Window* window) {
if (window && window->hwnd) ShowWindow(window->hwnd, SW_HIDE);
}
int window_process_messages(Window* window) {
MSG msg = {0};
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) return 0;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 1;
}
int window_get_width(Window* window) { return window ? window->width : 0; }
int window_get_height(Window* window) { return window ? window->height : 0; }
HWND window_get_handle(Window* window) { return window ? window->hwnd : NULL; }
int window_is_fullscreen(Window* window) { return window ? window->fullscreen : 0; }
int window_is_minimized(Window* window) { return window ? window->minimized : 0; }
void window_set_key_callback(Window* window, WindowKeyCallback callback) { g_key_callback = callback; }
void window_set_resize_callback(Window* window, WindowResizeCallback callback) { g_resize_callback = callback; }
void window_set_mouse_move_callback(Window* window, WindowMouseMoveCallback callback) { g_mouse_move_callback = callback; }
void window_set_mouse_button_callback(Window* window, WindowMouseButtonCallback callback) { g_mouse_button_callback = callback; }
+47
View File
@@ -0,0 +1,47 @@
#pragma once
// ============================================================================
// window.h - Win32 窗口管理
// ============================================================================
#include <Windows.h>
// 窗口结构
typedef struct Window {
HWND hwnd;
int width;
int height;
int fullscreen;
int minimized;
const char* title;
} Window;
// 回调类型
typedef void (*WindowKeyCallback)(int key);
typedef void (*WindowResizeCallback)(int width, int height);
typedef void (*WindowMouseMoveCallback)(int x, int y);
typedef void (*WindowMouseButtonCallback)(int button);
// 创建/销毁
Window* window_create(const char* title, int width, int height, int fullscreen);
void window_destroy(Window* window);
// 显示/隐藏
void window_show(Window* window);
void window_hide(Window* window);
// 消息处理
int window_process_messages(Window* window);
// 获取属性
int window_get_width(Window* window);
int window_get_height(Window* window);
HWND window_get_handle(Window* window);
int window_is_fullscreen(Window* window);
int window_is_minimized(Window* window);
// 设置回调
void window_set_key_callback(Window* window, WindowKeyCallback callback);
void window_set_resize_callback(Window* window, WindowResizeCallback callback);
void window_set_mouse_move_callback(Window* window, WindowMouseMoveCallback callback);
void window_set_mouse_button_callback(Window* window, WindowMouseButtonCallback callback);
+145
View File
@@ -0,0 +1,145 @@
#pragma once
// ============================================================================
// engine_api.h - C-ASM 接口头文件
// 暴露所有汇编函数给 C 代码使用
// ============================================================================
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// 当 MASM 不可用时,使用 C fallback
// math_c_fallback.h 已经定义了所有数学类型和函数
// 不需要重复声明
// ============================================================================
// memory.asm - 对齐内存分配
// ============================================================================
#ifndef MATH_ASM_AVAILABLE
// 在 C fallback 模式下,这些函数已在 math_c_fallback.h 中定义
// 不需要重复声明
#else
void* mem_aligned_alloc(uint64_t size, uint64_t alignment);
void mem_aligned_free(void* ptr);
void* mem_aligned_realloc(void* ptr, uint64_t size, uint64_t alignment);
// ============================================================================
// string_ops.asm - 快速字符串操作
// ============================================================================
void fast_memcpy(void* dst, const void* src, uint64_t count);
void fast_memset(void* dst, int value, uint64_t count);
uint64_t fast_strlen(const char* str);
int fast_strcmp(const char* a, const char* b);
// ============================================================================
// profiling.asm - 性能分析
// ============================================================================
uint64_t prof_rdtsc(void);
double prof_cycles_to_ms(uint64_t cycles);
uint64_t prof_get_freq(void);
// 性能计时器结构
typedef struct {
uint64_t start;
uint64_t end;
double elapsed_ms;
} ProfTimer;
void prof_timer_start(ProfTimer* timer);
void prof_timer_stop(ProfTimer* timer);
#endif
#ifdef __cplusplus
}
#endif
// ============================================================================
// C++ 便利封装
// ============================================================================
#ifdef __cplusplus
// Vec3 运算符重载
inline Vec3 operator+(const Vec3& a, const Vec3& b) {
Vec3 result;
vec3_add(&a, &b, &result);
return result;
}
inline Vec3 operator-(const Vec3& a, const Vec3& b) {
Vec3 result;
vec3_sub(&a, &b, &result);
return result;
}
inline Vec3 operator*(const Vec3& a, float s) {
Vec3 result;
vec3_scale(&a, s, &result);
return result;
}
inline float dot(const Vec3& a, const Vec3& b) {
return vec3_dot(&a, &b);
}
inline Vec3 cross(const Vec3& a, const Vec3& b) {
Vec3 result;
vec3_cross(&a, &b, &result);
return result;
}
inline float length(const Vec3& a) {
return vec3_length(&a);
}
inline Vec3 normalize(const Vec3& a) {
Vec3 result;
vec3_normalize(&a, &result);
return result;
}
inline Vec3 lerp(const Vec3& a, const Vec3& b, float t) {
Vec3 result;
vec3_lerp(&a, &b, t, &result);
return result;
}
// Mat4 运算符重载
inline Mat4 operator*(const Mat4& a, const Mat4& b) {
Mat4 result;
mat4_multiply(&a, &b, &result);
return result;
}
inline Vec3 transformPoint(const Mat4& m, const Vec3& v) {
Vec3 result;
// 使用 vec4 乘法, w=1
Vec4 v4 = {v.x, v.y, v.z, 1.0f};
Vec4 r4;
// 简化: 逐行计算
result.x = m.m[0][0]*v.x + m.m[0][1]*v.y + m.m[0][2]*v.z + m.m[0][3];
result.y = m.m[1][0]*v.x + m.m[1][1]*v.y + m.m[1][2]*v.z + m.m[1][3];
result.z = m.m[2][0]*v.x + m.m[2][1]*v.y + m.m[2][2]*v.z + m.m[2][3];
return result;
}
// Quat 运算符重载
inline Quat operator*(const Quat& a, const Quat& b) {
Quat result;
quat_multiply(&a, &b, &result);
return result;
}
inline Vec3 rotate(const Quat& q, const Vec3& v) {
Vec3 result;
quat_rotate_vec3(&q, &v, &result);
return result;
}
#endif // __cplusplus