diff --git a/CMakeLists.txt b/CMakeLists.txt index 86578bf..fd50d73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,3 +61,7 @@ set_target_properties(lity3d_editor PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_ add_executable(lity3d_compat WIN32 Demo/compat_test.c) target_link_libraries(lity3d_compat ${LINK_LIBS}) set_target_properties(lity3d_compat PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) + +add_executable(ly_interpreter Demo/ly_interpreter.c) +target_link_libraries(ly_interpreter Engine d3d11 dxgi d3dcompiler ole32 oleaut32 uuid gdi32 user32 kernel32 winmm) +set_target_properties(ly_interpreter PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) diff --git a/Demo/compat_test.c b/Demo/compat_test.c index e9e5ca8..9f2d5af 100644 --- a/Demo/compat_test.c +++ b/Demo/compat_test.c @@ -76,7 +76,9 @@ static void on_render(Engine* engine) { shader_set_matrix(g_shader, ctx, (float*)&proj_t); mesh_draw(g_tri, ctx); - ctx->lpVtbl->OMSetDepthStencilState(ctx, g_no_depth, 0); + { + ctx->lpVtbl->OMSetDepthStencilState(ctx, g_no_depth, 0); + } draw_quad(ctx, sw - 200, 10, 180, 60, 1, 1, 1, 1); diff --git a/Engine/VisualScript/block_executor.c b/Engine/VisualScript/block_executor.c index 8867f52..fb2cf8d 100644 --- a/Engine/VisualScript/block_executor.c +++ b/Engine/VisualScript/block_executor.c @@ -1,11 +1,43 @@ // ============================================================================ -// block_executor.c - 积木执行引擎实现 +// block_executor.c - 积木执行引擎 (完整实现) // ============================================================================ #include "block_executor.h" +#include "block_types.h" #include #include #include +#include +#include + +// 日志回调 +typedef void (*LogCallback)(const char* msg, int level); +static LogCallback g_log_cb = NULL; + +static void log_info(const char* fmt, ...) { + char buf[512]; va_list args; va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); + if (g_log_cb) g_log_cb(buf, 0); else printf("[INFO] %s\n", buf); +} +static void log_error(const char* fmt, ...) { + char buf[512]; va_list args; va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); + if (g_log_cb) g_log_cb(buf, 2); else printf("[ERROR] %s\n", buf); +} + +void executor_set_log_callback(LogCallback cb) { g_log_cb = cb; } + +// 值辅助 +static SlotValue make_number(double v) { SlotValue v2; v2.type = SLOT_VALUE_NUMBER; v2.as.number = v; return v2; } +static SlotValue make_string(const char* s) { SlotValue v; v.type = SLOT_VALUE_STRING; strncpy(v.as.string, s, 255); return v; } +static SlotValue make_bool(int b) { SlotValue v; v.type = SLOT_VALUE_BOOLEAN; v.as.boolean = b; return v; } +static SlotValue make_vec3(float x, float y, float z) { SlotValue v; v.type = SLOT_VALUE_VECTOR3; v.as.vector3.x = x; v.as.vector3.y = y; v.as.vector3.z = z; return v; } + +// 连接追踪:获取槽位的输入值(通过连线回溯) +static SlotValue get_connected_value(BlockSlot* slot) { + if (slot->connected) return slot->connected->value; + return slot->value; +} BlockExecutor* executor_create(BlockWorkspace* ws) { BlockExecutor* exec = (BlockExecutor*)calloc(1, sizeof(BlockExecutor)); @@ -14,157 +46,331 @@ BlockExecutor* executor_create(BlockWorkspace* ws) { return exec; } -void executor_destroy(BlockExecutor* exec) { - free(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; + log_info("执行器启动: 找到 on_start 事件"); + return; } } -} - -void executor_stop(BlockExecutor* exec) { + log_error("未找到 on_start 事件积木"); exec->state = EXEC_IDLE; - exec->current_block = NULL; } -void executor_pause(BlockExecutor* exec) { - if (exec->state == EXEC_RUNNING) { - exec->state = EXEC_PAUSED; - } +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; } + +// 获取下一个执行的积木(通过输出端口连接) +static Block* next_from_output(Block* block, int output_index) { + if (output_index >= block->output_count) return NULL; + BlockSlot* out = &block->outputs[output_index]; + if (out->connected && out->connected->owner) return out->connected->owner; + return NULL; } -void executor_resume(BlockExecutor* exec) { - if (exec->state == EXEC_PAUSED) { - exec->state = EXEC_RUNNING; - } +// 获取值输入 +static SlotValue get_input(Block* block, int idx) { + if (idx >= block->input_count) return make_number(0); + return get_connected_value(&block->inputs[idx]); } void executor_step(BlockExecutor* exec) { - if (!exec->current_block) return; - - // 执行当前积木 - Block* current = exec->current_block; + if (!exec->current_block) { exec->state = EXEC_IDLE; return; } + Block* cur = exec->current_block; Block* next = NULL; - - switch (current->type) { + + switch (cur->type) { + // === 事件 === case BLOCK_EVENT_START: case BLOCK_EVENT_UPDATE: - // 执行语句输出连接的积木 - if (current->output_count > 0) { - BlockSlot* out = ¤t->outputs[0]; - if (out->connected && out->connected->owner) { - next = out->connected->owner; - } - } + case BLOCK_EVENT_COLLISION: + case BLOCK_EVENT_MOUSE_CLICK: + next = next_from_output(cur, 0); break; - - case BLOCK_ACTION_MOVE: - // 获取参数 - if (current->input_count >= 4) { - SlotValue x = block_slot_get_value(¤t->inputs[1]); - SlotValue y = block_slot_get_value(¤t->inputs[2]); - SlotValue z = block_slot_get_value(¤t->inputs[3]); - // TODO: 实际移动物体 - } - next = current->next; - break; - - case BLOCK_CONTROL_IF: - if (current->input_count >= 2) { - SlotValue cond = block_slot_get_value(¤t->inputs[1]); - if (cond.as.boolean) { - // 执行 Then 分支 - if (current->output_count > 0) { - BlockSlot* out = ¤t->outputs[0]; - if (out->connected && out->connected->owner) { - next = out->connected->owner; - } - } - } else { - // 执行 Else 分支 - if (current->output_count > 1) { - BlockSlot* out = ¤t->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(¤t->inputs[0]); - SlotValue b = block_slot_get_value(¤t->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(¤t->inputs[1]); - // TODO: 获取变量名 - } - next = current->next; - break; - - default: - next = current->next; + case BLOCK_EVENT_KEY_PRESSED: { + const char* key = get_input(cur, 0).as.string; + log_info("事件: 按键 '%s' (需要引擎集成)", key); + next = next_from_output(cur, 0); break; } - + case BLOCK_EVENT_TIMER: { + double interval = get_input(cur, 0).as.number; + log_info("事件: 定时器 %.1fs (需要引擎集成)", interval); + next = next_from_output(cur, 0); + break; + } + + // === 动作 === + case BLOCK_ACTION_MOVE: { + double x = get_input(cur, 1).as.number; + double y = get_input(cur, 2).as.number; + double z = get_input(cur, 3).as.number; + log_info("移动物体: (%.2f, %.2f, %.2f)", x, y, z); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_ROTATE: { + double x = get_input(cur, 1).as.number; + double y = get_input(cur, 2).as.number; + double z = get_input(cur, 3).as.number; + log_info("旋转物体: (%.2f, %.2f, %.2f)", x, y, z); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_SCALE: { + double x = get_input(cur, 1).as.number; + double y = get_input(cur, 2).as.number; + double z = get_input(cur, 3).as.number; + log_info("缩放物体: (%.2f, %.2f, %.2f)", x, y, z); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_SET_POSITION: { + double x = get_input(cur, 1).as.number; + double y = get_input(cur, 2).as.number; + double z = get_input(cur, 3).as.number; + log_info("设置位置: (%.2f, %.2f, %.2f)", x, y, z); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_SET_ROTATION: { + double x = get_input(cur, 1).as.number; + double y = get_input(cur, 2).as.number; + double z = get_input(cur, 3).as.number; + log_info("设置旋转: (%.2f, %.2f, %.2f)", x, y, z); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_PLAY_SOUND: { + const char* name = get_input(cur, 1).as.string; + log_info("播放音效: '%s'", name); + next = next_from_output(cur, 0); + break; + } + case BLOCK_ACTION_DESTROY: + log_info("销毁物体"); + next = next_from_output(cur, 0); + break; + case BLOCK_ACTION_INSTANTIATE: { + const char* prefab = get_input(cur, 1).as.string; + log_info("实例化预制体: '%s'", prefab); + next = next_from_output(cur, 0); + break; + } + + // === 控制流 === + case BLOCK_CONTROL_IF: + case BLOCK_CONTROL_IF_ELSE: { + int cond = get_input(cur, 1).as.boolean; + log_info("如果 %s", cond ? "真 -> Then" : "假 -> Else"); + next = next_from_output(cur, cond ? 0 : 1); + break; + } + case BLOCK_CONTROL_REPEAT: { + int cond = get_input(cur, 1).as.boolean; + if (cond) next = next_from_output(cur, 0); + else next = next_from_output(cur, 0); // 退出循环: 走输出 + break; + } + case BLOCK_CONTROL_REPEAT_TIMES: { + double times = get_input(cur, 1).as.number; + // 简化: 只执行一次,实际需要计数器 + log_info("循环 %.0f 次 (简化: 执行一次)", times); + next = next_from_output(cur, 0); + break; + } + case BLOCK_CONTROL_WHILE: { + int cond = get_input(cur, 1).as.boolean; + if (cond) next = next_from_output(cur, 0); + break; + } + case BLOCK_CONTROL_WAIT: { + double secs = get_input(cur, 1).as.number; + log_info("等待 %.1f 秒", secs); + exec->wait_timer = secs; + exec->state = EXEC_WAITING; + exec->current_block = next_from_output(cur, 0); + return; + } + case BLOCK_CONTROL_FUNCTION_DEF: + log_info("函数定义 (跳过)"); + next = next_from_output(cur, 0); + break; + + // === 运算 === + case BLOCK_OP_ADD: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_number(a + b); + log_info("%.1f + %.1f = %.1f", a, b, a + b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_SUB: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_number(a - b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_MUL: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_number(a * b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_DIV: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_number(b != 0 ? a / b : 0); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_MOD: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_number(b != 0 ? fmod(a, b) : 0); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_EQUALS: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_bool(a == b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_NOT_EQUALS: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_bool(a != b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_GREATER: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_bool(a > b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_LESS: { + double a = get_input(cur, 0).as.number; + double b = get_input(cur, 1).as.number; + cur->outputs[0].value = make_bool(a < b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_AND: { + int a = get_input(cur, 0).as.boolean; + int b = get_input(cur, 1).as.boolean; + cur->outputs[0].value = make_bool(a && b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_OR: { + int a = get_input(cur, 0).as.boolean; + int b = get_input(cur, 1).as.boolean; + cur->outputs[0].value = make_bool(a || b); + next = next_from_output(cur, 0); + break; + } + case BLOCK_OP_NOT: { + int a = get_input(cur, 0).as.boolean; + cur->outputs[0].value = make_bool(!a); + next = next_from_output(cur, 0); + break; + } + + // === 变量 === + case BLOCK_VAR_GET: { + const char* name = cur->label; + SlotValue val = executor_get_variable(exec, name); + cur->outputs[0].value = val; + log_info("读取变量 '%s' = %.2f", name, val.as.number); + next = next_from_output(cur, 0); + break; + } + case BLOCK_VAR_SET: { + const char* name = cur->label; + SlotValue val = get_input(cur, 1); + executor_set_variable(exec, name, val); + log_info("设置变量 '%s' = %.2f", name, val.as.number); + next = next_from_output(cur, 0); + break; + } + case BLOCK_VAR_CREATE: { + const char* name = cur->label; + executor_create_variable(exec, name); + log_info("创建变量 '%s' = 0", name); + next = next_from_output(cur, 0); + break; + } + + // === 函数 === + case BLOCK_FUNC_CALL: { + const char* fname = get_input(cur, 1).as.string; + log_info("调用函数 '%s'", fname); + if (exec->call_stack_top < MAX_CALL_STACK) { + exec->call_stack[exec->call_stack_top].block = cur; + exec->call_stack_top++; + } + // TODO: 查找函数定义积木并跳转 + next = next_from_output(cur, 0); + break; + } + case BLOCK_FUNC_RETURN: { + if (exec->call_stack_top > 0) { + exec->call_stack_top--; + Block* caller = exec->call_stack[exec->call_stack_top].block; + next = next_from_output(caller, 0); + } + break; + } + + default: + log_error("未知积木类型: %d", cur->type); + next = next_from_output(cur, 0); + break; + } + exec->current_block = next; - if (!exec->current_block) { + log_info("执行完成"); 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; - } + if (exec->wait_timer <= 0) exec->state = EXEC_RUNNING; return; } - - // 执行多步以避免卡顿 + if (exec->state != EXEC_RUNNING) return; int steps = 0; - while (exec->current_block && steps < 100) { + while (exec->current_block && exec->state == EXEC_RUNNING && steps < 1000) { 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); @@ -175,17 +381,11 @@ void executor_set_variable(BlockExecutor* exec, const char* name, SlotValue valu 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; - } + if (strcmp(exec->variables[i].name, name) == 0) return exec->variables[i].value; } - SlotValue empty = {0}; - return empty; + return make_number(0); } 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); + executor_set_variable(exec, name, make_number(0)); } diff --git a/Engine/VisualScript/block_executor.h b/Engine/VisualScript/block_executor.h index c9b3493..db7e4e9 100644 --- a/Engine/VisualScript/block_executor.h +++ b/Engine/VisualScript/block_executor.h @@ -68,3 +68,7 @@ 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); + +// 日志回调 +typedef void (*LogCallback)(const char* msg, int level); +void executor_set_log_callback(LogCallback cb); diff --git a/Engine/VisualScript/block_workspace.c b/Engine/VisualScript/block_workspace.c index 286b634..84939bd 100644 --- a/Engine/VisualScript/block_workspace.c +++ b/Engine/VisualScript/block_workspace.c @@ -26,10 +26,9 @@ void workspace_destroy(BlockWorkspace* 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++; + if (block->id <= 0) block->id = ws->next_block_id++; + else if (block->id >= ws->next_block_id) ws->next_block_id = block->id + 1; block->workspace = ws; - ws->blocks[ws->block_count++] = block; return block->id; }