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

+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);