From c86b8cbd0074ed24b83c270b20d6597d25af94f870cff6f384b101b31f25294a Mon Sep 17 00:00:00 2001 From: Mexpert_PRO Date: Thu, 26 Mar 2026 18:54:05 +0100 Subject: [PATCH] first Dicom Viewer commit --- .gitignore | 188 ++++----- TSE | 2 +- TSE-RTS/src/game.cpp | 511 +++++++++++++----------- TSE-RTS/src/main.cpp | 273 +++++++------ TSE-RTS/src/shaders/DICOMShader.cpp | 124 ++++++ TSE-RTS/src/shaders/DICOMShader.hpp | 33 ++ TSE-RTS/src/shaders/DICOMShaderGLSL.hpp | 264 ++++++++++++ 7 files changed, 937 insertions(+), 458 deletions(-) create mode 100644 TSE-RTS/src/shaders/DICOMShader.cpp create mode 100644 TSE-RTS/src/shaders/DICOMShader.hpp create mode 100644 TSE-RTS/src/shaders/DICOMShaderGLSL.hpp diff --git a/.gitignore b/.gitignore index 192c4c1..5a85b79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,93 +1,95 @@ -# ---> C++ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Executables -*.exe -*.out -*.app - -# ---> C -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -# ---> CMake -CMakeLists.txt.user -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -_deps -CMakeUserPresets.json - -build -bin -lib \ No newline at end of file +# ---> C++ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Executables +*.exe +*.out +*.app + +# ---> C +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# ---> CMake +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json + +build +bin +lib + +DCM \ No newline at end of file diff --git a/TSE b/TSE index f50b68c..51a6ea1 160000 --- a/TSE +++ b/TSE @@ -1 +1 @@ -Subproject commit f50b68c9ba514b0ecf5df423a632da02bab996dfe9089366d4ad029f253d9931 +Subproject commit 51a6ea13286ecf221a7195002db594e828f4e626479cc248c0e36457c77d0eec diff --git a/TSE-RTS/src/game.cpp b/TSE-RTS/src/game.cpp index 8bbbfef..d5442e7 100644 --- a/TSE-RTS/src/game.cpp +++ b/TSE-RTS/src/game.cpp @@ -1,232 +1,281 @@ -#include "game.hpp" -#include "elements/Transformable.hpp" -#include "BehaviourScripts/TileMap.hpp" -#include "BehaviourScripts/OrdererSpriteSet.hpp" -#include "BehaviourScripts/Renderable.hpp" -#include "elements/ShaderRegistry.hpp" -#include "Vector2.hpp" -#include -#include "PerlinNoise.hpp" -#include "BehaviourScripts/Camera.hpp" -#include "interfaces/IRenderTexture.hpp" -#include "BehaviourScripts/MeshContainer.hpp" -#include "BehaviourScripts/CameraSizeChangeNotifyer.hpp" -#include "BehaviourScripts/RenderTextureResizes.hpp" -#include "BehaviourScripts/CanvasScaler.hpp" -#include "Random.hpp" - -#define circleRadius 32 -#define circleFallof 25 -#define treeCircleRadius 27 -#define treeCircleFallof 20 - -void game::setup(TSE::Scene* s, TSE::IWindow* wnd) -{ - using namespace TSE; - s->AddLayer(&gameLayer); - s->AddLayer(&propsLayer); - - TileMap* maps[4]; - OrdererSpriteSet* props; - Material* tileMapMaterial = new Material("tileSetMat", ShaderRegistry::GetShader("TileMapShader v2")); - tileMapMaterial->SetValue("spritePivot", Vector2(0,0)); - Texture* setTexture = new Texture("tiles.png"); - TileSet* set = new TileSet(setTexture, 10, 10); - - for (int i = 0; i < 4; i++) - { - Transformable* tileMap = new Transformable("tileMapL" + std::to_string(i)); - tileMap->position += {0,0.5f * i,0}; - gameLayer.AddTransformable(tileMap); - TileMap* map = new TileMap(); - map->chunkSize = 12; - map->set = set; - - Renderable* rnd = new Renderable(tileMapMaterial); - - tileMap->AddBehaviourScript(map); - tileMap->AddBehaviourScript(rnd); - - maps[i] = map; - } - - Material* objectsMaterial = new Material("objectsTileSetMat", ShaderRegistry::GetShader("Basic Ordered Sprite Set Shader")); - Texture* treeSetTexture = new Texture("trees.png"); - TileSet* treeSet = new TileSet(treeSetTexture, 6, 2); - Transformable* tileMap = new Transformable("propMap"); - propsLayer.AddTransformable(tileMap); - OrdererSpriteSet* map = new OrdererSpriteSet(); - map->chunkSize = 12; - map->set = treeSet; - //map->SpriteScale = Vector2(1,2); - - Renderable* rend = new Renderable(objectsMaterial); - - tileMap->AddBehaviourScript(map); - tileMap->AddBehaviourScript(rend); - - props = map; - - - Random rnd = Random(12345u); - - const siv::PerlinNoise perlin{ rnd.nextUInt() }; - const siv::PerlinNoise perlin2{ rnd.nextUInt() }; - - for (int x = circleRadius * -4; x < circleRadius * 4; x++) - { - for (int y = circleRadius * -4; y < circleRadius * 4; y++) - { - float noise = (float)perlin.octave2D_01(x * 0.05f,y * 0.05f, 4); - float treeNoise = (float)perlin2.octave2D_01(x * 0.05f,y * 0.05f, 2); - float noiseFallof = 1; - float treeNoiseFallof = 1; - Vector2 realpos = maps[0]->TileMapToRealPos(Vector2(x,y)); - Vector2 realposprop = (maps[0]->TileMapToRealPos(Vector2(x,y)) + Vector2(0, 0.25f)) * Vector2(1,0.5f); - realpos *= {1,1.5f}; - float dist = realpos.Length(); - if(dist <= circleRadius && dist >= circleFallof) - { - float reldist = dist - circleFallof; - noiseFallof = (reldist / (circleRadius - circleFallof) - 1) * -1; - } - if(dist <= treeCircleRadius && dist >= treeCircleFallof) - { - float reldist = dist - treeCircleFallof; - treeNoiseFallof = (reldist / (treeCircleRadius - treeCircleFallof) - 1) * -1; - } - else if (dist > treeCircleRadius) - treeNoiseFallof = 0; - noise *= noiseFallof; - treeNoise *= treeNoiseFallof; - if(dist <= circleRadius && noise >= 0.2f) - { - float treernd = rnd.nextFloat01(); - int treeid = 0; - if(noise >= 0.8f) - { - if(treeNoise > 0.5f && treernd > 0.4f) - { - treeid = rnd.nextInt(0,5); - props->SetSprite(realposprop + Vector2(0, 0.75f), Vector2(treeid, 1), 4.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); - } - maps[3]->SetTile(Vector2(x, y), {0,9}, {1,9}); - } - else if(noise >= 0.6f) - { - if(treeNoise > 0.5f && treernd > 0.4f) - { - treeid = rnd.nextInt(0,5); - props->SetSprite(realposprop + Vector2(0, 0.5f), Vector2(treeid, 1), 3.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); - } - maps[2]->SetTile(Vector2(x, y), {0,9}, {1,9}); - } - else if(noise >= 0.4f) - { - if(treeNoise > 0.5f && treernd > 0.4f) - { - treeid = rnd.nextInt(0,5); - props->SetSprite(realposprop + Vector2(0, 0.25f), Vector2(treeid, 1), 2.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); - } - maps[1]->SetTile(Vector2(x, y), {0,9}, {1,9}); - } - else - { - if(treeNoise > 0.5f && treernd > 0.4f) - { - treeid = rnd.nextInt(0,5); - props->SetSprite(realposprop, Vector2(treeid, 1), 1.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); - } - maps[0]->SetTile(Vector2(x, y), {0,9}, {1,9}); - } - } - } - } - - //RenderingLayer - - s->AddLayer(&renderingLayer); - s->AddLayer(&characterLayer); - - Transformable* player = new Transformable("Player"); - - Transformable* lastPassCamera = new Transformable("lastPassCamera"); - Camera* lpCam = new Camera(); - lpCam->SetRenderTarget(wnd); - lpCam->SetRenderScale(1); - lpCam->layersNotToRender.push_back(gameLayer.GetID()); - lpCam->layersNotToRender.push_back(propsLayer.GetID()); - lpCam->layersNotToRender.push_back(characterLayer.GetID()); - lastPassCamera->AddBehaviourScript(lpCam); - CameraSizeChangeNotifyer* camNotifyer = new CameraSizeChangeNotifyer(); - camNotifyer->lastSize = {0,0}; - camNotifyer->camToObserver = lpCam; - lastPassCamera->AddBehaviourScript(camNotifyer); - - Vector2 canvasSize = wnd->GetSize() / 4.0f; - - IRenderTexture* rt = IRenderTexture::factory->CreateTextureHeap(canvasSize, 3); - Transformable* firstPassCamera = new Transformable("firstPassCamera"); - Camera* fpCam = new Camera(); - fpCam->SetRenderScale(256); - fpCam->SetRenderTarget(rt); - fpCam->layersNotToRender.push_back(renderingLayer.GetID()); - fpCam->layersNotToRender.push_back(propsLayer.GetID()); - fpCam->layersNotToRender.push_back(characterLayer.GetID()); - firstPassCamera->AddBehaviourScript(fpCam); - RenderTextureResizes* resizer = new RenderTextureResizes(); - resizer->rt = rt; - camNotifyer->Observe(resizer); - firstPassCamera->AddBehaviourScript(resizer); - firstPassCamera->SetParent(player); - - IRenderTexture* rtProps = IRenderTexture::factory->CreateTextureHeap(canvasSize, 3); - Transformable* secondPassCamera = new Transformable("secondPassCamera"); - Camera* spCam = new Camera(); - spCam->SetRenderScale(256); - spCam->SetRenderTarget(rtProps); - spCam->layersNotToRender.push_back(renderingLayer.GetID()); - spCam->layersNotToRender.push_back(gameLayer.GetID()); - spCam->layersNotToRender.push_back(characterLayer.GetID()); - secondPassCamera->AddBehaviourScript(spCam); - RenderTextureResizes* resizerProps = new RenderTextureResizes(); - resizerProps->rt = rtProps; - camNotifyer->Observe(resizerProps); - secondPassCamera->AddBehaviourScript(resizerProps); - secondPassCamera->SetParent(player); - - //Render pipeline setup - - characterLayer.AddTransformable(player); - renderingLayer.AddTransformable(lastPassCamera); - - //final - - Mesh* canvasMesh = new Mesh(Mesh::GetQuadMesh()); - for(auto& vertex : canvasMesh->vertecies) - { - vertex *= wnd->GetSize(); - } - MeshContainer* canvasContainer = new MeshContainer(canvasMesh); - - Material* canvasMat = new Material("canvasMat", ShaderRegistry::GetShader("LastPassShader")); - canvasMat->SetValue("threshold", 0.01f); - canvasMat->SetValue("darken", 0.15f); - canvasMat->SetValue("colorTextureID", rt->GetTextureId(0)); - canvasMat->SetValue("heightTextureID", rt->GetTextureId(1)); - canvasMat->SetValue("depthTextureID", rt->GetTextureId(2)); - canvasMat->SetValue("colorTexture2ID", rtProps->GetTextureId(0)); - canvasMat->SetValue("heightTexture2ID", rtProps->GetTextureId(1)); - canvasMat->SetValue("depthTexture2ID", rtProps->GetTextureId(2)); - Renderable* canvasRenderer = new Renderable(canvasMat); - - CanvasScaler* canvasScaler = new CanvasScaler(); - canvasScaler->mesh = canvasMesh; - camNotifyer->Observe(canvasScaler); - - lastPassCamera->AddBehaviourScript(canvasContainer); - lastPassCamera->AddBehaviourScript(canvasRenderer); - lastPassCamera->AddBehaviourScript(canvasScaler); - - //propper resize stuff for prior passes, and canvas, and implement LastPassShader siehe dazu den chat: https://chatgpt.com/c/69985c47-6a50-838b-852d-45bb0b8454e5 +#include "game.hpp" +#include "elements/Transformable.hpp" +#include "BehaviourScripts/TileMap.hpp" +#include "BehaviourScripts/OrdererSpriteSet.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "elements/ShaderRegistry.hpp" +#include "Vector2.hpp" +#include "Vector3.hpp" +#include +#include "PerlinNoise.hpp" +#include "BehaviourScripts/Camera.hpp" +#include "interfaces/IRenderTexture.hpp" +#include "BehaviourScripts/MeshContainer.hpp" +#include "BehaviourScripts/CameraSizeChangeNotifyer.hpp" +#include "BehaviourScripts/RenderTextureResizes.hpp" +#include "BehaviourScripts/CanvasScaler.hpp" +#include "Random.hpp" +#include "elements/VolumeTexture3D.hpp" + +#define circleRadius 32 +#define circleFallof 25 +#define treeCircleRadius 27 +#define treeCircleFallof 20 + +void game::setup(TSE::Scene* s, TSE::IWindow* wnd) +{ + using namespace TSE; + //s->AddLayer(&gameLayer); + // s->AddLayer(&propsLayer); + + // TileMap* maps[4]; + // OrdererSpriteSet* props; + // Material* tileMapMaterial = new Material("tileSetMat", ShaderRegistry::GetShader("TileMapShader v2")); + // tileMapMaterial->SetValue("spritePivot", Vector2(0,0)); + // Texture* setTexture = new Texture("tiles.png"); + // TileSet* set = new TileSet(setTexture, 10, 10); + + // for (int i = 0; i < 4; i++) + // { + // Transformable* tileMap = new Transformable("tileMapL" + std::to_string(i)); + // tileMap->position += {0,0.5f * i,0}; + // gameLayer.AddTransformable(tileMap); + // TileMap* map = new TileMap(); + // map->chunkSize = 12; + // map->set = set; + + // Renderable* rnd = new Renderable(tileMapMaterial); + + // tileMap->AddBehaviourScript(map); + // tileMap->AddBehaviourScript(rnd); + + // maps[i] = map; + // } + + // Material* objectsMaterial = new Material("objectsTileSetMat", ShaderRegistry::GetShader("Basic Ordered Sprite Set Shader")); + // Texture* treeSetTexture = new Texture("trees.png"); + // TileSet* treeSet = new TileSet(treeSetTexture, 6, 2); + // Transformable* tileMap = new Transformable("propMap"); + // propsLayer.AddTransformable(tileMap); + // OrdererSpriteSet* map = new OrdererSpriteSet(); + // map->chunkSize = 12; + // map->set = treeSet; + // //map->SpriteScale = Vector2(1,2); + + // Renderable* rend = new Renderable(objectsMaterial); + + // tileMap->AddBehaviourScript(map); + // tileMap->AddBehaviourScript(rend); + + // props = map; + + + // Random rnd = Random(12345u); + + // const siv::PerlinNoise perlin{ rnd.nextUInt() }; + // const siv::PerlinNoise perlin2{ rnd.nextUInt() }; + + // for (int x = circleRadius * -4; x < circleRadius * 4; x++) + // { + // for (int y = circleRadius * -4; y < circleRadius * 4; y++) + // { + // float noise = (float)perlin.octave2D_01(x * 0.05f,y * 0.05f, 4); + // float treeNoise = (float)perlin2.octave2D_01(x * 0.05f,y * 0.05f, 2); + // float noiseFallof = 1; + // float treeNoiseFallof = 1; + // Vector2 realpos = maps[0]->TileMapToRealPos(Vector2(x,y)); + // Vector2 realposprop = (maps[0]->TileMapToRealPos(Vector2(x,y)) + Vector2(0, 0.25f)) * Vector2(1,0.5f); + // realpos *= {1,1.5f}; + // float dist = realpos.Length(); + // if(dist <= circleRadius && dist >= circleFallof) + // { + // float reldist = dist - circleFallof; + // noiseFallof = (reldist / (circleRadius - circleFallof) - 1) * -1; + // } + // if(dist <= treeCircleRadius && dist >= treeCircleFallof) + // { + // float reldist = dist - treeCircleFallof; + // treeNoiseFallof = (reldist / (treeCircleRadius - treeCircleFallof) - 1) * -1; + // } + // else if (dist > treeCircleRadius) + // treeNoiseFallof = 0; + // noise *= noiseFallof; + // treeNoise *= treeNoiseFallof; + // if(dist <= circleRadius && noise >= 0.2f) + // { + // float treernd = rnd.nextFloat01(); + // int treeid = 0; + // if(noise >= 0.8f) + // { + // if(treeNoise > 0.5f && treernd > 0.4f) + // { + // treeid = rnd.nextInt(0,5); + // props->SetSprite(realposprop + Vector2(0, 0.75f), Vector2(treeid, 1), 4.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); + // } + // maps[3]->SetTile(Vector2(x, y), {0,9}, {1,9}); + // } + // else if(noise >= 0.6f) + // { + // if(treeNoise > 0.5f && treernd > 0.4f) + // { + // treeid = rnd.nextInt(0,5); + // props->SetSprite(realposprop + Vector2(0, 0.5f), Vector2(treeid, 1), 3.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); + // } + // maps[2]->SetTile(Vector2(x, y), {0,9}, {1,9}); + // } + // else if(noise >= 0.4f) + // { + // if(treeNoise > 0.5f && treernd > 0.4f) + // { + // treeid = rnd.nextInt(0,5); + // props->SetSprite(realposprop + Vector2(0, 0.25f), Vector2(treeid, 1), 2.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); + // } + // maps[1]->SetTile(Vector2(x, y), {0,9}, {1,9}); + // } + // else + // { + // if(treeNoise > 0.5f && treernd > 0.4f) + // { + // treeid = rnd.nextInt(0,5); + // props->SetSprite(realposprop, Vector2(treeid, 1), 1.5f / 10.0f, Vector2(1,2), Vector2(treeid, 0)); + // } + // maps[0]->SetTile(Vector2(x, y), {0,9}, {1,9}); + // } + // } + // } + // } + + //RenderingLayer + + s->AddLayer(&renderingLayer); + + float smallDicomDevider = 8.0f; + + VolumeTexture3D* dicom = new VolumeTexture3D("./DCM"); + Vector3 textureSize = {dicom->Width(), dicom->Height(), dicom->Depth()}; + Vector3 smallTextureSize = { ceilf(textureSize.x / smallDicomDevider), ceilf(textureSize.y / smallDicomDevider), ceilf(textureSize.z / smallDicomDevider)}; + VolumeTexture3D* dicomSmall = new VolumeTexture3D(smallTextureSize, 32); + + for(int x = 0; x < smallTextureSize.x; x++) + { + for(int y = 0; y < smallTextureSize.y; y++) + { + for(int z = 0; z < smallTextureSize.z; z++) + { + float value = 0; + for(int sx = 0; sx < smallDicomDevider; sx++) + { + for(int sy = 0; sy < smallDicomDevider; sy++) + { + for(int sz = 0; sz < smallDicomDevider; sz++) + { + Color c; + Vector3 pos = Vector3(x * 8 + sx, y * 8 + sy, z * 8 + sz); + if(pos.x < dicom->Width() && pos.y < dicom->Height() && pos.z < dicom->Depth()) + { + dicom->GetPixel(pos, c); + value = fmax(value, c.r); + } + } + } + } + dicomSmall->SetPixelNoApply(x,y,z, Color(value, value, value, value)); + } + } + } + dicomSmall->Apply(); + + + + //s->AddLayer(&characterLayer); + + Transformable* player = new Transformable("Player"); + + Transformable* lastPassCamera = new Transformable("lastPassCamera"); + Camera* lpCam = new Camera(); + lpCam->SetRenderTarget(wnd); + lpCam->SetRenderScale(0.0025f); + lpCam->SetFarClippingPlane(1000); + lpCam->layersNotToRender.push_back(gameLayer.GetID()); + lpCam->layersNotToRender.push_back(propsLayer.GetID()); + lpCam->layersNotToRender.push_back(characterLayer.GetID()); + lastPassCamera->AddBehaviourScript(lpCam); + CameraSizeChangeNotifyer* camNotifyer = new CameraSizeChangeNotifyer(); + camNotifyer->lastSize = {0,0}; + camNotifyer->camToObserver = lpCam; + lastPassCamera->AddBehaviourScript(camNotifyer); + lastPassCamera->position = Vector3(-0.7f, -0.1f, 0); + lastPassCamera->SetEuler(Vector3(-16.7f, 0.3f, -0.2f)); + + Vector2 canvasSize = wnd->GetSize() / 4.0f; + + // IRenderTexture* rt = IRenderTexture::factory->CreateTextureHeap(canvasSize, 3); + // Transformable* firstPassCamera = new Transformable("firstPassCamera"); + // Camera* fpCam = new Camera(); + // fpCam->SetRenderScale(256); + // fpCam->SetRenderTarget(rt); + // fpCam->layersNotToRender.push_back(renderingLayer.GetID()); + // fpCam->layersNotToRender.push_back(propsLayer.GetID()); + // fpCam->layersNotToRender.push_back(characterLayer.GetID()); + // firstPassCamera->AddBehaviourScript(fpCam); + // RenderTextureResizes* resizer = new RenderTextureResizes(); + // resizer->rt = rt; + // camNotifyer->Observe(resizer); + // firstPassCamera->AddBehaviourScript(resizer); + // firstPassCamera->SetParent(player); + + // IRenderTexture* rtProps = IRenderTexture::factory->CreateTextureHeap(canvasSize, 3); + // Transformable* secondPassCamera = new Transformable("secondPassCamera"); + // Camera* spCam = new Camera(); + // spCam->SetRenderScale(256); + // spCam->SetRenderTarget(rtProps); + // spCam->layersNotToRender.push_back(renderingLayer.GetID()); + // spCam->layersNotToRender.push_back(gameLayer.GetID()); + // spCam->layersNotToRender.push_back(characterLayer.GetID()); + // secondPassCamera->AddBehaviourScript(spCam); + // RenderTextureResizes* resizerProps = new RenderTextureResizes(); + // resizerProps->rt = rtProps; + // camNotifyer->Observe(resizerProps); + // secondPassCamera->AddBehaviourScript(resizerProps); + // secondPassCamera->SetParent(player); + + //Render pipeline setup + + // characterLayer.AddTransformable(player); + renderingLayer.AddTransformable(lastPassCamera); + + //final + + Mesh* canvasMesh = new Mesh(Mesh::GetQuadMesh()); + for(auto& vertex : canvasMesh->vertecies) + { + vertex *= 2; + } + MeshContainer* canvasContainer = new MeshContainer(canvasMesh); + + Material* canvasMat = new Material("canvasMat", ShaderRegistry::GetShader("DICOMShader")); + canvasMat->SetValue("threshold", 0.4f); + canvasMat->SetValue("stepSize", 0.01f); + canvasMat->SetValue("texSize", textureSize); + canvasMat->SetValue("smallTexSize", smallTextureSize); + Vector3 objectScale = Vector3(1,1,1); + canvasMat->SetValue("ObjectScale", objectScale); + canvasMat->SetValue("DICOM", dicom); + canvasMat->SetValue("DICOMsmall", dicomSmall); + // canvasMat->SetValue("heightTextureID", rt->GetTextureId(1)); + // canvasMat->SetValue("depthTextureID", rt->GetTextureId(2)); + // canvasMat->SetValue("colorTexture2ID", rtProps->GetTextureId(0)); + // canvasMat->SetValue("heightTexture2ID", rtProps->GetTextureId(1)); + // canvasMat->SetValue("depthTexture2ID", rtProps->GetTextureId(2)); + Renderable* canvasRenderer = new Renderable(canvasMat); + + CanvasScaler* canvasScaler = new CanvasScaler(); + canvasScaler->mesh = canvasMesh; + camNotifyer->Observe(canvasScaler); + + lastPassCamera->AddBehaviourScript(canvasContainer); + lastPassCamera->AddBehaviourScript(canvasRenderer); + lastPassCamera->AddBehaviourScript(canvasScaler); + + //propper resize stuff for prior passes, and canvas, and implement LastPassShader siehe dazu den chat: https://chatgpt.com/c/69985c47-6a50-838b-852d-45bb0b8454e5 } \ No newline at end of file diff --git a/TSE-RTS/src/main.cpp b/TSE-RTS/src/main.cpp index c01c293..23ccf7a 100644 --- a/TSE-RTS/src/main.cpp +++ b/TSE-RTS/src/main.cpp @@ -1,134 +1,141 @@ -#include -#include "GL/gl3w.h" -#include "globalVars.hpp" -#include "WindowManager.hpp" -#if defined(TSE_GLFW) -#include "WindowGlfw.hpp" -#elif defined(TSE_SDL3) -#include "WindowSdl3.hpp" -#endif -#include "OpenGLRenderingBackend.hpp" -#include "imgui/imgui.h" -#include "shader/defaultShaderHandler.cpp" -#include "DefaultRendererOpenGL.hpp" -#include "BehaviourScripts/RectBase.hpp" -#include "BehaviourScripts/Renderable.hpp" -#include "BehaviourScripts/Camera.hpp" -#include "elements/Sprite.hpp" -#include "elements/Texture.hpp" -#include "elements/Layer.hpp" -#include "elements/Scene.hpp" -#include "EditorSubsystem.hpp" -#include "game.hpp" -#include "shaders/TileMapShader.hpp" -#include "shaders/LastPassShader.hpp" - -#define USE_EDITOR - -using namespace TSE; -#if defined(TSE_GLFW) -using namespace TSE::GLFW; -#elif defined(TSE_SDL3) -using namespace TSE::SDL3; -#endif -using namespace TSE::OpenGL; -using namespace TSE::EDITOR; - -IWindow* wnd = nullptr; -DefaultRendererOpenGL* rend = nullptr; -Scene* currentScene = nullptr; -Layer* planeteryLayer = nullptr; -EditorSubsystem* editor; - -void SetupWindow() -{ - Color backColor(0.0f, 0.0f, 0.0f, 0.0f); -#if defined(TSE_GLFW) -#ifdef USE_EDITOR - wnd = new WindowGlfw(PROJECT_NAME, 800, 600, new OpenGLRenderingBackend(backColor, false, 8, true), WindowType::Maximized); - editor = new EditorSubsystem(); -#else - wnd = new WindowGlfw(PROJECT_NAME, 1920, 1080, new OpenGLRenderingBackend(backColor, false, 8, false), WindowType::Fullscreen); -#endif -#elif defined(TSE_SDL3) -#ifdef USE_EDITOR - wnd = new WindowSdl3(PROJECT_NAME, 800, 600, new OpenGLRenderingBackend(backColor, false, 8, true), WindowType::Maximized); - editor = new EditorSubsystem(); -#else - wnd = new WindowSdl3(PROJECT_NAME, 1920, 1080, new OpenGLRenderingBackend(backColor, false, 8, false), WindowType::Fullscreen); -#endif -#endif - - LoadBasicShaders(wnd->GetSize().x, wnd->GetSize().y); - TileMapShader::Init(wnd->GetSize().x, wnd->GetSize().y); - LastPassShader::Init(wnd->GetSize().x, wnd->GetSize().y); - ShaderRegistry::SetShader("TileMapShader v2", TileMapShader::Instance()); - ShaderRegistry::SetShader("LastPassShader", LastPassShader::Instance()); - - rend = new DefaultRendererOpenGL(*BasicShader::Instance()); - currentScene = new Scene(); - - #ifdef USE_EDITOR - ((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->layersNotToRender.push_back(game::renderingLayer.GetID()); - ((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->SetRenderScale(128); - currentScene->AddLayer(&editor->editorLayer); - editor->hv.SetScene(currentScene); - #endif - - - game::setup(currentScene, wnd); - - wnd->DoneSetup(); -} - -void CleanUp() -{ -#ifdef USE_EDITOR - delete(editor); -#endif - - UnLoadBasicShaders(); -} - -void GameLoop() -{ - while(!wnd->ShouldClose()) - { - wnd->Clear(); - rend->Begin(); - - if(currentScene != nullptr) - currentScene->Render(*rend, *wnd); - - rend->End(); - rend->Flush(); - - if(currentScene != nullptr) - currentScene->DoneRender(); - -#ifdef USE_EDITOR - editor->controller.Update(); -#endif - wnd->Update(); - if(currentScene != nullptr) - currentScene->Update(); - } -} - - -int main(int argc, char** argv) -{ - SetupWindow(); - - GameLoop(); - - CleanUp(); - return 0; -} - -#if defined(_WIN32) -extern "C" { - __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; // NVIDIA - __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; // AMD -} +#include +#include "GL/gl3w.h" +#include "globalVars.hpp" +#include "WindowManager.hpp" +#if defined(TSE_GLFW) +#include "WindowGlfw.hpp" +#elif defined(TSE_SDL3) +#include "WindowSdl3.hpp" +#endif +#include "OpenGLRenderingBackend.hpp" +#include "imgui/imgui.h" +#include "shader/defaultShaderHandler.cpp" +#include "DefaultRendererOpenGL.hpp" +#include "BehaviourScripts/RectBase.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "BehaviourScripts/Camera.hpp" +#include "elements/Sprite.hpp" +#include "elements/Texture.hpp" +#include "elements/Layer.hpp" +#include "elements/Scene.hpp" +#include "EditorSubsystem.hpp" +#include "game.hpp" +#include "shaders/TileMapShader.hpp" +#include "shaders/LastPassShader.hpp" +#include "shaders/DICOMShader.hpp" + +#define USE_EDITOR + +using namespace TSE; +#if defined(TSE_GLFW) +using namespace TSE::GLFW; +#elif defined(TSE_SDL3) +using namespace TSE::SDL3; +#endif +using namespace TSE::OpenGL; +using namespace TSE::EDITOR; + +IWindow* wnd = nullptr; +DefaultRendererOpenGL* rend = nullptr; +Scene* currentScene = nullptr; +Layer* planeteryLayer = nullptr; +EditorSubsystem* editor; + +void SetupWindow() +{ + Color backColor(0.0f, 0.0f, 0.0f, 0.0f); +#if defined(TSE_GLFW) +#ifdef USE_EDITOR + wnd = new WindowGlfw(PROJECT_NAME, 800, 600, new OpenGLRenderingBackend(backColor, false, 8, true), WindowType::Maximized); + editor = new EditorSubsystem(); +#else + wnd = new WindowGlfw(PROJECT_NAME, 1920, 1080, new OpenGLRenderingBackend(backColor, false, 8, false), WindowType::Fullscreen); +#endif +#elif defined(TSE_SDL3) +#ifdef USE_EDITOR + wnd = new WindowSdl3(PROJECT_NAME, 800, 600, new OpenGLRenderingBackend(backColor, false, 8, true), WindowType::Maximized); + editor = new EditorSubsystem(); +#else + wnd = new WindowSdl3(PROJECT_NAME, 1920, 1080, new OpenGLRenderingBackend(backColor, false, 8, false), WindowType::Fullscreen); +#endif +#endif + + LoadBasicShaders(wnd->GetSize().x, wnd->GetSize().y); + TileMapShader::Init(wnd->GetSize().x, wnd->GetSize().y); + LastPassShader::Init(wnd->GetSize().x, wnd->GetSize().y); + DICOMShader::Init(wnd->GetSize().x, wnd->GetSize().y); + ShaderRegistry::SetShader("TileMapShader v2", TileMapShader::Instance()); + ShaderRegistry::SetShader("LastPassShader", LastPassShader::Instance()); + ShaderRegistry::SetShader("DICOMShader", DICOMShader::Instance()); + + rend = new DefaultRendererOpenGL(*BasicShader::Instance()); + currentScene = new Scene(); + + #ifdef USE_EDITOR + //((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->layersNotToRender.push_back(game::renderingLayer.GetID()); + ((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->SetRenderScale(0.002f); + ((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->SetFarClippingPlane(1000); + ((Camera*)Transformable::Find(".EditorCamera")->GetBehaviourScript(CAMERA))->SetNearClippingPlane(0.1f); + Transformable::Find(".EditorCamera")->position = Vector3(-30.678f, 618.352f, 139.872f); + Transformable::Find(".EditorCamera")->rotation = Quaternion::FromEulerAngles(Vector3(86.348f, -0.450f, 9.699f)); + currentScene->AddLayer(&editor->editorLayer); + editor->hv.SetScene(currentScene); + #endif + + + game::setup(currentScene, wnd); + + wnd->DoneSetup(); +} + +void CleanUp() +{ +#ifdef USE_EDITOR + delete(editor); +#endif + + UnLoadBasicShaders(); +} + +void GameLoop() +{ + while(!wnd->ShouldClose()) + { + wnd->Clear(); + rend->Begin(); + + if(currentScene != nullptr) + currentScene->Render(*rend, *wnd); + + rend->End(); + rend->Flush(); + + if(currentScene != nullptr) + currentScene->DoneRender(); + +#ifdef USE_EDITOR + editor->controller.Update(); +#endif + wnd->Update(); + if(currentScene != nullptr) + currentScene->Update(); + } +} + + +int main(int argc, char** argv) +{ + SetupWindow(); + + GameLoop(); + + CleanUp(); + return 0; +} + +#if defined(_WIN32) +extern "C" { + __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; // NVIDIA + __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; // AMD +} #endif \ No newline at end of file diff --git a/TSE-RTS/src/shaders/DICOMShader.cpp b/TSE-RTS/src/shaders/DICOMShader.cpp new file mode 100644 index 0000000..ee7f02e --- /dev/null +++ b/TSE-RTS/src/shaders/DICOMShader.cpp @@ -0,0 +1,124 @@ +#include "DICOMShader.hpp" + +#include "DICOMShaderGLSL.hpp" +#include "BehaviourScripts/Renderable.hpp" +#include "Color.hpp" + +using namespace TSE; +using namespace TSE::OpenGL; + +#define SHADER_VERTEX_INDEX 0 +#define SHADER_UV_INDEX 1 + +#define SHADER_PACKAGE_SIZE (sizeof(float) * (3 + 2)) + +DICOMShader* DICOMShader::instance = nullptr; + +DICOMShader *DICOMShader::Instance() +{ + return instance; +} + +void DICOMShader::Destroy() +{ + if(instance != nullptr) + delete instance; + instance = nullptr; +} + +void DICOMShader::Init(float width, float height) +{ + std::vector> parts; + parts.push_back(ShaderPart::LoadFromString(vertDICOM, GL_VERTEX_SHADER)); + parts.push_back(ShaderPart::LoadFromString(fragDICOM, GL_FRAGMENT_SHADER)); + instance = new DICOMShader(std::move(parts)); + + instance->Enable(); + instance->SetUniform("DICOMTexture", 0); + instance->SetUniform("SmallDICOMTexture", 1); + instance->SetUniform("Threshold", 0.5f); + instance->SetUniform("TexSize", &Vector3::zero); + instance->SetUniform("SmallTexSize", &Vector3::zero); + instance->SetUniform("StepSize", 0.5f); + instance->Disable(); +} + +DICOMShader::DICOMShader(std::vector> &&parts) : Shader(parts) +{ + PackageSize = SHADER_PACKAGE_SIZE; +} + +void DICOMShader::OnEnable() const +{ + glEnableVertexAttribArray(SHADER_VERTEX_INDEX); + glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)0); + glEnableVertexAttribArray(SHADER_UV_INDEX); + glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, false, SHADER_PACKAGE_SIZE, (void*)(sizeof(float) * 3)); +} + +void DICOMShader::OnDisable() const +{ + glDisableVertexAttribArray(SHADER_VERTEX_INDEX); + glDisableVertexAttribArray(SHADER_UV_INDEX); +} + +void DICOMShader::OnFlush() +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_3D, DICOM->GetTextureId()); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, SmallDICOM->GetTextureId()); + SetUniform("Threshold", Threshold); + if(stepSize < 0.001f) stepSize = 0.001f; + SetUniform("StepSize", stepSize); + SetUniform("TexSize", &size); + SetUniform("SmallTexSize", &smallSize); + SetUniform("ObjectScale", &scale); + SetUniform("BrickScale", 8.0f); +} + +void DICOMShader::OnDrawCall(int indexCount) +{ + glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, NULL); +} + +void DICOMShader::OnSubmit(const TSE::Transformable &t, float *&target, TSE::TransformationStack &stack, void (*restartDrawcall)(TSE::IRenderer &), TSE::IRenderer &rnd) +{ + auto* r = dynamic_cast(t.GetBehaviourScript(RENDERABLE)); + if (!r) return; + if(!r->GetMaterial()->HasValue("threshold")) return; + if(!r->GetMaterial()->HasValue("texSize")) return; + if(!r->GetMaterial()->HasValue("smallTexSize")) return; + if(!r->GetMaterial()->HasValue("DICOM")) return; + if(!r->GetMaterial()->HasValue("DICOMsmall")) return; + if(!r->GetMaterial()->HasValue("stepSize")) return; + if(!r->GetMaterial()->HasValue("ObjectScale")) return; + Threshold = r->GetMaterial()->GetValue("threshold"); + stepSize = r->GetMaterial()->GetValue("stepSize"); + size = r->GetMaterial()->GetValue("texSize"); + smallSize = r->GetMaterial()->GetValue("smallTexSize"); + scale = r->GetMaterial()->GetValue("ObjectScale"); + DICOM = r->GetMaterial()->GetValue("DICOM"); + SmallDICOM = r->GetMaterial()->GetValue("DICOMsmall"); + + const Vector3* verts = r->GetVertices(); + const Vector2* uvs = r->GetUVs(); + ushort vCount = r->GetVertexCount(); + + Matrix4x4 matr = t.GetLocalMatrix(); + + stack.Push(matr); + const Matrix4x4& top = stack.Top(); + + for (ushort i = 0; i < vCount; i++) { + Vector3 p = top * verts[i]; + Vector2 uv = uvs[i]; + *target++ = p.x; + *target++ = p.y; + *target++ = p.z; + *target++ = uv.x; + *target++ = uv.y; + } + + stack.Pop(); +} diff --git a/TSE-RTS/src/shaders/DICOMShader.hpp b/TSE-RTS/src/shaders/DICOMShader.hpp new file mode 100644 index 0000000..ac0dd8a --- /dev/null +++ b/TSE-RTS/src/shaders/DICOMShader.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "GL/gl3w.h" +#include "GL/gl.h" +#include "shader/Shader.hpp" +#include "Types.hpp" +#include "interfaces/ITexture.hpp" + +class DICOMShader : public TSE::OpenGL::Shader +{ +private: + static DICOMShader* instance; + TSE::ITexture* DICOM; + TSE::ITexture* SmallDICOM; + TSE::Vector3 size; + TSE::Vector3 smallSize; + TSE::Vector3 scale; + float Threshold; + float stepSize; + +public: + static DICOMShader* Instance(); + static void Destroy(); + static void Init(float width, float height); + DICOMShader(std::vector>&& parts); + +protected: + void OnEnable() const override; + void OnDisable() const override; + void OnFlush() override; + void OnDrawCall(int indexCount) override; + void OnSubmit(const TSE::Transformable& t, float*& target, TSE::TransformationStack& stack, void (*restartDrawcall)(TSE::IRenderer&), TSE::IRenderer& rnd) override; +}; diff --git a/TSE-RTS/src/shaders/DICOMShaderGLSL.hpp b/TSE-RTS/src/shaders/DICOMShaderGLSL.hpp new file mode 100644 index 0000000..7794205 --- /dev/null +++ b/TSE-RTS/src/shaders/DICOMShaderGLSL.hpp @@ -0,0 +1,264 @@ +#pragma once + +inline const char* vertDICOM = R"( + #version 330 core + + layout (location = 0) in vec3 position; + layout (location = 1) in vec2 uv; + + uniform mat4 prMatrix; + uniform mat4 camMatrix; + + out DATA + { + vec2 uv_out; + } vs_out; + + + void main() + { + gl_Position = vec4(position.x, position.y, 0.0, 1.0); + vs_out.uv_out = uv; + } +)"; + +inline const char* fragDICOM = R"( + #version 330 core + layout (location = 0) out vec4 color; + + uniform sampler3D DICOMTexture; + uniform sampler3D SmallDICOMTexture; + + uniform vec3 CamPos; + uniform vec3 CamRight; + uniform vec3 CamUp; + uniform vec3 CamForward; + + uniform float OrthoLeft; + uniform float OrthoRight; + uniform float OrthoBottom; + uniform float OrthoTop; + uniform float NearPlane; + uniform float FarPlane; + + uniform float Threshold; + uniform float StepSize; + uniform vec3 TexSize; + uniform vec3 SmallTexSize; + uniform vec3 ObjectScale; + + uniform float BrickScale; + + in DATA + { + vec2 uv_out; + } fs_in; + + bool IntersectAABB(vec3 rayOrigin, vec3 rayDir, vec3 boxMin, vec3 boxMax, out float tEnter, out float tExit) + { + vec3 invDir = 1.0 / rayDir; + + vec3 t0 = (boxMin - rayOrigin) * invDir; + vec3 t1 = (boxMax - rayOrigin) * invDir; + + vec3 tMin3 = min(t0, t1); + vec3 tMax3 = max(t0, t1); + + tEnter = max(max(tMin3.x, tMin3.y), tMin3.z); + tExit = min(min(tMax3.x, tMax3.y), tMax3.z); + + return tExit >= max(tEnter, 0.0); + } + + void BuildOrthoRay(out vec3 rayOrigin, out vec3 rayDir) + { + vec2 uv = fs_in.uv_out; + + float xView = mix(OrthoLeft, OrthoRight, uv.x); + float yView = mix(OrthoBottom, OrthoTop, uv.y); + + rayOrigin = CamPos + + CamRight * xView + + CamUp * yView + + CamForward * NearPlane; + + rayDir = CamForward; + } + + float TraverseFineBlock(vec3 rayOrigin, vec3 rayDir, float blockTEnter, float blockTExit, ivec3 brickCoord, float brickScaleF, ivec3 gridSize) + { + int brickSize = int(brickScaleF); + + ivec3 blockVoxelMin = brickCoord * brickSize; + ivec3 blockVoxelMax = min(blockVoxelMin + ivec3(brickSize - 1), gridSize - ivec3(1)); + + float t = blockTEnter + 1e-4; + vec3 pos = rayOrigin + rayDir * t; + + ivec3 voxel = ivec3(floor(pos / ObjectScale)); + voxel = clamp(voxel, blockVoxelMin, blockVoxelMax); + + ivec3 step; + step.x = (rayDir.x > 0.0) ? 1 : ((rayDir.x < 0.0) ? -1 : 0); + step.y = (rayDir.y > 0.0) ? 1 : ((rayDir.y < 0.0) ? -1 : 0); + step.z = (rayDir.z > 0.0) ? 1 : ((rayDir.z < 0.0) ? -1 : 0); + + vec3 tDelta; + tDelta.x = (step.x != 0) ? abs(ObjectScale.x / rayDir.x) : 1e30; + tDelta.y = (step.y != 0) ? abs(ObjectScale.y / rayDir.y) : 1e30; + tDelta.z = (step.z != 0) ? abs(ObjectScale.z / rayDir.z) : 1e30; + + vec3 nextBoundary; + nextBoundary.x = (step.x > 0) ? (float(voxel.x) + 1.0) * ObjectScale.x : float(voxel.x) * ObjectScale.x; + nextBoundary.y = (step.y > 0) ? (float(voxel.y) + 1.0) * ObjectScale.y : float(voxel.y) * ObjectScale.y; + nextBoundary.z = (step.z > 0) ? (float(voxel.z) + 1.0) * ObjectScale.z : float(voxel.z) * ObjectScale.z; + + vec3 tMax; + tMax.x = (step.x != 0) ? ((nextBoundary.x - rayOrigin.x) / rayDir.x) : 1e30; + tMax.y = (step.y != 0) ? ((nextBoundary.y - rayOrigin.y) / rayDir.y) : 1e30; + tMax.z = (step.z != 0) ? ((nextBoundary.z - rayOrigin.z) / rayDir.z) : 1e30; + + int maxIters = brickSize * 3 + 8; + + float hits = 0; + + for (int i = 0; i < maxIters; ++i) + { + if (t > blockTExit) + break; + + float density = texelFetch(DICOMTexture, voxel, 0).r; + if (density >= Threshold) + hits++; + + if (tMax.x <= tMax.y && tMax.x <= tMax.z) + { + voxel.x += step.x; + if (voxel.x < blockVoxelMin.x || voxel.x > blockVoxelMax.x) break; + t = tMax.x; + tMax.x += tDelta.x; + } + else if (tMax.y <= tMax.z) + { + voxel.y += step.y; + if (voxel.y < blockVoxelMin.y || voxel.y > blockVoxelMax.y) break; + t = tMax.y; + tMax.y += tDelta.y; + } + else + { + voxel.z += step.z; + if (voxel.z < blockVoxelMin.z || voxel.z > blockVoxelMax.z) break; + t = tMax.z; + tMax.z += tDelta.z; + } + } + + return hits; + } + + vec4 RenderVoxelDDA(vec3 rayOrigin, vec3 rayDir) + { + ivec3 gridSize = ivec3(TexSize); + ivec3 smallGridSize = ivec3(SmallTexSize); + + float brickScaleF = max(BrickScale, 1.0); + int brickSize = int(brickScaleF); + + vec3 scaledSize = TexSize * ObjectScale; + vec3 boxMin = vec3(0.0); + vec3 boxMax = scaledSize; + + float tEnter, tExit; + if (!IntersectAABB(rayOrigin, rayDir, boxMin, boxMax, tEnter, tExit)) + return vec4(0.0, 0.0, 0.0, 1.0); + + tEnter = max(tEnter, 0.0); + tExit = min(tExit, FarPlane - NearPlane); + + vec3 brickWorldSize = ObjectScale * brickScaleF; + + float t = tEnter + 1e-4; + vec3 pos = rayOrigin + rayDir * t; + + ivec3 brick = ivec3(floor(pos / brickWorldSize)); + ivec3 brickMax = smallGridSize - ivec3(1); + brick = clamp(brick, ivec3(0), brickMax); + + ivec3 step; + step.x = (rayDir.x > 0.0) ? 1 : ((rayDir.x < 0.0) ? -1 : 0); + step.y = (rayDir.y > 0.0) ? 1 : ((rayDir.y < 0.0) ? -1 : 0); + step.z = (rayDir.z > 0.0) ? 1 : ((rayDir.z < 0.0) ? -1 : 0); + + vec3 tDelta; + tDelta.x = (step.x != 0) ? abs(brickWorldSize.x / rayDir.x) : 1e30; + tDelta.y = (step.y != 0) ? abs(brickWorldSize.y / rayDir.y) : 1e30; + tDelta.z = (step.z != 0) ? abs(brickWorldSize.z / rayDir.z) : 1e30; + + vec3 nextBoundary; + nextBoundary.x = (step.x > 0) ? (float(brick.x) + 1.0) * brickWorldSize.x : float(brick.x) * brickWorldSize.x; + nextBoundary.y = (step.y > 0) ? (float(brick.y) + 1.0) * brickWorldSize.y : float(brick.y) * brickWorldSize.y; + nextBoundary.z = (step.z > 0) ? (float(brick.z) + 1.0) * brickWorldSize.z : float(brick.z) * brickWorldSize.z; + + vec3 tMax; + tMax.x = (step.x != 0) ? ((nextBoundary.x - rayOrigin.x) / rayDir.x) : 1e30; + tMax.y = (step.y != 0) ? ((nextBoundary.y - rayOrigin.y) / rayDir.y) : 1e30; + tMax.z = (step.z != 0) ? ((nextBoundary.z - rayOrigin.z) / rayDir.z) : 1e30; + + int maxIters = smallGridSize.x + smallGridSize.y + smallGridSize.z + 8; + + float count = 0; + + float increment = StepSize; + + for (int i = 0; i < maxIters; ++i) + { + if (t > tExit) + break; + + float brickDensity = texelFetch(SmallDICOMTexture, brick, 0).r; + + float cellTExit = min(min(tMax.x, tMax.y), tMax.z); + cellTExit = min(cellTExit, tExit); + + if (brickDensity >= Threshold) + { + float hits = TraverseFineBlock(rayOrigin, rayDir, t, cellTExit, brick, brickScaleF, gridSize); + count += hits * increment; + if(count >= 1) break; + } + + if (tMax.x <= tMax.y && tMax.x <= tMax.z) + { + brick.x += step.x; + if (brick.x < 0 || brick.x > brickMax.x) break; + t = tMax.x; + tMax.x += tDelta.x; + } + else if (tMax.y <= tMax.z) + { + brick.y += step.y; + if (brick.y < 0 || brick.y > brickMax.y) break; + t = tMax.y; + tMax.y += tDelta.y; + } + else + { + brick.z += step.z; + if (brick.z < 0 || brick.z > brickMax.z) break; + t = tMax.z; + tMax.z += tDelta.z; + } + } + count = clamp(count, 0.0, 1.0); + + return vec4(count, count, count, 1.0); + } + + void main() + { + vec3 rayOrigin, rayDir; + BuildOrthoRay(rayOrigin, rayDir); + color = RenderVoxelDDA(rayOrigin, rayDir); + } +)";