/
Zamar_Terrier
/
TigorEngine
Обзор
Документация
Войти
/
Zamar_Terrier
/
TigorEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/TigorEngine.c
581 строка
19 KB
Zamar_Terrier
Офигенное обновление движка
31 июл 2026, 21:03
Верифицирован
31 июл 2026, 21:03
1682686
Код
Авторство
О чём код?
#include "TigorEngine.h" #include "TigorWidgets.h" #include <vulkan/vulkan.h> #include <assert.h> #include "Core/e_memory.h" #include "Core/e_buffer.h" #include "Core/e_window.h" #include "Core/e_device.h" #include "Core/e_texture.h" #include "Objects/render_texture.h" #include "Objects/light_object.h" #include "GUI/GUIManager.h" #include "wManager/window_manager.h" #include "Tools/e_math.h" #include "Tools/e_shaders.h" #include "Variabels/engine_includes.h" #include "tigor.h" #include "arch/win32/apr_arch_misc.h" TEngine engine; extern GUIManager gui; extern bool enableValidationLayers; extern void EntryWidgetCharacterCallback(void *arg, uint32_t codepoint); extern void EntryWidgetKeyCallback(void *arg, int key, int scancode, int action, int mods); extern void WidgetScrollCallBack(void *window, double xoffset, double yoffset); void TEnginePoolEvents(); void EngineCharacterCallback(void *window, uint32_t codepoint) { EntryWidgetCharacterCallback(window, codepoint); if (engine.internal_charCallback != NULL) engine.internal_charCallback(window, codepoint); } void EngineKeyCallback(void *window, unsigned int key, unsigned int scancode, unsigned int action, unsigned int mods) { EntryWidgetKeyCallback(window, key, scancode, action, mods); if (engine.internal_keyCallback != NULL) engine.internal_keyCallback(window, key, scancode, action, mods); } int TEngineLockGlobal() { return tigor_mutex_lock(engine.global_mutex); } int TEngineUnLockGlobal() { return tigor_mutex_unlock(engine.global_mutex); } int TEngineTryLockGlobal() { return tigor_mutex_trylock(engine.global_mutex); } void EngineCreateSyncobjects() { engine.Sync.imageAvailableSemaphores = (VkSemaphore *)AllocateMemoryP(engine.imagesCount, sizeof(VkSemaphore), &engine); engine.Sync.renderFinishedSemaphores = (VkSemaphore *)AllocateMemoryP(engine.imagesCount, sizeof(VkSemaphore), &engine); engine.Sync.inFlightFences = (VkFence *)AllocateMemoryP(engine.imagesCount, sizeof(VkFence), &engine); VkSemaphoreCreateInfo semaphoreInfo = {0}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkFenceCreateInfo fenceInfo = {0}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; for (int i = 0; i < engine.imagesCount; i++) { if (vkCreateSemaphore(engine.device.e_device, &semaphoreInfo, NULL, &engine.Sync.imageAvailableSemaphores[i]) != VK_SUCCESS || vkCreateSemaphore(engine.device.e_device, &semaphoreInfo, NULL, &engine.Sync.renderFinishedSemaphores[i]) != VK_SUCCESS || vkCreateFence(engine.device.e_device, &fenceInfo, NULL, &engine.Sync.inFlightFences[i]) != VK_SUCCESS) { printf("failed to create synchronization objects for a frame!"); exit(1); } } } void EngineCreateSilent() { memset(&engine, 0, sizeof(TEngine)); wManagerInit(); createInstance(); setupDebugMessenger(); pickPhysicalDevice(); createLogicalDevice(); BuffersCreateCommandPool(); } void EngineInitVulkan() { createInstance(); createSurface(); setupDebugMessenger(); pickPhysicalDevice(); createLogicalDevice(); SwapChainCreate(); SwapChainCreateImageViews(); BuffersCreateCommandPool(); ToolsCreateDepthResources(); BuffersCreateCommand(); EngineCreateSyncobjects(); } void EngineWaitEvents() { wManagerWaitEvents(); } void TEngineStartRender() { double deltaTime = 0; double last_tick_time = 0; while (!TEngineWindowIsClosed()) { engine.current_render = engine.main_render; double tick_time = TEngineGetTime(); deltaTime = tick_time - last_tick_time; wManagerPoolEvents(); if (engine.Updater != NULL) engine.Updater(deltaTime); TEngineRender(); last_tick_time = tick_time; engine.nbFrames++; if (last_tick_time - engine.lastTime > 1.0f) { engine.fpsCounter = engine.nbFrames; engine.nbFrames = 0; engine.lastTime = last_tick_time; } } } void TEngineInitSystem(int width, int height, const char *name) { memset(&engine, 0, sizeof(TEngine)); strncpy(engine.app_name, name, sizeof(engine.app_name)); engine.present = true; engine.width = width; engine.height = height; engine.diffSize = vec2_f(1.0f, 1.0f); engine.viewSize.x = engine.width; engine.viewSize.y = engine.height; #ifndef NDEBUG enableValidationLayers = true; #else enableValidationLayers = false; #endif engine.nbFrames = 0; engine.lastTime = 0; tigor_mutex_init((tigor_mutex_t **)&engine.global_mutex, 0, NULL); tigor_mutex_init((tigor_mutex_t **)&engine.global_shader_mutex, 0, NULL); tigor_mutex_init((tigor_mutex_t **)&engine.device.commandPool_mutex, 0, NULL); tigor_mutex_init((tigor_mutex_t **)&engine.device.graphicsQueue_mutex, 0, NULL); tigor_mutex_init((tigor_mutex_t **)&engine.device.commandBuffers_mutex, 0, NULL); InitWindow(); EngineInitVulkan(); engine.cache.alloc_buffers_memory_head = calloc(1, sizeof(ChildStack)); engine.cache.alloc_descriptor_head = calloc(1, sizeof(ChildStack)); engine.cache.alloc_pipeline_head = calloc(1, sizeof(ChildStack)); engine.e_var_current_entry = NULL; engine.DataR.e_var_images = AllocateMemoryP(MAX_IMAGES, sizeof(engine_buffered_image), &engine); engine.DataR.e_var_num_images = 0; engine.DataR.e_var_fonts = AllocateMemoryP(MAX_FONTS, sizeof(FontCache), &engine); engine.DataR.e_var_num_fonts = 0; wManagerSetCharCallback(engine.window.e_window, (wManagerCharacterFunc)EngineCharacterCallback); wManagerSetKeyCallback(engine.window.e_window, (wManagerKeyFunc)EngineKeyCallback); ShadersInit(); char *text = "Null texture"; engine_buffered_image *images = engine.DataR.e_var_images; TextureCreateEmptyDefault(&images[engine.DataR.e_var_num_images].texture); TextureCreateTextureImageView(&images[engine.DataR.e_var_num_images].texture, VK_IMAGE_VIEW_TYPE_2D); TextureCreateSampler(&images[engine.DataR.e_var_num_images].texture.sampler, images[engine.DataR.e_var_num_images].texture.textureType, images[engine.DataR.e_var_num_images].texture.image_data.mip_levels); strcpy(images[engine.DataR.e_var_num_images].path, text); engine.DataR.e_var_num_images++; memset(&engine.renders, 0, sizeof(EngineRenderItems)); memset(&engine.lights, 0, sizeof(EngineLightItems)); engine.main_render = AllocateMemory(1, sizeof(RenderTexture)); RenderTextureInit(engine.main_render, TIGOR_RENDER_TYPE_WINDOW, 0, 0, 0); TEngineSetRender(engine.main_render, 1); GUIManagerInit(); wManagerSetMouseScrollCallback(engine.window.e_window, (wManagerScrollfFn)WidgetScrollCallBack); engine.internal_charCallback = NULL; engine.internal_keyCallback = NULL; engine.Updater = NULL; engine.Drawer = NULL; engine.Recreator = NULL; } void TEngineSetRender(void *obj, uint32_t count) { if (count == 0) return; RenderTexture *some_render = obj; for (int i = 0; i < engine.renders.size; i++) { if (engine.renders.objects[i] == &some_render[0]) return; } for (int i = 0; i < count; i++) { engine.renders.objects[engine.renders.size] = &some_render[i]; engine.renders.size++; } } void TEngineRender() { vkWaitForFences(engine.device.e_device, 1, &engine.Sync.inFlightFences[engine.imageIndex], VK_TRUE, UINT64_MAX); VkResult result = vkAcquireNextImageKHR(engine.device.e_device, engine.swapchain.swapChain, UINT64_MAX, engine.Sync.imageAvailableSemaphores[engine.currentFrame], VK_NULL_HANDLE, &engine.imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { RecreateSwapChain(); if (engine.Recreator != NULL) engine.Recreator(engine.width, engine.height); engine.framebufferwasResized = true; return; } else if (result == VK_ERROR_DEVICE_LOST) { printf("\n[CRITICAL] Vulkan Device Lost! (VkResult: %d)\n", result); printf("Reason: GPU driver crashed or detected invalid state.\n"); printf("This is usually caused by Buffer Overflows, invalid descriptors, or using destroyed resources.\n"); printf(">>> Please scroll up and check the Validation Layers output for the exact cause! <<<\n\n"); exit(1); } else if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY || result == VK_ERROR_OUT_OF_HOST_MEMORY) { printf("\n[CRITICAL] Out of Memory! (VkResult: %d)\n", result); printf("Reason: VRAM or RAM is exhausted.\n"); printf("This is caused by massive memory leaks (e.g., GUI buffers not being freed every frame).\n\n"); exit(1); } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { printf("failed to acquire swap chain image! (Unknown VkResult: %d)\n", result); exit(1); } tigor_mutex_lock(engine.device.commandPool_mutex); if (GUIManagerIsInit()) GUIManagerUpdate(); VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; if (vkBeginCommandBuffer(engine.device.commandBuffers[engine.imageIndex], &beginInfo) != VK_SUCCESS) { printf("failed begin command buffer\n"); exit(1); } for (int i = 0; i < engine.renders.size; i++) { RenderTexture *render; engine.current_render = render = engine.renders.objects[i]; if ((render->flags & TIGOR_RENDER_FLAG_ONE_SHOT) && (render->flags & TIGOR_RENDER_FLAG_SHOOTED)) continue; if (render->type & TIGOR_RENDER_TYPE_CUBEMAP) { for (int k = 0; k < 6; k++) { RenderTextureSetCurrentFrame(engine.current_render, k); RenderTextureBeginRendering(engine.current_render, engine.device.commandBuffers[engine.imageIndex]); engine.Drawer(); RenderTextureEndRendering(engine.current_render, engine.device.commandBuffers[engine.imageIndex]); } } else { RenderTextureBeginRendering(engine.current_render, engine.device.commandBuffers[engine.imageIndex]); engine.Drawer(); RenderTextureEndRendering(engine.current_render, engine.device.commandBuffers[engine.imageIndex]); } } if (vkEndCommandBuffer(engine.device.commandBuffers[engine.imageIndex]) != VK_SUCCESS) { printf("failed to record command buffer!"); exit(1); } tigor_mutex_lock(engine.device.graphicsQueue_mutex); VkSubmitInfo submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; VkSemaphore waitSemaphores[] = {engine.Sync.imageAvailableSemaphores[engine.currentFrame]}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitDstStageMask = waitStages; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = (const VkCommandBuffer *)&engine.device.commandBuffers[engine.imageIndex]; VkSemaphore signalSemaphores[] = {engine.Sync.renderFinishedSemaphores[engine.currentFrame]}; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; vkResetFences(engine.device.e_device, 1, (const VkFence *)&engine.Sync.inFlightFences[engine.currentFrame]); if (vkQueueSubmit(engine.device.graphicsQueue, 1, &submitInfo, engine.Sync.inFlightFences[engine.currentFrame]) != VK_SUCCESS) { printf("failed to submit draw command buffer!"); exit(1); } vkQueueWaitIdle(engine.device.graphicsQueue); VkPresentInfoKHR presentInfo = {0}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; presentInfo.pWaitSemaphores = signalSemaphores; VkSwapchainKHR swapChains[] = {engine.swapchain.swapChain}; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = swapChains; presentInfo.pImageIndices = &engine.imageIndex; result = vkQueuePresentKHR(engine.device.presentQueue, &presentInfo); tigor_mutex_unlock(engine.device.graphicsQueue_mutex); tigor_mutex_unlock(engine.device.commandPool_mutex); if (engine.framebufferwasResized) { engine.framebufferwasResized = false; } if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || engine.framebufferResized) { engine.framebufferResized = false; RecreateSwapChain(); engine.framebufferwasResized = true; if (engine.Recreator != NULL) engine.Recreator(engine.width, engine.height); } else if (result != VK_SUCCESS) { printf("failed to present swap chain image!"); exit(1); } for (int i = 0; i < gui.curr_buffer_gui; i++) { BuffersDestroyer(&gui.buffers_pool[i].indxBuffer); BuffersDestroyer(&gui.buffers_pool[i].vertBuffer); } gui.curr_buffer_gui = 0; for (int i = 0; i < engine.renders.size; i++) { RenderTexture *render = engine.renders.objects[i]; if ((render->flags & TIGOR_RENDER_FLAG_ONE_SHOT) && !(render->flags & TIGOR_RENDER_FLAG_SHOOTED)) render->flags |= TIGOR_RENDER_FLAG_SHOOTED; } engine.currentFrame = (engine.currentFrame + 1) % engine.imagesCount; } void TEngineSetRecreateFunc(EngineRecreateFunc recreate) { engine.Recreator = recreate; } void TEngineSetKeyCallback(void *callback) { engine.internal_keyCallback = (e_keyCallback )callback; } void TEngineSetCharCallback(void *callback) { engine.internal_charCallback = (e_charCallback )callback; } void TEngineSetMouseKeyCallback(void *callback) { wManagerSetMouseButtonCallback(engine.window.e_window, callback); } void TEngineSetCursorPoscallback(void *callback) { wManagerSetCursorPosCallback(engine.window.e_window, callback); } void TEngineGetWindowSize(int *width, int *height) { *width = engine.width; *height = engine.height; } void TEngineFixedCursorCenter() { wManagerSetCursorPos(engine.window.e_window, engine.width / 2, engine.height / 2); } void TEngineGetCursorPos(double *xpos, double *ypos) { wManagerGetCursorPos(engine.window.e_window, xpos, ypos); } void TEngineSetCursorPos(float xpos, float ypos) { wManagerSetCursorPos(engine.window.e_window, xpos, ypos); } void TEngineHideCursor(char state) { switch (state) { case 0: wManagerSetInputMode(engine.window.e_window, TIGOR_CURSOR, TIGOR_CURSOR_DISABLED); break; case 1: wManagerSetInputMode(engine.window.e_window, TIGOR_CURSOR, TIGOR_CURSOR_HIDDEN); break; case 2: wManagerSetInputMode(engine.window.e_window, TIGOR_CURSOR, TIGOR_CURSOR_NORMAL); break; } } int TEngineGetMousePress(int Key) { int state = 0; state = wManagerGetMouseButton(engine.window.e_window, Key); return state; } void TEngineRenderGUI() { if (GUIManagerIsInit() && (((RenderTexture *)engine.current_render)->type & TIGOR_RENDER_TYPE_WINDOW)) { GUIManagerDraw(); GUIManagerClear(); } } void TEngineSetUpdater(EngineUpdateFunc update) { engine.Updater = update; } void TEngineSetDrawer(EngineDrawFunc draw) { engine.Drawer = draw; } int TEngineIsMainRender() { return engine.current_render == engine.main_render; } int TEngineWindowIsClosed() { int state = 0; tigor_status_t result = tigor_mutex_trylock(engine.global_mutex); if (APR_STATUS_IS_EBUSY(result)) state = false; else { state = wManagerWindowIsClosed(); tigor_mutex_unlock(engine.global_mutex); } return state; } double TEngineGetTime() { double time = 0; time = wManagerGetTime(); return time; } int TEngineGetKeyPress(int Key) { int state = 0; state = wManagerGetKey(engine.window.e_window, Key); return state; } const char *TEngineGetClipBoardString() { const char *state = wManagerGetClipboardString(engine.window.e_window); return state; } void TEngineSetClipBoardString(const char *string) { wManagerSetClipboardString(engine.window.e_window, string); } void TEngineSetFont(char *font_path) { } void TEngineCleanUp() { tigor_mutex_destroy(engine.global_mutex); tigor_mutex_destroy(engine.global_shader_mutex); tigor_mutex_destroy(engine.device.commandPool_mutex); tigor_mutex_destroy(engine.device.graphicsQueue_mutex); tigor_mutex_destroy(engine.device.commandBuffers_mutex); tigor_mutex_destroy(engine.device.e_device_mutex); vkDeviceWaitIdle(engine.device.e_device); if (engine.present) { CleanupSwapChain(); for (size_t i = 0; i < engine.imagesCount; i++) { vkDestroySemaphore(engine.device.e_device, engine.Sync.renderFinishedSemaphores[i], NULL); vkDestroySemaphore(engine.device.e_device, engine.Sync.imageAvailableSemaphores[i], NULL); vkDestroyFence(engine.device.e_device, engine.Sync.inFlightFences[i], NULL); } FreeMemory(engine.Sync.renderFinishedSemaphores); FreeMemory(engine.Sync.imageAvailableSemaphores); FreeMemory(engine.Sync.inFlightFences); } vkDestroyCommandPool(engine.device.e_device, (VkCommandPool)engine.device.commandPool, NULL); if (engine.DataR.e_var_num_fonts > 0) { FontCache *fonts = engine.DataR.e_var_fonts; for (int i = 0; i < engine.DataR.e_var_num_fonts; i++) { FreeMemory(fonts[i].cdata); FreeMemory(fonts[i].info); ImageDestroyTexture(fonts[i].texture); FreeMemory(fonts[i].texture); } } FreeMemory(engine.DataR.e_var_fonts); engine.DataR.e_var_fonts = NULL; if (engine.DataR.e_var_num_images > 0) { engine_buffered_image *images = engine.DataR.e_var_images; for (int i = 0; i < engine.DataR.e_var_num_images; i++) { ImageDestroyTexture(&images[i].texture); } } FreeMemory(engine.DataR.e_var_images); engine.DataR.e_var_images = NULL; RenderTextureDestroy(engine.main_render); FreeMemory(engine.main_render); if (engine.DataR.font_path != NULL) FreeMemory(engine.DataR.font_path); if (GUIManagerIsInit()) GUIManagerDestroy(); LightObjectClear(); ShadersClear(); vkDestroyDevice(engine.device.e_device, NULL); if (enableValidationLayers) { DestroyDebugUtilsMessengerEXT(engine.window.instance, engine.debugMessenger, NULL); } if (engine.present) vkDestroySurfaceKHR(engine.window.instance, (VkSurfaceKHR)engine.window.surface, NULL); vkDestroyInstance(engine.window.instance, NULL); wManagerDestroyWindow(engine.window.e_window); wManagerTerminate(); if (engine.cache.alloc_buffers_memory_head != NULL) { StackClear(engine.cache.alloc_buffers_memory_head, NULL, 0); engine.cache.alloc_buffers_memory_head = NULL; } if (engine.cache.alloc_descriptor_head != NULL) { StackClear(engine.cache.alloc_descriptor_head, NULL, 0); engine.cache.alloc_descriptor_head = NULL; } if (engine.cache.alloc_pipeline_head != NULL) { StackClear(engine.cache.alloc_pipeline_head, NULL, 0); engine.cache.alloc_pipeline_head = NULL; } ClearAllAllocatedMemory(); } void TEngineDeviceWaitIdle() { vkDeviceWaitIdle(engine.device.e_device); }