/
Zamar_Terrier
/
TEngineEditor
Обзор
Документация
Войти
/
Zamar_Terrier
/
TEngineEditor
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/render_window.c
278 строк
10 KB
Zamar_Terrier
checkpoint
23 июл 2026, 18:41
23 июл 2026, 18:41
10276a6
Код
Авторство
О чём код?
#include <TigorEngine.h> #include <TigorWidgets.h> #include <TigorGUI.h> #include <Core/e_camera.h> #include <Objects/shape_object.h> #include <Objects/render_texture.h> #include <Tools/e_math.h> #include "scene.h" #include "tool_bar.h" RenderTexture scene_buffer; ShapeObject shape; EWidget widget, black_plane; vec2 window_pos = {200, 200}; extern TEngine engine; // Глобальная сцена - объявляем как extern для доступа к объектам сцены extern Scene global_scene; bool can_move = false, right_press = false, in_controll = false; vec2 drag_offset = {0, 0}; vec2 last_mouse = {0, 0}, next_mouse = {0}; void RenderWindowMousePress(EWidget *widget, void *value, void *arg){ can_move = true; double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); drag_offset.x = window_pos.x - xpos; drag_offset.y = window_pos.y - ypos; } void RenderWindowMouseUnPress(EWidget *widget, void *value, void *arg){ can_move = false; } void RenderWindowFocus(EWidget *widget, void *value, void *arg){ in_controll = true; } void RenderWindowUnFocus(EWidget *widget, void *value, void *arg){ in_controll = false; } // Вспомогательная функция для получения направления луча из камеры vec3 GetRayDirection(double mouse_x, double mouse_y, Camera3D* cam, int win_width, int win_height) { float ndc_x = (mouse_x / (float)win_width) * 2.0f - 1.0f; float ndc_y = 1.0f - (mouse_y / (float)win_height) * 2.0f; float fov = 45.0f; // градусы float aspect = (float)win_width / win_height; float tan_fov = tan(fov * M_PI / 360.0f); // Направление в пространстве камеры (перед камерой -Z) vec3 cam_dir = vec3_f(ndc_x * tan_fov * aspect, ndc_y * tan_fov, -1.0f); cam_dir = v3_norm(cam_dir); // Поворачиваем направление в мировое пространство, используя углы камеры (yaw, pitch) float yaw = cam->yaw * M_PI / 180.0f; float pitch = cam->pitch * M_PI / 180.0f; // Матрица поворота: сначала yaw (вокруг Y), потом pitch (вокруг X) // Это упрощённо, но для наших целей достаточно float cos_y = cos(yaw); float sin_y = sin(yaw); float cos_p = cos(pitch); float sin_p = sin(pitch); // Поворачиваем cam_dir vec3 world_dir; // Поворот по Y world_dir.x = cam_dir.x * cos_y + cam_dir.z * sin_y; world_dir.y = cam_dir.y; world_dir.z = -cam_dir.x * sin_y + cam_dir.z * cos_y; // Поворот по X (pitch) float tmp_y = world_dir.y; float tmp_z = world_dir.z; world_dir.y = tmp_y * cos_p - tmp_z * sin_p; world_dir.z = tmp_y * sin_p + tmp_z * cos_p; return v3_norm(world_dir); } SceneObject* RenderWindowRaycast() { double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); // Позиция и размер shape (виджета, отображающего текстуру) vec2 shape_pos = Transform2DGetPosition((GameObject2D*)&shape); vec2 shape_scale = Transform2DGetScale((GameObject2D*)&shape); // Границы shape float min_x = shape_pos.x - shape_scale.x / 2.0f; float max_x = shape_pos.x + shape_scale.x / 2.0f; float min_y = shape_pos.y - shape_scale.y / 2.0f; float max_y = shape_pos.y + shape_scale.y / 2.0f; // Если мышь вне области shape – выходим if (xpos < min_x || xpos > max_x || ypos < min_y || ypos > max_y) { return NULL; } // Относительные координаты внутри shape (0..1) float rel_x = (xpos - min_x) / shape_scale.x; float rel_y = (ypos - min_y) / shape_scale.y; // Пиксельные координаты в текстуре (800x600) с инверсией Y int pixel_x = (int)(rel_x * 800); int pixel_y = (int)((1.0f - rel_y) * 600); // --- Проверка 2D-объектов --- SceneObject* current = global_scene.first_object; while (current) { if (current->type == OBJECT_TYPE_2D_QUAD && current->render_object.shape) { vec2 pos = Transform2DGetPosition((GameObject2D*)current->render_object.shape); vec2 scale = Transform2DGetScale((GameObject2D*)current->render_object.shape); float half_w = scale.x / 2.0f; float half_h = scale.y / 2.0f; // Добавляем допуск 2 пикселя для смягчения float tolerance = 2.0f; if (pixel_x >= pos.x - half_w - tolerance && pixel_x <= pos.x + half_w + tolerance && pixel_y >= pos.y - half_h - tolerance && pixel_y <= pos.y + half_h + tolerance) { return current; } } current = current->next; } // --- Raycasting для 3D-объектов --- vec3 cam_pos = scene_buffer.cam3D.position; vec3 ray_dir = GetRayDirection(pixel_x, pixel_y, &scene_buffer.cam3D, 800, 600); current = global_scene.first_object; SceneObject* closest = NULL; float closest_t = 1e9f; while (current) { if (current->type == OBJECT_TYPE_2D_QUAD || current->render_object.primitive == NULL) { current = current->next; continue; } vec3 obj_pos = current->transform.position; vec3 scale = current->transform.scale; float radius = fmax(fmax(scale.x, scale.y), scale.z) * 0.5f; vec3 to_obj = v3_sub(obj_pos, cam_pos); float t = v3_dot(to_obj, ray_dir); if (t < 0) { current = current->next; continue; } vec3 closest_point = v3_add(cam_pos, v3_muls(ray_dir, t)); float dist_to_ray = v3_length(v3_sub(obj_pos, closest_point)); if (dist_to_ray < radius && t < closest_t) { closest = current; closest_t = t; } current = current->next; } return closest; } void RenderWindowOnMouseClick(EWidget *widget, void *value, void *arg){ if (can_move) return; double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); printf("Mouse click at: %f %f\n", xpos, ypos); SceneObject* clicked = RenderWindowRaycast(); if (clicked) { printf("Clicked object: %s\n", clicked->name); SceneSelectObject(&global_scene, clicked); ToolBarUpdateSelectedObject(clicked); } else { printf("No object clicked\n"); SceneSelectObject(&global_scene, NULL); ToolBarUpdateSelectedObject(NULL); } } void RenderWindowUpdate(float dTime){ double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); if(in_controll){ if(TEngineGetMousePress(TIGOR_MOUSE_BUTTON_2)){ if(!right_press){ next_mouse.x = xpos; next_mouse.y = ypos; } right_press = true; Camera3DTrueRotation(&scene_buffer.cam3D, last_mouse.x + (xpos - next_mouse.x), last_mouse.y + (ypos - next_mouse.y), dTime); }else if(right_press){ last_mouse.x = last_mouse.x + (xpos - next_mouse.x); last_mouse.y = last_mouse.y + (ypos - next_mouse.y); right_press = false; } Camera3DMovementUpdate(&scene_buffer.cam3D, dTime); } if(can_move){ double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); window_pos.x = xpos + drag_offset.x; window_pos.y = ypos + drag_offset.y; } Transform2DSetPosition((GameObject2D *)&shape, window_pos.x, window_pos.y + 5); WidgetSetPosition((EWidget *)&widget, window_pos.x - (widget.scale.x / 2), window_pos.y - (widget.scale.y / 2)); WidgetSetPosition((EWidget *)&black_plane, window_pos.x - (black_plane.scale.x / 2), window_pos.y - (black_plane.scale.y / 2) + 5); SceneUpdate(dTime); } void RenderWindowDraw(){ double xpos, ypos; TEngineGetCursorPos(&xpos, &ypos); GameObjectDraw((GameObject *)&widget); GameObjectDraw((GameObject *)&black_plane); TEngineRenderGUI(); GameObjectDraw((GameObject *)&shape); SceneDraw(); } void RenderWindowInit(){ RenderTextureInit(&scene_buffer, TIGOR_RENDER_TYPE_COLORED_IMAGE, 800, 600, 0); TEngineSetRender(&scene_buffer, 1); ShapeObjectInit(&shape, NULL, TIGOR_SHAPE_OBJECT_QUAD, NULL); GameObject2DInitDefaultShaderWithName((GameObject2D *)&shape, "2DDefault"); GameObject2DSetDescriptorUpdate((GameObject2D *)&shape, 0, 0, (UpdateDescriptor)GameObject2DTransformBufferUpdate); GameObject2DSetDescriptorUpdate((GameObject2D *)&shape, 0, 1, (UpdateDescriptor)GameObject2DImageBuffer); GameObject2DTextureFromRender((GameObject2D *)&shape, &scene_buffer); Transform2DSetScale((GameObject2D *)&shape, 205, 150); WidgetInit(&widget, NULL); WidgetSetScale((EWidget *)&widget, 420, 320); WidgetSetColor((EWidget *)&widget, vec4_f(0.8, 0.8, 0.8, 1)); WidgetConnect(&widget, TIGOR_WIDGET_TRIGGER_MOUSE_PRESS, RenderWindowMousePress, NULL); WidgetConnect(&widget, TIGOR_WIDGET_TRIGGER_MOUSE_RELEASE, RenderWindowMouseUnPress, NULL); WidgetConnect(&widget, TIGOR_WIDGET_TRIGGER_WIDGET_FOCUS, RenderWindowFocus, NULL); WidgetConnect(&widget, TIGOR_WIDGET_TRIGGER_WIDGET_UNFOCUS, RenderWindowUnFocus, NULL); WidgetInit(&black_plane, NULL); WidgetSetScale((EWidget *)&black_plane, 410, 300); WidgetSetColor((EWidget *)&black_plane, vec4_f(1, 1, 1, 1)); WidgetConnect(&black_plane, TIGOR_WIDGET_TRIGGER_WIDGET_FOCUS, RenderWindowFocus, NULL); WidgetConnect(&black_plane, TIGOR_WIDGET_TRIGGER_WIDGET_UNFOCUS, RenderWindowUnFocus, NULL); WidgetConnect(&black_plane, TIGOR_WIDGET_TRIGGER_MOUSE_PRESS, RenderWindowOnMouseClick, NULL); scene_buffer.cam3D.yaw = -90; SceneInit(); } void RenderWindowCleanUp(){ RenderTextureDestroy(&scene_buffer); GameObjectDestroy((GameObject *)&shape); SceneCleanUp(); }