VkBool32 VKTS_APIENTRY engineAddUpdateThread(const IUpdateThreadSP& updateThread) { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Not in initialize state."); return VK_FALSE; } if (!updateThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! No update thread."); return VK_FALSE; } if (engineGetNumberUpdateThreads() >= VKTS_MAX_UPDATE_THREADS) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Too many update threads."); return VK_FALSE; } g_allUpdateThreads.append(updateThread); return VK_TRUE; }
VkBool32 removeAt(const size_t index) { if (index >= allKeys.size()) { return VK_FALSE; } allKeys.removeAt(index); allValues.removeAt(index); return VK_TRUE; }
void SubMesh::bindDrawIndexedRecursive(const std::string& nodeName, const ICommandBuffersSP& cmdBuffer, const SmartPointerVector<IGraphicsPipelineSP>& allGraphicsPipelines, const overwrite* renderOverwrite, const uint32_t bufferIndex) const { const overwrite* currentOverwrite = renderOverwrite; while (currentOverwrite) { if (!currentOverwrite->submeshBindDrawIndexedRecursive(*this, cmdBuffer, allGraphicsPipelines, bufferIndex)) { return; } currentOverwrite = currentOverwrite->getNextOverwrite(); } if (bsdfMaterial.get()) { // TODO: Add again. } else if (phongMaterial.get()) { IGraphicsPipelineSP graphicsPipeline; for (size_t i = 0; i < allGraphicsPipelines.size(); i++) { if (allGraphicsPipelines[i]->getVertexBufferType() == vertexBufferType) { graphicsPipeline = allGraphicsPipelines[i]; break; } } if (!graphicsPipeline.get()) { logPrint(VKTS_LOG_SEVERE, "SubMesh: Vertex buffer type not found %x", vertexBufferType); return; } vkCmdBindPipeline(cmdBuffer->getCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->getPipeline()); phongMaterial->bindDrawIndexedRecursive(nodeName,cmdBuffer, graphicsPipeline, renderOverwrite, bufferIndex); } else { return; } bindIndexBuffer(cmdBuffer, bufferIndex); bindVertexBuffers(cmdBuffer, bufferIndex); drawIndexed(cmdBuffer, bufferIndex); }
VkBool32 set(const K& key, const V& value) { for (size_t i = 0; i < allKeys.size(); i++) { if (key == allKeys[i]) { allValues[i] = value; return VK_TRUE; } else if (key < allKeys[i]) { allKeys.insert(i, key); allValues.insert(i, value); return VK_TRUE; } } allKeys.append(key); allValues.append(value); return VK_TRUE; }
void clear() { allKeys.clear(); allValues.clear(); }
int32_t VKTS_APIENTRY engineGetNumberUpdateThreads() { return static_cast<int32_t>(g_allUpdateThreads.size()); }
namespace vkts { typedef std::shared_ptr<std::thread> ThreadSP; static VKTS_ENGINE_STATES g_engineState = VKTS_ENGINE_INIT_STATE; static SmartPointerVector<IUpdateThreadSP> g_allUpdateThreads; static double g_tickTime = 1.0 / VKTS_TICKS_PER_SECOND; static std::multimap<IUpdateThreadSP, const NativeDisplaySP> g_allAttachedDisplays; static std::multimap<IUpdateThreadSP, const NativeWindowSP> g_allAttachedWindows; static uint32_t g_taskExecutorCount = 0; VkBool32 VKTS_APIENTRY engineInit() { if (!processorInit()) { VKTS_PRINTF("LOG [VKTS_LOG_ERROR]: Engine: Initialization failed! Could not initialize the processor!\n"); return VK_FALSE; } if (!logInit()) { VKTS_PRINTF("LOG [VKTS_LOG_ERROR]: Engine: Initialization failed! Could not initialize logging.\n"); return VK_FALSE; } if (!timeInit()) { logPrint(VKTS_LOG_ERROR, "Engine: Initialization failed! Could not initialize the timer!"); return VK_FALSE; } if (!barrierInit()) { logPrint(VKTS_LOG_ERROR, "Engine: Initialization failed! Could not initialize the barrier!"); return VK_FALSE; } if (!fileInit()) { logPrint(VKTS_LOG_ERROR, "Engine: Initialization failed! Could not initialize the file system!"); return VK_FALSE; } return VK_TRUE; } VkBool32 VKTS_APIENTRY engineAddUpdateThread(const IUpdateThreadSP& updateThread) { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Not in initialize state."); return VK_FALSE; } if (!updateThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! No update thread."); return VK_FALSE; } if (engineGetNumberUpdateThreads() >= VKTS_MAX_UPDATE_THREADS) { logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Too many update threads."); return VK_FALSE; } g_allUpdateThreads.append(updateThread); return VK_TRUE; } VkBool32 VKTS_APIENTRY engineAttachDisplayToUpdateThread(const INativeDisplayWP& display, const IUpdateThreadSP& updateThread) { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Adding attaching display failed! Not in initialize state."); return VK_FALSE; } if (!updateThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: No display or update thread."); return VK_FALSE; } auto sharedDisplay = display.lock(); if (!sharedDisplay.get()) { return VK_FALSE; } const auto nativeDisplay = visualGetDisplayInternal(sharedDisplay->getIndex()); if (!nativeDisplay.get()) { return VK_FALSE; } g_allAttachedDisplays.insert(std::pair<IUpdateThreadSP, const NativeDisplaySP>(updateThread, nativeDisplay)); return VK_TRUE; } VkBool32 VKTS_APIENTRY engineAttachWindowToUpdateThread(const INativeWindowWP& window, const IUpdateThreadSP& updateThread) { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Adding attaching window failed! Not in initialize state."); return VK_FALSE; } if (!updateThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: No window or update thread."); return VK_FALSE; } auto sharedWindow = window.lock(); if (!sharedWindow.get()) { return VK_FALSE; } const auto nativeWindow = visualGetWindowInternal(sharedWindow->getIndex()); if (!nativeWindow.get()) { return VK_FALSE; } g_allAttachedWindows.insert(std::pair<IUpdateThreadSP, const NativeWindowSP>(updateThread, nativeWindow)); return VK_TRUE; } VkBool32 VKTS_APIENTRY engineSetTicksPerSecond(const double ticksPerSecond) { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Setting ticks failed! Not in initialize state."); return VK_FALSE; } double newTicksPerSecond = glm::clamp(ticksPerSecond, VKTS_TICKS_PER_SECOND_MIN, VKTS_TICKS_PER_SECOND_MAX); g_tickTime = 1.0 / newTicksPerSecond; return VK_TRUE; } VkBool32 VKTS_APIENTRY engineRun() { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Not in initialize state."); return VK_FALSE; } if (engineGetNumberUpdateThreads() < VKTS_MIN_UPDATE_THREADS || engineGetNumberUpdateThreads() > VKTS_MAX_UPDATE_THREADS) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Number of update threads not correct."); return VK_FALSE; } // // Main thread gets all displays and windows attached. // const auto& displayList = _visualGetActiveDisplays(); for (size_t i = 0; i < displayList.size(); i++) { engineAttachDisplayToUpdateThread(displayList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } const auto& windowList = _visualGetActiveWindows(); for (size_t i = 0; i < windowList.size(); i++) { engineAttachWindowToUpdateThread(windowList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } // g_engineState = VKTS_ENGINE_UPDATE_STATE; logPrint(VKTS_LOG_INFO, "Engine: Started."); // Task queue creation. TaskQueueSP sendTaskQueue; TaskQueueSP executedTaskQueue; if (g_taskExecutorCount > 0) { sendTaskQueue = TaskQueueSP(new TaskQueue); if (!sendTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } executedTaskQueue = TaskQueueSP(new TaskQueue); if (!executedTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } } // Message dispatcher creation. MessageDispatcherSP messageDispatcher = MessageDispatcherSP(new MessageDispatcher()); if (!messageDispatcher.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create message dispatcher."); return VK_FALSE; } // Object, needed for synchronizing the executors. ExecutorSync executorSync; // // Task executor creation and launching, // SmartPointerVector<TaskExecutorSP> realTaskExecutors; SmartPointerVector<ThreadSP> realTaskThreads; for (uint32_t i = 0; i < g_taskExecutorCount; i++) { auto currentTaskExecutor = TaskExecutorSP(new TaskExecutor(i, executorSync, sendTaskQueue, executedTaskQueue)); if (!currentTaskExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current task executor."); return VK_FALSE; } auto currentRealThread = ThreadSP(new std::thread(&TaskExecutor::run, currentTaskExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } // realTaskExecutors.append(currentTaskExecutor); realTaskThreads.append(currentRealThread); logPrint(VKTS_LOG_INFO, "Engine: Task %d started.", currentTaskExecutor->getIndex()); } // // Update Thread creation and launching. // UpdateThreadExecutorSP mainUpdateThreadExecutor; SmartPointerVector<UpdateThreadExecutorSP> realUpdateThreadExecutors; SmartPointerVector<ThreadSP> realUpdateThreads; int32_t index = 0; for (size_t updateThreadIndex = 0; updateThreadIndex < g_allUpdateThreads.size(); updateThreadIndex++) { const auto& currentUpdateThread = g_allUpdateThreads[updateThreadIndex]; // const auto currentMessageDispatcher = (index == engineGetNumberUpdateThreads() - 1) ? messageDispatcher : MessageDispatcherSP(); // auto currentUpdateThreadContext = UpdateThreadContextSP(new UpdateThreadContext((int32_t) updateThreadIndex, (int32_t) g_allUpdateThreads.size(), g_tickTime, sendTaskQueue, executedTaskQueue)); if (!currentUpdateThreadContext.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create update thread context."); return VK_FALSE; } // for (auto currentDisplayWalker = g_allAttachedDisplays.lower_bound(currentUpdateThread); currentDisplayWalker != g_allAttachedDisplays.upper_bound(currentUpdateThread); currentDisplayWalker++) { currentUpdateThreadContext->attachDisplay(currentDisplayWalker->second); } // for (auto currentWindowWalker = g_allAttachedWindows.lower_bound(currentUpdateThread); currentWindowWalker != g_allAttachedWindows.upper_bound(currentUpdateThread); currentWindowWalker++) { currentUpdateThreadContext->attachWindow(currentWindowWalker->second); } // if (index == engineGetNumberUpdateThreads() - 1) { // Last thread is the main thread. mainUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!mainUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create main update thread executor."); return VK_FALSE; } } else { // Receive queue is the threads send queue. auto currentUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!currentUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current update thread executor."); return VK_FALSE; } realUpdateThreadExecutors.append(currentUpdateThreadExecutor); logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", currentUpdateThreadExecutor->getIndex()); auto currentRealThread = ThreadSP(new std::thread(&UpdateThreadExecutor::run, currentUpdateThreadExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } realUpdateThreads.append(currentRealThread); } index++; } // Run last thread and loop. logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", mainUpdateThreadExecutor->getIndex()); mainUpdateThreadExecutor->run(); // // Stopping everything. // logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", mainUpdateThreadExecutor->getIndex()); // Wait for all threads to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realUpdateThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realUpdateThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", reverseIndex); } realUpdateThreadExecutors.clear(); realUpdateThreads.clear(); // if (sendTaskQueue.get()) { // Empty the queue. // As no update thread can feed the queue anymore, it is save to call reset. sendTaskQueue->reset(); // ITaskSP stopTask; logPrint(VKTS_LOG_SEVERE, "Engine: Disabling task queue."); for (uint32_t i = 0; i < g_taskExecutorCount; i++) { // Send an empty task to the queue, to exit the thread. sendTaskQueue->addTask(stopTask); } } // Wait for all tasks to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realTaskThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realTaskThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Task %d stopped.", reverseIndex); } realTaskExecutors.clear(); realTaskThreads.clear(); // g_engineState = VKTS_ENGINE_INIT_STATE; logPrint(VKTS_LOG_INFO, "Engine: Stopped."); return VK_TRUE; } int32_t VKTS_APIENTRY engineGetNumberUpdateThreads() { return static_cast<int32_t>(g_allUpdateThreads.size()); } VkBool32 VKTS_APIENTRY engineSetTaskExecutorCount(const uint32_t count) { g_taskExecutorCount = count; return VK_TRUE; } uint32_t VKTS_APIENTRY engineGetTaskExecutorCount() { return g_taskExecutorCount; } void VKTS_APIENTRY engineTerminate() { fileTerminate(); barrierTerminate(); timeTerminate(); logTerminate(); processorTerminate(); } }
VkBool32 VKTS_APIENTRY engineRun() { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Not in initialize state."); return VK_FALSE; } if (engineGetNumberUpdateThreads() < VKTS_MIN_UPDATE_THREADS || engineGetNumberUpdateThreads() > VKTS_MAX_UPDATE_THREADS) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Number of update threads not correct."); return VK_FALSE; } // // Main thread gets all displays and windows attached. // const auto& displayList = _visualGetActiveDisplays(); for (size_t i = 0; i < displayList.size(); i++) { engineAttachDisplayToUpdateThread(displayList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } const auto& windowList = _visualGetActiveWindows(); for (size_t i = 0; i < windowList.size(); i++) { engineAttachWindowToUpdateThread(windowList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } // g_engineState = VKTS_ENGINE_UPDATE_STATE; logPrint(VKTS_LOG_INFO, "Engine: Started."); // Task queue creation. TaskQueueSP sendTaskQueue; TaskQueueSP executedTaskQueue; if (g_taskExecutorCount > 0) { sendTaskQueue = TaskQueueSP(new TaskQueue); if (!sendTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } executedTaskQueue = TaskQueueSP(new TaskQueue); if (!executedTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } } // Message dispatcher creation. MessageDispatcherSP messageDispatcher = MessageDispatcherSP(new MessageDispatcher()); if (!messageDispatcher.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create message dispatcher."); return VK_FALSE; } // Object, needed for synchronizing the executors. ExecutorSync executorSync; // // Task executor creation and launching, // SmartPointerVector<TaskExecutorSP> realTaskExecutors; SmartPointerVector<ThreadSP> realTaskThreads; for (uint32_t i = 0; i < g_taskExecutorCount; i++) { auto currentTaskExecutor = TaskExecutorSP(new TaskExecutor(i, executorSync, sendTaskQueue, executedTaskQueue)); if (!currentTaskExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current task executor."); return VK_FALSE; } auto currentRealThread = ThreadSP(new std::thread(&TaskExecutor::run, currentTaskExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } // realTaskExecutors.append(currentTaskExecutor); realTaskThreads.append(currentRealThread); logPrint(VKTS_LOG_INFO, "Engine: Task %d started.", currentTaskExecutor->getIndex()); } // // Update Thread creation and launching. // UpdateThreadExecutorSP mainUpdateThreadExecutor; SmartPointerVector<UpdateThreadExecutorSP> realUpdateThreadExecutors; SmartPointerVector<ThreadSP> realUpdateThreads; int32_t index = 0; for (size_t updateThreadIndex = 0; updateThreadIndex < g_allUpdateThreads.size(); updateThreadIndex++) { const auto& currentUpdateThread = g_allUpdateThreads[updateThreadIndex]; // const auto currentMessageDispatcher = (index == engineGetNumberUpdateThreads() - 1) ? messageDispatcher : MessageDispatcherSP(); // auto currentUpdateThreadContext = UpdateThreadContextSP(new UpdateThreadContext((int32_t) updateThreadIndex, (int32_t) g_allUpdateThreads.size(), g_tickTime, sendTaskQueue, executedTaskQueue)); if (!currentUpdateThreadContext.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create update thread context."); return VK_FALSE; } // for (auto currentDisplayWalker = g_allAttachedDisplays.lower_bound(currentUpdateThread); currentDisplayWalker != g_allAttachedDisplays.upper_bound(currentUpdateThread); currentDisplayWalker++) { currentUpdateThreadContext->attachDisplay(currentDisplayWalker->second); } // for (auto currentWindowWalker = g_allAttachedWindows.lower_bound(currentUpdateThread); currentWindowWalker != g_allAttachedWindows.upper_bound(currentUpdateThread); currentWindowWalker++) { currentUpdateThreadContext->attachWindow(currentWindowWalker->second); } // if (index == engineGetNumberUpdateThreads() - 1) { // Last thread is the main thread. mainUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!mainUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create main update thread executor."); return VK_FALSE; } } else { // Receive queue is the threads send queue. auto currentUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!currentUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current update thread executor."); return VK_FALSE; } realUpdateThreadExecutors.append(currentUpdateThreadExecutor); logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", currentUpdateThreadExecutor->getIndex()); auto currentRealThread = ThreadSP(new std::thread(&UpdateThreadExecutor::run, currentUpdateThreadExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } realUpdateThreads.append(currentRealThread); } index++; } // Run last thread and loop. logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", mainUpdateThreadExecutor->getIndex()); mainUpdateThreadExecutor->run(); // // Stopping everything. // logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", mainUpdateThreadExecutor->getIndex()); // Wait for all threads to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realUpdateThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realUpdateThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", reverseIndex); } realUpdateThreadExecutors.clear(); realUpdateThreads.clear(); // if (sendTaskQueue.get()) { // Empty the queue. // As no update thread can feed the queue anymore, it is save to call reset. sendTaskQueue->reset(); // ITaskSP stopTask; logPrint(VKTS_LOG_SEVERE, "Engine: Disabling task queue."); for (uint32_t i = 0; i < g_taskExecutorCount; i++) { // Send an empty task to the queue, to exit the thread. sendTaskQueue->addTask(stopTask); } } // Wait for all tasks to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realTaskThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realTaskThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Task %d stopped.", reverseIndex); } realTaskExecutors.clear(); realTaskThreads.clear(); // g_engineState = VKTS_ENGINE_INIT_STATE; logPrint(VKTS_LOG_INFO, "Engine: Stopped."); return VK_TRUE; }
SmartPointerVector<IImageDataSP> VKTS_APIENTRY imageDataMipmap(const IImageDataSP& sourceImage, VkBool32 addSourceAsCopy, const std::string& name) { if (name.size() == 0 || !sourceImage.get()) { return SmartPointerVector<IImageDataSP>(); } std::string sourceImageFilename = name; auto dotIndex = sourceImageFilename.rfind("."); if (dotIndex == sourceImageFilename.npos) { return SmartPointerVector<IImageDataSP>(); } auto sourceImageName = sourceImageFilename.substr(0, dotIndex); auto sourceImageExtension = sourceImageFilename.substr(dotIndex); IImageDataSP currentSourceImage = sourceImage; int32_t width = currentSourceImage->getWidth(); int32_t height = currentSourceImage->getHeight(); int32_t depth = currentSourceImage->getDepth(); IImageDataSP currentTargetImage; std::string targetImageFilename; int32_t level = 0; SmartPointerVector<IImageDataSP> result; if (addSourceAsCopy) { targetImageFilename = sourceImageName + "_L" + std::to_string(level++) + sourceImageExtension; currentTargetImage = imageDataCopy(sourceImage, targetImageFilename); if (!currentTargetImage.get()) { return SmartPointerVector<IImageDataSP>(); } result.append(currentTargetImage); } else { result.append(sourceImage); level++; } while (width > 1 || height > 1 || depth > 1) { width = glm::max(width / 2, 1); height = glm::max(height / 2, 1); depth = glm::max(depth / 2, 1); targetImageFilename = sourceImageName + "_L" + std::to_string(level++) + sourceImageExtension; currentTargetImage = imageDataCreate(targetImageFilename, width, height, depth, 0.0f, 0.0f, 0.0f, 0.0f, sourceImage->getImageType(), sourceImage->getFormat()); if (!currentTargetImage.get()) { return SmartPointerVector<IImageDataSP>(); } for (int32_t z = 0; z < depth; z++) { for (int32_t y = 0; y < height; y++) { for (int32_t x = 0; x < width; x++) { glm::vec4 rgba = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f); float sampleCount = 0.0f; for (int32_t iz = z * 2; iz < z * 2 + 1; iz++) { for (int32_t iy = y * 2; iy < y * 2 + 1; iy++) { for (int32_t ix = x * 2; ix < x * 2 + 1; ix++) { rgba += currentSourceImage->getTexel(ix, iy, iz); sampleCount += 1.0f; } } } if (sampleCount > 0.0f) { rgba /= sampleCount; currentTargetImage->setTexel(rgba, x, y, z); } } } } result.append(currentTargetImage); // currentSourceImage = currentTargetImage; width = currentSourceImage->getWidth(); height = currentSourceImage->getHeight(); depth = currentSourceImage->getDepth(); } return result; }