From c29f5d35485b38a7e384a1b7a05540f05b8d10de Mon Sep 17 00:00:00 2001 From: Martin Gerhardy Date: Mon, 28 Feb 2022 19:03:15 +0100 Subject: [PATCH] VOXEL: started to refactor the palette handling export the palette image for ply mesh exports --- src/games/openworld/client/Client.cpp | 2 +- src/modules/animation/AnimationRenderer.cpp | 12 +- src/modules/backend/loop/ServerLoop.cpp | 2 +- src/modules/backend/tests/EntityTest.h | 2 +- src/modules/backend/tests/MapProviderTest.cpp | 2 +- src/modules/backend/tests/MapTest.cpp | 2 +- src/modules/backend/tests/WorldTest.cpp | 2 +- src/modules/frontend/ClientEntityRenderer.cpp | 15 +- src/modules/rma/tests/MapBuilderTest.cpp | 2 +- src/modules/ui/nuklear/NuklearApp.cpp | 2 +- src/modules/voxel/CMakeLists.txt | 1 + src/modules/voxel/MaterialColor.cpp | 333 ++---------------- src/modules/voxel/MaterialColor.h | 39 +- src/modules/voxel/Palette.cpp | 250 +++++++++++++ src/modules/voxel/Palette.h | 47 ++- .../CubicSurfaceExtractorBenchmark.cpp | 2 +- src/modules/voxel/tests/AbstractVoxelTest.h | 8 +- src/modules/voxel/tests/TestHelper.h | 4 +- src/modules/voxelfont/VoxelFont.cpp | 3 +- src/modules/voxelformat/BinVoxFormat.cpp | 2 +- src/modules/voxelformat/CubFormat.cpp | 10 +- src/modules/voxelformat/Format.cpp | 23 +- src/modules/voxelformat/Format.h | 4 +- src/modules/voxelformat/GoxFormat.cpp | 12 +- src/modules/voxelformat/KV6Format.cpp | 12 +- src/modules/voxelformat/KVXFormat.cpp | 20 +- src/modules/voxelformat/OBJFormat.cpp | 17 +- src/modules/voxelformat/PLYFormat.cpp | 16 +- src/modules/voxelformat/QBCLFormat.cpp | 10 +- src/modules/voxelformat/QBFormat.cpp | 23 +- src/modules/voxelformat/QBTFormat.cpp | 29 +- src/modules/voxelformat/QEFFormat.cpp | 15 +- src/modules/voxelformat/SproxelFormat.cpp | 5 +- src/modules/voxelformat/VXLFormat.cpp | 30 +- src/modules/voxelformat/VXMFormat.cpp | 22 +- src/modules/voxelformat/VolumeFormat.h | 2 +- src/modules/voxelformat/VoxFormat.cpp | 47 +-- src/modules/voxelformat/VoxOldFormat.cpp | 6 +- src/modules/voxelgenerator/LUAGenerator.cpp | 28 +- .../voxelgenerator/tests/LUAGeneratorTest.cpp | 4 +- .../tests/ShapeGeneratorTest.cpp | 2 +- src/modules/voxelrender/CMakeLists.txt | 11 - src/modules/voxelrender/MeshRenderer.cpp | 12 +- src/modules/voxelrender/RawVolumeRenderer.cpp | 22 +- .../voxelrender/tests/MaterialTest.cpp | 53 --- src/modules/voxelutil/ImageUtils.cpp | 4 +- src/modules/voxelutil/VolumeRescaler.h | 14 +- .../voxelutil/tests/ImageUtilsTest.cpp | 6 +- .../voxelworld/benchmarks/VoxelBenchmark.cpp | 2 +- .../voxelworld/tests/AbstractVoxelWorldTest.h | 2 +- .../voxelworldrender/WorldRenderer.cpp | 22 +- src/tests/testanimation/TestAnimation.cpp | 2 +- src/tests/testbiomes/TestBiomes.cpp | 2 +- .../TestComputeTexture3D.cpp | 2 +- src/tests/testgpumc/TestGPUMC.cpp | 2 +- .../testmeshrenderer/TestMeshRenderer.cpp | 2 +- .../TestTextureAtlasRenderer.cpp | 2 +- src/tests/testvoxelfont/TestVoxelFont.cpp | 2 +- src/tests/testvoxelgpu/TestVoxelGPU.cpp | 2 +- src/tools/mapview/MapView.cpp | 2 +- src/tools/thumbnailer/ImageGenerator.cpp | 4 +- src/tools/voxconvert/VoxConvert.cpp | 14 +- .../modules/voxedit-ui/PalettePanel.cpp | 16 +- .../modules/voxedit-ui/ScriptPanel.cpp | 9 +- .../modules/voxedit-util/SceneManager.cpp | 43 ++- .../modifier/ModifierRenderer.cpp | 4 +- 66 files changed, 651 insertions(+), 674 deletions(-) create mode 100644 src/modules/voxel/Palette.cpp delete mode 100644 src/modules/voxelrender/tests/MaterialTest.cpp diff --git a/src/games/openworld/client/Client.cpp b/src/games/openworld/client/Client.cpp index b081b52d9..6d73049ea 100644 --- a/src/games/openworld/client/Client.cpp +++ b/src/games/openworld/client/Client.cpp @@ -213,7 +213,7 @@ app::AppState Client::onInit() { Log::warn("Failed to initialize the sound manager"); } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/modules/animation/AnimationRenderer.cpp b/src/modules/animation/AnimationRenderer.cpp index 79eb1d815..097af92d4 100644 --- a/src/modules/animation/AnimationRenderer.cpp +++ b/src/modules/animation/AnimationRenderer.cpp @@ -37,8 +37,14 @@ bool AnimationRenderer::init() { return false; } + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + const int shaderMaterialColorsArraySize = lengthof(shader::SkeletonData::MaterialblockData::materialcolor); - const int materialColorsArraySize = voxel::getMaterialColors().size(); + const int materialColorsArraySize = palette.colorCount; if (shaderMaterialColorsArraySize != materialColorsArraySize) { Log::error("Shader parameters and material colors don't match in their size: %i - %i", shaderMaterialColorsArraySize, materialColorsArraySize); @@ -46,8 +52,8 @@ bool AnimationRenderer::init() { } shader::SkeletonData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); if (!_shaderData.create(materialBlock)) { Log::error("Failed to create material buffer"); return false; diff --git a/src/modules/backend/loop/ServerLoop.cpp b/src/modules/backend/loop/ServerLoop.cpp index fba7cf139..26a9b83bd 100644 --- a/src/modules/backend/loop/ServerLoop.cpp +++ b/src/modules/backend/loop/ServerLoop.cpp @@ -335,7 +335,7 @@ bool ServerLoop::init() { r->registerHandler(network::ClientMsgType::VarUpdate, std::make_shared()); Log::info("Init material"); - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return false; } diff --git a/src/modules/backend/tests/EntityTest.h b/src/modules/backend/tests/EntityTest.h index c1cc45316..eba95f83e 100644 --- a/src/modules/backend/tests/EntityTest.h +++ b/src/modules/backend/tests/EntityTest.h @@ -74,7 +74,7 @@ protected: core::Var::get(cfg::VoxelMeshSize, "16", core::CV_READONLY); core::Var::get(cfg::DatabaseMinConnections, "0"); core::Var::get(cfg::DatabaseMaxConnections, "0"); - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); entityStorage = std::make_shared(_testApp->eventBus()); protocolHandlerRegistry = core::make_shared(); network = std::make_shared(protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric()); diff --git a/src/modules/backend/tests/MapProviderTest.cpp b/src/modules/backend/tests/MapProviderTest.cpp index b000c0cc3..a2bfc9d3a 100644 --- a/src/modules/backend/tests/MapProviderTest.cpp +++ b/src/modules/backend/tests/MapProviderTest.cpp @@ -39,7 +39,7 @@ public: app::AbstractTest::SetUp(); core::Var::get(cfg::ServerSeed, "1"); core::Var::get(cfg::VoxelMeshSize, "16", core::CV_READONLY); - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _entityStorage = std::make_shared(_testApp->eventBus()); ASSERT_TRUE(_entityStorage->init()); _protocolHandlerRegistry = core::make_shared(); diff --git a/src/modules/backend/tests/MapTest.cpp b/src/modules/backend/tests/MapTest.cpp index 56c29f7ca..0d1ab7a29 100644 --- a/src/modules/backend/tests/MapTest.cpp +++ b/src/modules/backend/tests/MapTest.cpp @@ -35,7 +35,7 @@ public: app::AbstractTest::SetUp(); core::Var::get(cfg::ServerSeed, "1"); core::Var::get(cfg::VoxelMeshSize, "16", core::CV_READONLY); - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _entityStorage = std::make_shared(_testApp->eventBus()); ASSERT_TRUE(_entityStorage->init()); _protocolHandlerRegistry = core::make_shared(); diff --git a/src/modules/backend/tests/WorldTest.cpp b/src/modules/backend/tests/WorldTest.cpp index 3b734df1c..f230eb595 100644 --- a/src/modules/backend/tests/WorldTest.cpp +++ b/src/modules/backend/tests/WorldTest.cpp @@ -39,7 +39,7 @@ public: app::AbstractTest::SetUp(); core::Var::get(cfg::ServerSeed, "1"); core::Var::get(cfg::VoxelMeshSize, "16", core::CV_READONLY); - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _entityStorage = std::make_shared(_testApp->eventBus()); _protocolHandlerRegistry = core::make_shared(); _network = std::make_shared(_protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric()); diff --git a/src/modules/frontend/ClientEntityRenderer.cpp b/src/modules/frontend/ClientEntityRenderer.cpp index 5728db6fc..167bb7f76 100644 --- a/src/modules/frontend/ClientEntityRenderer.cpp +++ b/src/modules/frontend/ClientEntityRenderer.cpp @@ -49,8 +49,15 @@ bool ClientEntityRenderer::init() { Log::error("Failed to init the animation system"); return false; } + + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + const int shaderMaterialColorsArraySize = lengthof(shader::SkeletonData::MaterialblockData::materialcolor); - const int materialColorsArraySize = (int)voxel::getMaterialColors().size(); + const int materialColorsArraySize = palette.colorCount; if (shaderMaterialColorsArraySize != materialColorsArraySize) { Log::error("Shader parameters and material colors don't match in their size: %i - %i", shaderMaterialColorsArraySize, materialColorsArraySize); @@ -58,8 +65,8 @@ bool ClientEntityRenderer::init() { } shader::SkeletonData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); _materialBlock.create(materialBlock); video::TextureConfig textureCfg; @@ -182,7 +189,7 @@ int ClientEntityRenderer::renderEntities(const core::List& entiti _chrShader.setFogrange(_fogRange); _chrShader.setFocuspos(_focusPos); _chrShader.setLightdir(shadow.sunDirection()); - _chrShader.setTime(_seconds); + _chrShader.setTime((float)_seconds); _chrShader.setClipplane(clipPlane); _chrShader.setViewprojection(viewProjectionMatrix); diff --git a/src/modules/rma/tests/MapBuilderTest.cpp b/src/modules/rma/tests/MapBuilderTest.cpp index b8e561612..adb2c3a14 100644 --- a/src/modules/rma/tests/MapBuilderTest.cpp +++ b/src/modules/rma/tests/MapBuilderTest.cpp @@ -28,7 +28,7 @@ protected: voxelformat::VolumeCachePtr _volumeCache; bool onInitApp() override { - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _volumeCache = std::make_shared(); if (!_volumeCache->init()) { return false; diff --git a/src/modules/ui/nuklear/NuklearApp.cpp b/src/modules/ui/nuklear/NuklearApp.cpp index 215425818..fd768b0df 100644 --- a/src/modules/ui/nuklear/NuklearApp.cpp +++ b/src/modules/ui/nuklear/NuklearApp.cpp @@ -227,7 +227,7 @@ app::AppState NuklearApp::onInit() { return app::AppState::InitFailure; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the material colors"); return app::AppState::InitFailure; } diff --git a/src/modules/voxel/CMakeLists.txt b/src/modules/voxel/CMakeLists.txt index c011be43c..570a70732 100644 --- a/src/modules/voxel/CMakeLists.txt +++ b/src/modules/voxel/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRCS MaterialColor.h MaterialColor.cpp Mesh.h Mesh.cpp Morton.h + Palette.h Palette.cpp PagedVolume.h PagedVolume.cpp PagedVolumeSampler.cpp PagedVolumeChunk.cpp PagedVolumeWrapper.h PagedVolumeWrapper.cpp diff --git a/src/modules/voxel/MaterialColor.cpp b/src/modules/voxel/MaterialColor.cpp index b286ce012..320d47b5b 100644 --- a/src/modules/voxel/MaterialColor.cpp +++ b/src/modules/voxel/MaterialColor.cpp @@ -34,58 +34,37 @@ static MaterialColor* luamaterial_getmaterialcolor(lua_State*s) { class MaterialColor { private: - MaterialColorArray _materialColors; - MaterialColorArray _glowColors; core::Map _colorMapping; bool _initialized = false; bool _dirty = false; + Palette _palette; public: - MaterialColor() { - _glowColors.resize(256); - } bool initialized() const { return _initialized; } - bool init(const uint8_t* paletteBuffer, size_t paletteBufferSize, const core::String& luaString) { + inline Palette &palette() { + return _palette; + } + + bool init(const Palette& palette) { if (_initialized) { Log::debug("MaterialColors are already initialized"); return true; } + _palette = palette; _initialized = true; _dirty = true; - _materialColors.reserve(256); - _glowColors.fill(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - const size_t colors = paletteBufferSize / 4; - if (colors > _materialColors.capacity()) { - Log::error("Palette image has invalid dimensions - we need max 256x1(depth: 4)"); - return false; - } - const uint32_t* paletteData = (const uint32_t*)paletteBuffer; - for (size_t i = 0; i < colors; ++i) { - _materialColors.emplace_back(core::Color::fromRGBA(*paletteData)); - ++paletteData; - } - for (size_t i = colors; i < _materialColors.capacity(); ++i) { - _materialColors.emplace_back(core::Color::Black); - ++paletteData; - } - Log::debug("Set up %i material colors", (int)_materialColors.size()); - - if (_materialColors.size() != colors) { - Log::warn("Color amount mismatch %i vs %i", (int)_materialColors.size(), (int)colors); - return false; - } MaterialColorIndices generic; - generic.reserve(colors); - for (size_t i = 0; i < colors; ++i) { + generic.reserve(_palette.colorCount); + for (int i = 0; i < _palette.colorCount; ++i) { generic.push_back(i); } _colorMapping.put(voxel::VoxelType::Generic, generic); - if (luaString.empty()) { + if (palette.lua.empty()) { Log::debug("No materials defined in palette lua script"); return true; } @@ -97,13 +76,12 @@ public: for (int i = (int)voxel::VoxelType::Air + 1; i < (int)voxel::VoxelType::Max; ++i, ++aindex) { funcs[aindex] = luaL_Reg{ voxel::VoxelTypeStr[i], [] (lua_State* l) -> int { MaterialColor* mc = luamaterial_getmaterialcolor(l); - const int index = luaL_checknumber(l, -1); + const int index = (int)luaL_checknumber(l, -1); // this is hacky - but we resolve the lua function name here to reverse lookup // the voxel type. This could maybe be done nicer with upvalues... lua_Debug entry; lua_getstack(l, 0, &entry); - const int status = lua_getinfo(l, "Sln", &entry); - core_assert_always(status == 1); + lua_getinfo(l, "Sln", &entry); for (int j = (int)voxel::VoxelType::Air + 1; j < (int)voxel::VoxelType::Max; ++j) { if (SDL_strcmp(voxel::VoxelTypeStr[j], entry.name) == 0) { auto i = mc->_colorMapping.find((VoxelType)j); @@ -124,12 +102,11 @@ public: luaL_Reg getmaterial = { "material", [] (lua_State* l) -> int { MaterialColor* mc = luamaterial_getmaterialcolor(l); lua_newtable(l); - const MaterialColorArray& colorArray = mc->getColors(); lua_newtable(l); const int top = lua_gettop(l); - for (size_t i = 0; i < colorArray.size(); ++i) { + for (int i = 0; i < PaletteMaxColors; ++i) { lua_pushinteger(l, i); - clua_push(l, colorArray[i]); + clua_push(l, core::Color::fromRGBA(mc->palette().colors[i])); lua_settable(l, top); } return 1; @@ -142,7 +119,7 @@ public: lua_pushlightuserdata(lua, this); lua_setglobal(lua, luamaterial_materialcolorid()); clua_registerfuncsglobal(lua, &funcs[0], "__meta_material", "MAT"); - if (!lua.load(luaString)) { + if (!lua.load(palette.lua)) { Log::error("Could not load lua script. Failed with error: %s", lua.error().c_str()); return false; @@ -165,7 +142,6 @@ public: } void shutdown() { - _materialColors.clear(); _colorMapping.clear(); _initialized = false; _dirty = false; @@ -179,56 +155,6 @@ public: return _dirty; } - const MaterialColorArray& getColors() const { - if (!_initialized) { - static const uint32_t defaultPalette[] = { - 0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff, - 0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff, - 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc, - 0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc, - 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99, - 0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699, - 0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66, - 0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666, - 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066, - 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933, - 0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033, - 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00, - 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300, - 0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044, - 0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000, - 0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111 - }; - initMaterialColors((const uint8_t*)defaultPalette, sizeof(defaultPalette), ""); - } - core_assert_msg(_initialized, "Material colors are not yet initialized"); - core_assert_msg(!_materialColors.empty(), "Failed to initialize the material colors"); - return _materialColors; - } - - void setGlowColor(int idx) { - _glowColors[idx] = _materialColors[idx]; - _dirty = true; - } - - bool isGlowColor(int idx) { - return _glowColors[idx] != core::Color::Clear; - } - - void removeGlowColor(int idx) { - _glowColors[idx] = core::Color::Clear; - _dirty = true; - } - - const MaterialColorArray& getGlowColors() const { - if (!_initialized) { - getColors(); - } - core_assert_msg(_initialized, "Material colors are not yet initialized"); - core_assert_msg(!_glowColors.empty(), "Failed to initialize the glow colors"); - return _glowColors; - } - const MaterialColorIndices& getColorIndices(VoxelType type) const { auto i = _colorMapping.find(type); if (i == _colorMapping.end()) { @@ -290,41 +216,8 @@ static MaterialColor& getInstance() { return color; } -bool initMaterialColors(const uint8_t* paletteBuffer, size_t paletteBufferSize, const core::String& luaBuffer) { - return getInstance().init(paletteBuffer, paletteBufferSize, luaBuffer); -} - -bool initMaterialColors(const Palette& palette) { - return initMaterialColors((const uint8_t*)palette._colors.begin(), palette.size() + 4, palette.lua); -} - -bool overrideMaterialColors(const uint8_t* paletteBuffer, size_t paletteBufferSize, const core::String& luaBuffer) { - shutdownMaterialColors(); - if (!initMaterialColors(paletteBuffer, paletteBufferSize, luaBuffer)) { - return initDefaultMaterialColors(); - } - return true; -} - -bool materialColorIsGlow(int idx) { - if (idx < 0 || idx >= 256) { - return false; - } - return getInstance().isGlowColor(idx); -} - -void materialColorSetGlow(int idx) { - if (idx < 0 || idx >= 256) { - return; - } - getInstance().setGlowColor(idx); -} - -void materialColorRemoveGlow(int idx) { - if (idx < 0 || idx >= 256) { - return; - } - getInstance().removeGlowColor(idx); +bool initPalette(const Palette& palette) { + return getInstance().init(palette); } bool materialColorChanged() { @@ -339,141 +232,26 @@ void shutdownMaterialColors() { return getInstance().shutdown(); } -bool initMinecraftMaterialColors() { - static const uint32_t palette[] = { - 0xff000000, 0xff7d7d7d, 0xff4cb376, 0xff436086, 0xff7a7a7a, 0xff4e7f9c, 0xff256647, 0xff535353, 0xffdcaf70, - 0xffdcaf70, 0xff135bcf, 0xff125ad4, 0xffa0d3db, 0xff7a7c7e, 0xff7c8b8f, 0xff7e8287, 0xff737373, 0xff315166, - 0xff31b245, 0xff54c3c2, 0xfff4f0da, 0xff867066, 0xff894326, 0xff838383, 0xff9fd3dc, 0xff324364, 0xff3634b4, - 0xff23c7f6, 0xff7c7c7c, 0xff77bf8e, 0xffdcdcdc, 0xff296595, 0xff194f7b, 0xff538ba5, 0xff5e96bd, 0xffdddddd, - 0xffe5e5e5, 0xff00ffff, 0xff0d00da, 0xff415778, 0xff0d0fe1, 0xff4eecf9, 0xffdbdbdb, 0xffa1a1a1, 0xffa6a6a6, - 0xff0630bc, 0xff0026af, 0xff39586b, 0xff658765, 0xff1d1214, 0xff00ffff, 0xff005fde, 0xff31271a, 0xff4e87a6, - 0xff2a74a4, 0xff0000ff, 0xff8f8c81, 0xffd5db61, 0xff2e5088, 0xff17593c, 0xff335682, 0xff676767, 0xff00b9ff, - 0xff5b9ab8, 0xff387394, 0xff345f79, 0xff5190b6, 0xff6a6a6a, 0xff5b9ab8, 0xff40596a, 0xff7a7a7a, 0xffc2c2c2, - 0xff65a0c9, 0xff6b6b84, 0xff2d2ddd, 0xff000066, 0xff0061ff, 0xff848484, 0xfff1f1df, 0xffffad7d, 0xfffbfbef, - 0xff1d830f, 0xffb0a49e, 0xff65c094, 0xff3b5985, 0xff42748d, 0xff1b8ce3, 0xff34366f, 0xff334054, 0xff45768f, - 0xffbf0a57, 0xff2198f1, 0xffffffec, 0xffb2b2b2, 0xffb2b2b2, 0xffffffff, 0xff2d5d7e, 0xff7c7c7c, 0xff7a7a7a, - 0xff7cafcf, 0xff78aaca, 0xff6a6c6d, 0xfff4efd3, 0xff28bdc4, 0xff69dd92, 0xff53ae73, 0xff0c5120, 0xff5287a5, - 0xff2a4094, 0xff7a7a7a, 0xff75718a, 0xff767676, 0xff1a162c, 0xff1a162c, 0xff1a162c, 0xff2d28a6, 0xffb1c454, - 0xff51677c, 0xff494949, 0xff343434, 0xffd18934, 0xffa5dfdd, 0xff0f090c, 0xff316397, 0xff42a0e3, 0xff4d84a1, - 0xff49859e, 0xff1f71dd, 0xffa8e2e7, 0xff74806d, 0xff3c3a2a, 0xff7c7c7c, 0xff5a5a5a, 0xff75d951, 0xff345e81, - 0xff84c0ce, 0xff455f88, 0xff868b8e, 0xffd7dd74, 0xff595959, 0xff334176, 0xff008c0a, 0xff17a404, 0xff5992b3, - 0xffb0b0b0, 0xff434347, 0xff1d6b9e, 0xff70fdfe, 0xffe5e5e5, 0xff4c4a4b, 0xffbdc6bf, 0xffddedfb, 0xff091bab, - 0xff4f547d, 0xff717171, 0xffdfe6ea, 0xffe3e8eb, 0xff41819b, 0xff747474, 0xffa1b2d1, 0xfff6f6f6, 0xff878787, - 0xff395ab0, 0xff325cac, 0xff152c47, 0xff65c878, 0xff3534df, 0xffc7c7c7, 0xffa5af72, 0xffbec7ac, 0xff9fd3dc, - 0xffcacaca, 0xff425c96, 0xff121212, 0xfff4bfa2, 0xff1474cf, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff1d56ac, - 0xff1d57ae, 0xff1d57ae, 0xff1d57ae, 0xff243c50, 0xff8dcddd, 0xff4d7aaf, 0xff0e2034, 0xff366bcf, 0xff355d7e, - 0xff7bb8c7, 0xff5f86bb, 0xff1e2e3f, 0xff3a6bc5, 0xff30536e, 0xffe0f3f7, 0xff5077a9, 0xff2955aa, 0xff21374e, - 0xffcdc5dc, 0xff603b60, 0xff856785, 0xffa679a6, 0xffaa7eaa, 0xffa879a8, 0xffa879a8, 0xffa879a8, 0xffaae6e1, - 0xffaae6e1, 0xff457d98, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, - 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, - 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, - 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, - 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, - 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff242132 - }; - return getInstance().init((const uint8_t* )palette, sizeof(palette), ""); -} - -bool initMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& luaFile) { - if (!paletteFile->exists()) { - Log::error("%s doesn't exist", paletteFile->name().c_str()); - return false; - } - core::String luaString = ""; - if (luaFile) { - if (!luaFile->exists()) { - Log::warn("Failed to load %s", luaFile->name().c_str()); - } else { - luaString = luaFile->load(); - if (luaString.empty()) { - Log::debug("No lua material definitions in %s", luaFile->name().c_str()); - } - } - } else { - Log::debug("No lua material definition file given"); - } - const image::ImagePtr& img = image::loadImage(paletteFile, false); - if (!img->isLoaded()) { - Log::error("Failed to load image %s", paletteFile->name().c_str()); - return false; - } - return initMaterialColors(img->data(), img->width() * img->height() * img->depth(), luaString); -} - -bool overrideMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& luaFile) { - if (!paletteFile->exists()) { - Log::error("%s doesn't exist", paletteFile->name().c_str()); - return false; - } - if (!luaFile->exists()) { - Log::error("Failed to load %s", luaFile->name().c_str()); - return false; - } - const image::ImagePtr& img = image::loadImage(paletteFile, false); - if (!img->isLoaded()) { - Log::error("Failed to load image %s", paletteFile->name().c_str()); - return false; - } - return overrideMaterialColors(img->data(), img->width() * img->height() * img->depth(), luaFile->load()); -} - -bool overrideMaterialColors(const voxel::Palette &palette) { - return overrideMaterialColors((const uint8_t*)palette._colors.begin(), palette.size() + 4, palette.lua); -} - -const char* getDefaultPaletteName() { - return "nippon"; -} - -core::String extractPaletteName(const core::String& file) { - if (!core::string::startsWith(file, "palette-")) { - return ""; - } - const core::String& nameWithExtension = file.substr(8); - const size_t extPos = nameWithExtension.rfind('.'); - if (extPos != core::String::npos) { - return nameWithExtension.substr(0, extPos); - } - return nameWithExtension; -} - -bool initDefaultMaterialColors() { - const io::FilesystemPtr& filesystem = io::filesystem(); - const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", getDefaultPaletteName())); - const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", getDefaultPaletteName())); - return initMaterialColors(paletteFile, luaFile); -} - -const MaterialColorArray& getMaterialColors() { - return getInstance().getColors(); -} - -const MaterialColorArray& getGlowColors() { - return getInstance().getGlowColors(); -} - -const glm::vec4& getMaterialColor(const Voxel& voxel) { - return getMaterialColors()[voxel.getColor()]; -} - -bool saveMaterialColorPng(const core::String& filename) { - image::Image img(filename); - core::Array palette; - int i = 0; - for (const glm::vec4& c : getMaterialColors()) { - palette[i++] = core::Color::getRGBA(c); - } - Log::info("Export palette to %s", filename.c_str()); - img.loadRGBA((const uint8_t*)palette.begin(), (int)palette.size() * 4, (int)palette.size(), 1); - if (!img.writePng()) { - Log::warn("Failed to write the palette file"); - return false; +bool overridePalette(const voxel::Palette &palette) { + shutdownMaterialColors(); + if (!initPalette(palette)) { + return initDefaultPalette(); } return true; } -bool materialColorInitialized() { - return getInstance().initialized(); +bool initDefaultPalette() { + Palette palette; + if (!palette.load(Palette::getDefaultPaletteName())) { + if (!palette.magicaVoxel()) { + return false; + } + } + return initPalette(palette); +} + +Palette& getPalette() { + return getInstance().palette(); } const MaterialColorIndices& getMaterialIndices(VoxelType type) { @@ -493,49 +271,4 @@ Voxel createRandomColorVoxel(VoxelType type, math::Random& random) { return getInstance().createRandomColorVoxel(type, random); } -bool createPalette(const image::ImagePtr& image, uint32_t *colorsBuffer, int colors) { - if (!image || !image->isLoaded()) { - return false; - } - const int imageWidth = image->width(); - const int imageHeight = image->height(); - Log::debug("Create palette for image: %s", image->name().c_str()); - core::Map colorset; - uint16_t paletteIndex = 0; - uint32_t empty = core::Color::getRGBA(core::Color::White); - colorset.put(empty, true); - colorsBuffer[paletteIndex++] = empty; - for (int x = 0; x < imageWidth; ++x) { - for (int y = 0; y < imageHeight; ++y) { - const uint8_t* data = image->at(x, y); - const uint32_t rgba = core::Color::getRGBA(core::Color::alpha(core::Color::fromRGBA(*(uint32_t*)data), 1.0f)); - if (colorset.find(rgba) != colorset.end()) { - continue; - } - colorset.put(rgba, true); - if (paletteIndex >= colors) { - Log::warn("Palette indices exceeded - only %i colors were loaded", colors); - return true; - } - colorsBuffer[paletteIndex++] = rgba; - } - } - for (int i = paletteIndex; i < colors; ++i) { - colorsBuffer[i] = 0xFFFFFFFF; - } - return true; -} - -bool createPaletteFile(const image::ImagePtr& image, const char *paletteFile) { - if (!image || !image->isLoaded() || paletteFile == nullptr) { - return false; - } - uint32_t buf[256]; - if (!createPalette(image, buf, lengthof(buf))) { - return false; - } - const image::ImagePtr& paletteImg = image::createEmptyImage("**palette**"); - return paletteImg->writePng(paletteFile, (const uint8_t*)buf, 256, 1, 4); -} - } diff --git a/src/modules/voxel/MaterialColor.h b/src/modules/voxel/MaterialColor.h index 27dc94c1e..6c64c3517 100644 --- a/src/modules/voxel/MaterialColor.h +++ b/src/modules/voxel/MaterialColor.h @@ -6,12 +6,6 @@ #include "voxel/Voxel.h" #include "voxel/Palette.h" -#include "io/File.h" -#include "image/Image.h" - -#include -#include "core/String.h" -#include "core/collection/DynamicArray.h" namespace math { class Random; @@ -19,40 +13,21 @@ class Random; namespace voxel { -// this size must match the color uniform size in the shader -typedef core::DynamicArray MaterialColorArray; -typedef core::DynamicArray MaterialColorIndices; - -extern const char* getDefaultPaletteName(); -extern core::String extractPaletteName(const core::String& file); - -extern bool initDefaultMaterialColors(); -extern bool initMinecraftMaterialColors(); -extern bool initMaterialColors(const voxel::Palette &palette); -extern bool initMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& luaFile); -extern bool initMaterialColors(const uint8_t* paletteBuffer, size_t paletteBufferSize, const core::String& luaBuffer); -extern bool overrideMaterialColors(const io::FilePtr& paletteFile, const io::FilePtr& luaFile); -extern bool overrideMaterialColors(const voxel::Palette &palette); -extern bool overrideMaterialColors(const uint8_t* paletteBuffer, size_t paletteBufferSize, const core::String& luaBuffer); +extern bool initDefaultPalette(); +extern bool initPalette(const voxel::Palette &palette); +extern bool overridePalette(const voxel::Palette &palette); extern void shutdownMaterialColors(); -extern bool saveMaterialColorPng(const core::String& filename); -extern bool materialColorInitialized(); extern void materialColorMarkClean(); extern bool materialColorChanged(); -extern bool materialColorIsGlow(int idx); -extern void materialColorSetGlow(int idx); -extern void materialColorRemoveGlow(int idx); -extern const MaterialColorArray& getMaterialColors(); -extern const MaterialColorArray& getGlowColors(); -extern const glm::vec4& getMaterialColor(const Voxel& voxel); +extern Palette& getPalette(); -extern bool createPalette(const image::ImagePtr& image, uint32_t *colorsBuffer, int colors); -extern bool createPaletteFile(const image::ImagePtr& image, const char *paletteFile); +// this size must match the color uniform size in the shader +typedef core::DynamicArray MaterialColorIndices; /** * @brief Get all known material color indices for the given VoxelType * @param type The VoxelType to get the indices for - * @return Indices to the MaterialColorArray for the given VoxelType + * @return Indices to the palette color array for the given VoxelType */ extern const MaterialColorIndices& getMaterialIndices(VoxelType type); extern Voxel createRandomColorVoxel(VoxelType type); diff --git a/src/modules/voxel/Palette.cpp b/src/modules/voxel/Palette.cpp new file mode 100644 index 000000000..b5a4213a0 --- /dev/null +++ b/src/modules/voxel/Palette.cpp @@ -0,0 +1,250 @@ +/** + * @file + */ + +#include "Palette.h" +#include "app/App.h" +#include "core/Color.h" +#include "core/Log.h" +#include "core/String.h" +#include "core/StringUtil.h" +#include "core/collection/Array.h" +#include "image/Image.h" +#include "io/File.h" +#include "io/Filesystem.h" +#include "math/Math.h" + +namespace voxel { + +bool Palette::save(const char *name) { + image::Image img(name); + Log::info("Export palette to %s", name); + img.loadRGBA((const uint8_t *)colors, sizeof(colors), lengthof(colors), 1); + if (!img.writePng()) { + Log::warn("Failed to write the palette file"); + return false; + } + return true; +} + +bool Palette::load(const uint8_t *rgbaBuf, size_t bufsize) { + if (bufsize % 4 != 0) { + Log::warn("Buf size doesn't match expectation: %i", (int)bufsize); + } + int colors = (int)bufsize / 4; + if (colors <= 0) { + Log::error("Buffer is not big enough: %i bytes", (int)bufsize); + return false; + } + if (colors > PaletteMaxColors) { + Log::warn("Too many colors given for palette."); + } + colors = core_min(colors, PaletteMaxColors); + image::ImagePtr img = image::createEmptyImage("**palette**"); + if (!img->loadRGBA(rgbaBuf, colors * 4, colors, 1)) { + return false; + } + return load(img); +} + +bool Palette::load(const image::ImagePtr &img) { + if (img->depth() != 4) { + Log::warn("Palette image has invalid depth (exepected: 4bpp, got %i)", img->depth()); + return false; + } + core_memset(glowColors, 0, sizeof(glowColors)); + int n = img->width(); + if (n > PaletteMaxColors) { + n = PaletteMaxColors; + Log::warn("Palette image has invalid dimensions - we need max 256x1(depth: 4)"); + } + colorCount = n; + for (int i = 0; i < colorCount; ++i) { + colors[i] = *(uint32_t *)img->at(i, 0); + } + for (int i = colorCount; i < PaletteMaxColors; ++i) { + colors[i] = core::Color::getRGBA(0, 0, 0, 255); + } + Log::debug("Set up %i material colors", colorCount); + return true; +} + +bool Palette::load(const char *paletteName) { + const io::FilesystemPtr &filesystem = io::filesystem(); + io::FilePtr paletteFile = filesystem->open(paletteName); + if (!paletteFile->validHandle()) { + paletteFile = filesystem->open(core::string::format("palette-%s.png", paletteName)); + } + if (!paletteFile->validHandle()) { + Log::error("Failed to load palette file %s", paletteName); + return false; + } + const image::ImagePtr &img = image::loadImage(paletteFile, false); + if (!img->isLoaded()) { + Log::error("Failed to load image %s", paletteFile->name().c_str()); + return false; + } + const io::FilePtr &luaFile = filesystem->open(core::string::format("palette-%s.lua", paletteName)); + if (luaFile->validHandle()) { + lua = luaFile->load(); + } else { + lua = ""; + } + return load(img); +} + +bool Palette::minecraft() { + static const uint32_t palette[PaletteMaxColors] = { + 0xff000000, 0xff7d7d7d, 0xff4cb376, 0xff436086, 0xff7a7a7a, 0xff4e7f9c, 0xff256647, 0xff535353, 0xffdcaf70, + 0xffdcaf70, 0xff135bcf, 0xff125ad4, 0xffa0d3db, 0xff7a7c7e, 0xff7c8b8f, 0xff7e8287, 0xff737373, 0xff315166, + 0xff31b245, 0xff54c3c2, 0xfff4f0da, 0xff867066, 0xff894326, 0xff838383, 0xff9fd3dc, 0xff324364, 0xff3634b4, + 0xff23c7f6, 0xff7c7c7c, 0xff77bf8e, 0xffdcdcdc, 0xff296595, 0xff194f7b, 0xff538ba5, 0xff5e96bd, 0xffdddddd, + 0xffe5e5e5, 0xff00ffff, 0xff0d00da, 0xff415778, 0xff0d0fe1, 0xff4eecf9, 0xffdbdbdb, 0xffa1a1a1, 0xffa6a6a6, + 0xff0630bc, 0xff0026af, 0xff39586b, 0xff658765, 0xff1d1214, 0xff00ffff, 0xff005fde, 0xff31271a, 0xff4e87a6, + 0xff2a74a4, 0xff0000ff, 0xff8f8c81, 0xffd5db61, 0xff2e5088, 0xff17593c, 0xff335682, 0xff676767, 0xff00b9ff, + 0xff5b9ab8, 0xff387394, 0xff345f79, 0xff5190b6, 0xff6a6a6a, 0xff5b9ab8, 0xff40596a, 0xff7a7a7a, 0xffc2c2c2, + 0xff65a0c9, 0xff6b6b84, 0xff2d2ddd, 0xff000066, 0xff0061ff, 0xff848484, 0xfff1f1df, 0xffffad7d, 0xfffbfbef, + 0xff1d830f, 0xffb0a49e, 0xff65c094, 0xff3b5985, 0xff42748d, 0xff1b8ce3, 0xff34366f, 0xff334054, 0xff45768f, + 0xffbf0a57, 0xff2198f1, 0xffffffec, 0xffb2b2b2, 0xffb2b2b2, 0xffffffff, 0xff2d5d7e, 0xff7c7c7c, 0xff7a7a7a, + 0xff7cafcf, 0xff78aaca, 0xff6a6c6d, 0xfff4efd3, 0xff28bdc4, 0xff69dd92, 0xff53ae73, 0xff0c5120, 0xff5287a5, + 0xff2a4094, 0xff7a7a7a, 0xff75718a, 0xff767676, 0xff1a162c, 0xff1a162c, 0xff1a162c, 0xff2d28a6, 0xffb1c454, + 0xff51677c, 0xff494949, 0xff343434, 0xffd18934, 0xffa5dfdd, 0xff0f090c, 0xff316397, 0xff42a0e3, 0xff4d84a1, + 0xff49859e, 0xff1f71dd, 0xffa8e2e7, 0xff74806d, 0xff3c3a2a, 0xff7c7c7c, 0xff5a5a5a, 0xff75d951, 0xff345e81, + 0xff84c0ce, 0xff455f88, 0xff868b8e, 0xffd7dd74, 0xff595959, 0xff334176, 0xff008c0a, 0xff17a404, 0xff5992b3, + 0xffb0b0b0, 0xff434347, 0xff1d6b9e, 0xff70fdfe, 0xffe5e5e5, 0xff4c4a4b, 0xffbdc6bf, 0xffddedfb, 0xff091bab, + 0xff4f547d, 0xff717171, 0xffdfe6ea, 0xffe3e8eb, 0xff41819b, 0xff747474, 0xffa1b2d1, 0xfff6f6f6, 0xff878787, + 0xff395ab0, 0xff325cac, 0xff152c47, 0xff65c878, 0xff3534df, 0xffc7c7c7, 0xffa5af72, 0xffbec7ac, 0xff9fd3dc, + 0xffcacaca, 0xff425c96, 0xff121212, 0xfff4bfa2, 0xff1474cf, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff1d56ac, + 0xff1d57ae, 0xff1d57ae, 0xff1d57ae, 0xff243c50, 0xff8dcddd, 0xff4d7aaf, 0xff0e2034, 0xff366bcf, 0xff355d7e, + 0xff7bb8c7, 0xff5f86bb, 0xff1e2e3f, 0xff3a6bc5, 0xff30536e, 0xffe0f3f7, 0xff5077a9, 0xff2955aa, 0xff21374e, + 0xffcdc5dc, 0xff603b60, 0xff856785, 0xffa679a6, 0xffaa7eaa, 0xffa879a8, 0xffa879a8, 0xffa879a8, 0xffaae6e1, + 0xffaae6e1, 0xff457d98, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, + 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, + 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, + 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, + 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, + 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff242132}; + return load((const uint8_t *)palette, sizeof(palette)); +} + +bool Palette::magicaVoxel() { + static const uint32_t palette[PaletteMaxColors] = { + 0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, + 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff, 0xff6699ff, 0xff3399ff, + 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, + 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff, 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, + 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, + 0xff99cccc, 0xff66cccc, 0xff33cccc, 0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, + 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, + 0xff9933cc, 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, + 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99, 0xffcccc99, + 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, + 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699, 0xff006699, 0xffff3399, 0xffcc3399, + 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, + 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66, 0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, + 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, + 0xff009966, 0xffff6666, 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, + 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066, + 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, + 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933, 0xff669933, 0xff339933, + 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, + 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033, 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, + 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, + 0xff99cc00, 0xff66cc00, 0xff33cc00, 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, + 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, + 0xff993300, 0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, + 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044, 0xff000022, + 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, + 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000, 0xff880000, 0xff770000, 0xff550000, + 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, + 0xff555555, 0xff444444, 0xff222222, 0xff111111}; + return load((const uint8_t *)palette, sizeof(palette)); +} + +core::String Palette::extractPaletteName(const core::String &file) { + if (!core::string::startsWith(file, "palette-")) { + return ""; + } + const core::String &nameWithExtension = file.substr(8); + const size_t extPos = nameWithExtension.rfind('.'); + if (extPos != core::String::npos) { + return nameWithExtension.substr(0, extPos); + } + return nameWithExtension; +} + +bool Palette::createPalette(const image::ImagePtr &image, voxel::Palette &palette) { + if (!image || !image->isLoaded()) { + return false; + } + const int colors = (int)PaletteMaxColors; + const int imageWidth = image->width(); + const int imageHeight = image->height(); + Log::debug("Create palette for image: %s", image->name().c_str()); + core::Map colorset; + uint16_t paletteIndex = 0; + uint32_t empty = core::Color::getRGBA(core::Color::White); + colorset.put(empty, true); + palette.colors[paletteIndex++] = empty; + for (int x = 0; x < imageWidth; ++x) { + for (int y = 0; y < imageHeight; ++y) { + const uint8_t *data = image->at(x, y); + const uint32_t rgba = + core::Color::getRGBA(core::Color::alpha(core::Color::fromRGBA(*(uint32_t *)data), 1.0f)); + if (colorset.find(rgba) != colorset.end()) { + continue; + } + colorset.put(rgba, true); + if (paletteIndex >= colors) { + Log::warn("Palette indices exceeded - only %i colors were loaded", colors); + return true; + } + palette.colors[paletteIndex++] = rgba; + } + } + for (int i = paletteIndex; i < colors; ++i) { + palette.colors[i] = empty; + } + return true; +} + +bool Palette::hasGlow(uint8_t idx) const { + return glowColors[idx] != 0; +} + +void Palette::removeGlow(uint8_t idx) { + glowColors[idx] = 0; +} + +void Palette::setGlow(uint8_t idx, float factor) { + // TODO: handle factor + glowColors[idx] = colors[idx]; +} + +void Palette::toVec4f(core::DynamicArray &vec4f) const { + vec4f.reserve(colorCount); + for (int i = 0; i < colorCount; ++i) { + vec4f.push_back(core::Color::fromRGBA(colors[i])); + } +} + +void Palette::glowToVec4f(core::DynamicArray &vec4f) const { + vec4f.reserve(colorCount); + for (int i = 0; i < colorCount; ++i) { + vec4f.push_back(core::Color::fromRGBA(glowColors[i])); + } +} + +bool Palette::convertImageToPalettePng(const image::ImagePtr &image, const char *paletteFile) { + if (!image || !image->isLoaded() || paletteFile == nullptr) { + return false; + } + Palette palette; + if (!createPalette(image, palette)) { + return false; + } + const image::ImagePtr &paletteImg = image::createEmptyImage("**palette**"); + return paletteImg->writePng(paletteFile, (const uint8_t *)palette.colors, palette.colorCount, 1, 4); +} + +} // namespace voxel diff --git a/src/modules/voxel/Palette.h b/src/modules/voxel/Palette.h index 5e5f414f1..a56929094 100644 --- a/src/modules/voxel/Palette.h +++ b/src/modules/voxel/Palette.h @@ -6,19 +6,54 @@ #include "core/String.h" #include "core/collection/Array.h" +#include "core/collection/DynamicArray.h" +#include "image/Image.h" #include +#include namespace voxel { -struct Palette { - core::Array _colors; - core::Array _glowColors; - core::String lua; - size_t colorCount = 0; +static constexpr int PaletteMaxColors = 256; +// RGBA color values in the range [0-255] +using PaletteColorArray = uint32_t[PaletteMaxColors]; + +class Palette { +private: + bool load(const image::ImagePtr &img); + +public: + PaletteColorArray colors {}; + PaletteColorArray glowColors {}; + int colorCount = 0; + core::String lua; inline size_t size() const { return colorCount; } + bool load(const char *name); + bool save(const char *name); + bool load(const uint8_t *rgbaBuf, size_t bufsize); + + bool minecraft(); + bool magicaVoxel(); + + bool hasGlow(uint8_t idx) const; + void removeGlow(uint8_t idx); + void setGlow(uint8_t idx, float factor = 1.0f); + + /** + * @brief Convert the RGBA color values in the range [0-255] to float color values in the range [0.0-1.0] + */ + void toVec4f(core::DynamicArray &rgba) const; + void glowToVec4f(core::DynamicArray &vec4f) const; + + static const char* getDefaultPaletteName() { + return "nippon"; + } + + static core::String extractPaletteName(const core::String& file); + static bool createPalette(const image::ImagePtr& image, voxel::Palette &palette); + static bool convertImageToPalettePng(const image::ImagePtr& image, const char *paletteFile); }; -} \ No newline at end of file +} // namespace voxel diff --git a/src/modules/voxel/benchmarks/CubicSurfaceExtractorBenchmark.cpp b/src/modules/voxel/benchmarks/CubicSurfaceExtractorBenchmark.cpp index a443ddcaa..22df3c4ee 100644 --- a/src/modules/voxel/benchmarks/CubicSurfaceExtractorBenchmark.cpp +++ b/src/modules/voxel/benchmarks/CubicSurfaceExtractorBenchmark.cpp @@ -41,7 +41,7 @@ public: }; bool onInitApp() override { - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { return false; } return true; diff --git a/src/modules/voxel/tests/AbstractVoxelTest.h b/src/modules/voxel/tests/AbstractVoxelTest.h index 27ab9dc88..c596c995b 100644 --- a/src/modules/voxel/tests/AbstractVoxelTest.h +++ b/src/modules/voxel/tests/AbstractVoxelTest.h @@ -5,6 +5,7 @@ #pragma once #include "app/tests/AbstractTest.h" +#include "voxel/MaterialColor.h" #include "voxel/tests/TestHelper.h" namespace voxel { @@ -60,11 +61,16 @@ public: void SetUp() override { _volData.flushAll(); app::AbstractTest::SetUp(); - ASSERT_TRUE(voxel::initDefaultMaterialColors()); + ASSERT_TRUE(voxel::initDefaultPalette()); _random.setSeed(_seed); _ctx = PagedVolumeWrapper(&_volData, _volData.chunk(_region.getCenter()), _region); VolumePrintThreshold = 10; } + + void TearDown() override { + voxel::shutdownMaterialColors(); + app::AbstractTest::TearDown(); + } }; } diff --git a/src/modules/voxel/tests/TestHelper.h b/src/modules/voxel/tests/TestHelper.h index 636f1a654..31f7e03e0 100644 --- a/src/modules/voxel/tests/TestHelper.h +++ b/src/modules/voxel/tests/TestHelper.h @@ -49,7 +49,9 @@ inline bool volumeComparator(const voxel::RawVolume& volume1, const voxel::RawVo const int32_t upperX = region.getUpperX(); const int32_t upperY = region.getUpperY(); const int32_t upperZ = region.getUpperZ(); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + core::DynamicArray materialColors; + const voxel::Palette &palette = voxel::getPalette(); + palette.toVec4f(materialColors); for (int32_t z = lowerZ; z <= upperZ; ++z) { for (int32_t y = lowerY; y <= upperY; ++y) { diff --git a/src/modules/voxelfont/VoxelFont.cpp b/src/modules/voxelfont/VoxelFont.cpp index cf78c1f54..ac79c54d2 100644 --- a/src/modules/voxelfont/VoxelFont.cpp +++ b/src/modules/voxelfont/VoxelFont.cpp @@ -27,7 +27,6 @@ #include "voxel/RawVolume.h" #include "voxel/CubicSurfaceExtractor.h" #include "voxel/IsQuadNeeded.h" -#include "voxel/MaterialColor.h" #include namespace voxel { @@ -127,7 +126,7 @@ void VoxelFont::shutdown() { } bool VoxelFont::renderGlyphs(const char* string) { - static const voxel::Voxel& voxel = voxel::createColorVoxel(VoxelType::Generic, 0); + static const voxel::Voxel& voxel = voxel::createVoxel(VoxelType::Generic, 1); const char **s = &string; int spaceWidth = 0; int chars = 0; diff --git a/src/modules/voxelformat/BinVoxFormat.cpp b/src/modules/voxelformat/BinVoxFormat.cpp index 9d9bff6fc..05cb733c0 100644 --- a/src/modules/voxelformat/BinVoxFormat.cpp +++ b/src/modules/voxelformat/BinVoxFormat.cpp @@ -26,7 +26,7 @@ namespace voxel { } bool BinVoxFormat::readData(State& state, const core::String& filename, io::SeekableReadStream& stream, SceneGraph& sceneGraph) { - const voxel::Region region(0, 0, 0, state._d - 1, state._w - 1, state._h - 1); + const voxel::Region region(0, 0, 0, (int)state._d - 1, (int)state._w - 1, (int)state._h - 1); if (!region.isValid()) { Log::error("Invalid region found in file"); return false; diff --git a/src/modules/voxelformat/CubFormat.cpp b/src/modules/voxelformat/CubFormat.cpp index 7711f3905..0f660dbdc 100644 --- a/src/modules/voxelformat/CubFormat.cpp +++ b/src/modules/voxelformat/CubFormat.cpp @@ -8,6 +8,7 @@ #include "core/Log.h" #include "core/Color.h" #include "core/ScopedPtr.h" +#include "voxel/MaterialColor.h" namespace voxel { @@ -34,7 +35,7 @@ bool CubFormat::loadGroups(const core::String &filename, io::SeekableReadStream& return false; } - const voxel::Region region(0, 0, 0, width - 1, height - 1, depth - 1); + const voxel::Region region(0, 0, 0, (int)width - 1, (int)height - 1, (int)depth - 1); if (!region.isValid()) { Log::error("Invalid region: %i:%i:%i", width, height, depth); return false; @@ -62,7 +63,7 @@ bool CubFormat::loadGroups(const core::String &filename, io::SeekableReadStream& const int index = findClosestIndex(color); const voxel::Voxel& voxel = voxel::createVoxel(voxel::VoxelType::Generic, index); // we have to flip depth with height for our own coordinate system - volume->setVoxel(w, h, d, voxel); + volume->setVoxel((int)w, (int)h, (int)d, voxel); } } } @@ -89,6 +90,7 @@ bool CubFormat::saveGroups(const SceneGraph& sceneGraph, const core::String &fil wrapBool(stream.writeUInt32(depth)) wrapBool(stream.writeUInt32(height)) + const voxel::Palette &palette = voxel::getPalette(); for (uint32_t y = 0u; y < height; ++y) { for (uint32_t z = 0u; z < depth; ++z) { for (uint32_t x = 0u; x < width; ++x) { @@ -100,8 +102,8 @@ bool CubFormat::saveGroups(const SceneGraph& sceneGraph, const core::String &fil wrapBool(stream.writeUInt8(0)) continue; } - const glm::vec4& color = getColor(voxel); - const glm::u8vec4& rgba = core::Color::getRGBAVec(color); + + const glm::u8vec4 &rgba = core::Color::toRGBA(palette.colors[voxel.getColor()]); wrapBool(stream.writeUInt8(rgba.r)) wrapBool(stream.writeUInt8(rgba.g)) wrapBool(stream.writeUInt8(rgba.b)) diff --git a/src/modules/voxelformat/Format.cpp b/src/modules/voxelformat/Format.cpp index e259345b0..7ed60c397 100644 --- a/src/modules/voxelformat/Format.cpp +++ b/src/modules/voxelformat/Format.cpp @@ -21,29 +21,20 @@ namespace voxel { -const glm::vec4& Format::getColor(const Voxel& voxel) const { - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); - return materialColors[voxel.getColor()]; -} - uint8_t Format::convertPaletteIndex(uint32_t paletteIndex) const { - if (paletteIndex >= _paletteColors.colorCount) { - if (_paletteColors.colorCount > 0) { - return paletteIndex % _paletteColors.colorCount; + if (paletteIndex >= (uint32_t)_palette.colorCount) { + if (_palette.colorCount > 0) { + return paletteIndex % _palette.colorCount; } return paletteIndex % _paletteMapping.size(); } return _paletteMapping[paletteIndex]; } -glm::vec4 Format::findClosestMatch(const glm::vec4& color) const { - const int index = findClosestIndex(color); - voxel::MaterialColorArray materialColors = voxel::getMaterialColors(); - return materialColors[index]; -} - uint8_t Format::findClosestIndex(const glm::vec4& color) const { - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); //materialColors.erase(materialColors.begin()); return core::Color::getClosestMatch(color, materialColors); } @@ -148,7 +139,7 @@ RawVolume* Format::load(const core::String &filename, io::SeekableReadStream& st size_t Format::loadPalette(const core::String &filename, io::SeekableReadStream& stream, Palette &palette) { SceneGraph sceneGraph; loadGroups(filename, stream, sceneGraph); - palette = _paletteColors; + palette = _palette; return palette.colorCount; } diff --git a/src/modules/voxelformat/Format.h b/src/modules/voxelformat/Format.h index f52f98472..cbf752126 100644 --- a/src/modules/voxelformat/Format.h +++ b/src/modules/voxelformat/Format.h @@ -28,10 +28,8 @@ class Mesh; class Format { protected: core::Array _paletteMapping; - Palette _paletteColors; + Palette _palette; - const glm::vec4& getColor(const Voxel& voxel) const; - glm::vec4 findClosestMatch(const glm::vec4& color) const; uint8_t findClosestIndex(const glm::vec4& color) const; /** * @brief Maps a custum palette index to our own 256 color palette by a closest match diff --git a/src/modules/voxelformat/GoxFormat.cpp b/src/modules/voxelformat/GoxFormat.cpp index 0864384d4..56dde0773 100644 --- a/src/modules/voxelformat/GoxFormat.cpp +++ b/src/modules/voxelformat/GoxFormat.cpp @@ -458,14 +458,13 @@ bool GoxFormat::saveChunk_LIGH(io::SeekableWriteStream& stream) { bool GoxFormat::saveChunk_MATE(io::SeekableWriteStream& stream) { GoxScopedChunkWriter scoped(stream, FourCC('M', 'A', 'T', 'E')); - const MaterialColorArray& materialColors = getMaterialColors(); - const int numColors = (int)materialColors.size(); + const voxel::Palette& palette = voxel::getPalette(); - for (int i = 0; i < numColors; ++i) { - const core::String name = core::string::format("mat%i", i); + for (int i = 0; i < palette.colorCount; ++i) { + const core::String& name = core::string::format("mat%i", i); const float value[3] = {0.0f, 0.0f, 0.0f}; wrapBool(saveChunk_DictEntry(stream, "name", name.c_str(), name.size())) - wrapBool(saveChunk_DictEntry(stream, "color", core::Color::getRGBA(materialColors[i]))) + wrapBool(saveChunk_DictEntry(stream, "color", palette.colors[i])) wrapBool(saveChunk_DictEntry(stream, "metallic", value[0])) wrapBool(saveChunk_DictEntry(stream, "roughness", value[0])) wrapBool(saveChunk_DictEntry(stream, "emission", value)) @@ -554,11 +553,12 @@ bool GoxFormat::saveChunk_BL16(io::SeekableWriteStream& stream, const SceneGraph const size_t size = (size_t)BlockSize * BlockSize * BlockSize * 4; uint32_t *data = (uint32_t*)core_malloc(size); int offset = 0; + const voxel::Palette& palette = voxel::getPalette(); voxelutil::visitVolume(*mirrored, blockRegion, [&](int, int, int, const voxel::Voxel& voxel) { if (voxel::isAir(voxel.getMaterial())) { data[offset++] = 0; } else { - data[offset++] = core::Color::getRGBA(getColor(voxel)); + data[offset++] = palette.colors[voxel.getColor()]; } }, voxelutil::VisitAll(), voxelutil::VisitorOrder::YZX); diff --git a/src/modules/voxelformat/KV6Format.cpp b/src/modules/voxelformat/KV6Format.cpp index d1b8d36e3..0e0f68cc4 100644 --- a/src/modules/voxelformat/KV6Format.cpp +++ b/src/modules/voxelformat/KV6Format.cpp @@ -49,7 +49,7 @@ bool KV6Format::loadGroups(const core::String &filename, io::SeekableReadStream& Log::error("Volume exceeds the max allowed size: %i:%i:%i", xsiz, zsiz, ysiz); return false; } - const voxel::Region region(0, 0, 0, xsiz - 1, zsiz - 1, ysiz - 1); + const voxel::Region region(0, 0, 0, (int)xsiz - 1, (int)zsiz - 1, (int)ysiz - 1); if (!region.isValid()) { Log::error("Invalid region: %i:%i:%i", xsiz, zsiz, ysiz); return false; @@ -69,8 +69,8 @@ bool KV6Format::loadGroups(const core::String &filename, io::SeekableReadStream& uint32_t palMagic; wrap(stream.readUInt32(palMagic)) if (palMagic == FourCC('S','P','a','l')) { - _paletteColors.colorCount = _paletteMapping.size(); - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + _palette.colorCount = (int)_paletteMapping.size(); + for (int i = 0; i < _palette.colorCount; ++i) { uint8_t r, g, b; wrap(stream.readUInt8(b)) wrap(stream.readUInt8(g)) @@ -83,7 +83,7 @@ bool KV6Format::loadGroups(const core::String &filename, io::SeekableReadStream& const glm::vec4& color = core::Color::fromRGBA(nr, ng, nb, 255u); const int index = findClosestIndex(color); _paletteMapping[i] = index; - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); } } } @@ -131,7 +131,7 @@ bool KV6Format::loadGroups(const core::String &filename, io::SeekableReadStream& for (int end = idx + xyoffset[x][y]; idx < end; ++idx) { const voxtype& vox = voxdata[idx]; const voxel::Voxel col = voxel::createVoxel(voxel::VoxelType::Generic, vox.col); - volume->setVoxel(x, (zsiz - 1) - vox.z, y, col); + volume->setVoxel((int)x, (int)((zsiz - 1) - vox.z), (int)y, col); } } } @@ -149,7 +149,7 @@ bool KV6Format::loadGroups(const core::String &filename, io::SeekableReadStream& } if (vox.vis & (1 << 5)) { for (; lastZ < vox.z; ++lastZ) { - volume->setVoxel(x, (zsiz - 1) - lastZ, y, lastCol); + volume->setVoxel((int)x, (int)((zsiz - 1) - lastZ), (int)y, lastCol); } } } diff --git a/src/modules/voxelformat/KVXFormat.cpp b/src/modules/voxelformat/KVXFormat.cpp index de5467315..2e9f9d98c 100644 --- a/src/modules/voxelformat/KVXFormat.cpp +++ b/src/modules/voxelformat/KVXFormat.cpp @@ -53,7 +53,7 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& return false; } - const voxel::Region region(0, 0, 0, xsiz - 1, zsiz - 1, ysiz - 1); + const voxel::Region region(0, 0, 0, (int)xsiz - 1, (int)zsiz - 1, (int)ysiz - 1); if (!region.isValid()) { Log::error("Invalid region: %i:%i:%i", xsiz, zsiz, ysiz); return false; @@ -70,7 +70,7 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& wrap(stream.readUInt32(xoffset)) core_assert(((xsiz + 1) << 2) == sizeof(uint32_t) * (xsiz + 1)); - stream.skip(sizeof(uint32_t) * xsiz); + stream.skip((int64_t)sizeof(uint32_t) * xsiz); for (uint32_t x = 0u; x < xsiz; ++x) { for (uint32_t y = 0u; y <= ysiz; ++y) { wrap(stream.readUInt16(xyoffset[x][y])) @@ -83,15 +83,15 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& } // Read the color palette from the end of the file and convert to our palette const size_t currentPos = stream.pos(); - _paletteColors.colorCount = _paletteMapping.size(); - stream.seek(stream.size() - 3 * _paletteColors.colorCount); + _palette.colorCount = (int)_paletteMapping.size(); + stream.seek(stream.size() - 3 * _palette.colorCount); /** * The last 768 bytes of the KVX file is a standard 256-color VGA palette. * The palette is in (Red:0, Green:1, Blue:2) order and intensities range * from 0-63. */ - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + for (int i = 0; i < _palette.colorCount; ++i) { uint8_t r, g, b; wrap(stream.readUInt8(r)) wrap(stream.readUInt8(g)) @@ -103,9 +103,9 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& const glm::vec4& color = core::Color::fromRGBA(nr, ng, nb, 255); _paletteMapping[i] = findClosestIndex(color); - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); } - stream.seek(currentPos); + stream.seek((int64_t)currentPos); RawVolume *volume = new RawVolume(region); SceneGraphNode node; @@ -164,7 +164,7 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& uint8_t col; wrap(stream.readUInt8(col)) lastCol = voxel::createVoxel(voxel::VoxelType::Generic, convertPaletteIndex(col)); - volume->setVoxel(x, (zsiz - 1) - (header.slabztop + i), y, lastCol); + volume->setVoxel((int)x, (int)((zsiz - 1) - (header.slabztop + i)), (int)y, lastCol); } /** @@ -173,13 +173,13 @@ bool KVXFormat::loadGroups(const core::String &filename, io::SeekableReadStream& */ if (!(header.slabbackfacecullinfo & (1 << 4))) { for (uint32_t i = lastZ + 1; i < header.slabztop; ++i) { - volume->setVoxel(x, (zsiz - 1) - i, y, lastCol); + volume->setVoxel((int)x, (int)((zsiz - 1) - i), (int)y, lastCol); } } if (!(header.slabbackfacecullinfo & (1 << 5))) { lastZ = header.slabztop + header.slabzleng; } - n -= (header.slabzleng + sizeof(header)); + n -= (int32_t)(header.slabzleng + sizeof(header)); } } } diff --git a/src/modules/voxelformat/OBJFormat.cpp b/src/modules/voxelformat/OBJFormat.cpp index 4a513d559..f53a86417 100644 --- a/src/modules/voxelformat/OBJFormat.cpp +++ b/src/modules/voxelformat/OBJFormat.cpp @@ -59,10 +59,9 @@ bool OBJFormat::writeMtlFile(const core::String &mtlName, const core::String &pa bool OBJFormat::saveMeshes(const Meshes &meshes, const core::String &filename, io::SeekableWriteStream &stream, float scale, bool quad, bool withColor, bool withTexCoords) { - const MaterialColorArray &colors = getMaterialColors(); - + const voxel::Palette& palette = voxel::getPalette(); // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)colors.size(); + const float texcoord = 1.0f / (float)palette.colorCount; // it is only 1 pixel high - sample the middle const float v1 = 0.5f; @@ -106,7 +105,7 @@ bool OBJFormat::saveMeshes(const Meshes &meshes, const core::String &filename, i (offset.y + (float)v.position.y) * scale, (offset.z + (float)v.position.z) * scale); if (withColor) { - const glm::vec4 &color = colors[v.colorIndex]; + const glm::vec4& color = core::Color::fromRGBA(palette.colors[v.colorIndex]); stream.writeStringFormat(false, " %.03f %.03f %.03f", color.r, color.g, color.b); } wrapBool(stream.writeStringFormat(false, "\n")) @@ -168,10 +167,7 @@ bool OBJFormat::saveMeshes(const Meshes &meshes, const core::String &filename, i if (!writeMtlFile(mtlname, palettename)) { return false; } - if (!voxel::saveMaterialColorPng(palettename)) { - return false; - } - return true; + return voxel::getPalette().save(palettename.c_str()); } #undef wrapBool @@ -311,7 +307,10 @@ static void voxelizeShape(const tinyobj::shape_t &shape, const core::StringMap palette; palette.reserve(subdivided.size()); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + + const voxel::Palette &pal = voxel::getPalette(); + core::DynamicArray materialColors; + pal.toVec4f(materialColors); for (const Tri &tri : subdivided) { const glm::vec2 &uv = tri.centerUV(); diff --git a/src/modules/voxelformat/PLYFormat.cpp b/src/modules/voxelformat/PLYFormat.cpp index 30580130c..c0d47c12d 100644 --- a/src/modules/voxelformat/PLYFormat.cpp +++ b/src/modules/voxelformat/PLYFormat.cpp @@ -5,6 +5,7 @@ #include "PLYFormat.h" #include "core/Log.h" #include "core/Var.h" +#include "core/Color.h" #include "io/File.h" #include "io/FileStream.h" #include "voxel/MaterialColor.h" @@ -16,9 +17,10 @@ namespace voxel { bool PLYFormat::saveMeshes(const Meshes& meshes, const core::String &filename, io::SeekableWriteStream& stream, float scale, bool quad, bool withColor, bool withTexCoords) { + const char *paletteName = voxel::Palette::getDefaultPaletteName(); stream.writeStringFormat(false, "ply\nformat ascii 1.0\n"); stream.writeStringFormat(false, "comment version " PROJECT_VERSION " github.com/mgerhardy/vengi\n"); - stream.writeStringFormat(false, "comment TextureFile palette-%s.png\n", voxel::getDefaultPaletteName()); + stream.writeStringFormat(false, "comment TextureFile palette-%s.png\n", paletteName); int elements = 0; int indices = 0; @@ -53,9 +55,9 @@ bool PLYFormat::saveMeshes(const Meshes& meshes, const core::String &filename, i stream.writeStringFormat(false, "property list uchar uint vertex_indices\n"); stream.writeStringFormat(false, "end_header\n"); - const MaterialColorArray& colors = getMaterialColors(); + const voxel::Palette& palette = voxel::getPalette(); // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)colors.size(); + const float texcoord = 1.0f / (float)palette.colorCount; // it is only 1 pixel high - sample the middle const float v1 = 0.5f; @@ -67,7 +69,6 @@ bool PLYFormat::saveMeshes(const Meshes& meshes, const core::String &filename, i for (int i = 0; i < nv; ++i) { const voxel::VoxelVertex& v = vertices[i]; - const glm::vec4& color = colors[v.colorIndex]; stream.writeStringFormat(false, "%f %f %f", (offset.x + (float)v.position.x) * scale, (offset.y + (float)v.position.y) * scale, -(offset.z + (float)v.position.z) * scale); if (withTexCoords) { @@ -75,8 +76,9 @@ bool PLYFormat::saveMeshes(const Meshes& meshes, const core::String &filename, i stream.writeStringFormat(false, " %f %f", u, v1); } if (withColor) { - stream.writeStringFormat(false, " %u %u %u", - (uint8_t)(color.r * 255.0f), (uint8_t)(color.g * 255.0f), (uint8_t)(color.b * 255.0f)); + const uint32_t color = palette.colors[v.colorIndex]; + const glm::u8vec4& cv = core::Color::toRGBA(color); + stream.writeStringFormat(false, " %u %u %u", cv.r, cv.g, cv.b); } stream.writeStringFormat(false, "\n"); } @@ -110,7 +112,7 @@ bool PLYFormat::saveMeshes(const Meshes& meshes, const core::String &filename, i } idxOffset += nv; } - return true; + return voxel::getPalette().save(paletteName); } } diff --git a/src/modules/voxelformat/QBCLFormat.cpp b/src/modules/voxelformat/QBCLFormat.cpp index 18986df6e..cefe4afbd 100644 --- a/src/modules/voxelformat/QBCLFormat.cpp +++ b/src/modules/voxelformat/QBCLFormat.cpp @@ -81,8 +81,8 @@ static int writeRLE(io::WriteStream& stream, const voxel::Voxel& voxel, uint8_t } glm::u8vec4 color(0); if (!voxel::isAir(voxel.getMaterial())) { - const glm::vec4 &rgbaColor = getMaterialColor(voxel); - color = core::Color::getRGBAVec(rgbaColor); + const voxel::Palette& palette = voxel::getPalette(); + color = core::Color::toRGBA(palette.colors[voxel.getColor()]); } if (count == 1) { wrapSaveColor(stream.writeUInt8(color.r)) @@ -350,7 +350,7 @@ bool QBCLFormat::readMatrix(const core::String &filename, io::SeekableReadStream for (int j = 0; j < rleLength; ++j) { const uint32_t x = (index / size.z); const uint32_t z = index % size.z; - volume->setVoxel(position.x + x, position.y + y, position.z + z, voxel); + volume->setVoxel(position.x + (int)x, position.y + y, position.z + (int)z, voxel); ++y; } } @@ -365,7 +365,7 @@ bool QBCLFormat::readMatrix(const core::String &filename, io::SeekableReadStream const glm::vec4& color = core::Color::fromRGBA(red, green, blue, 255); const uint8_t palIndex = findClosestIndex(color); const voxel::Voxel& voxel = voxel::createVoxel(voxel::VoxelType::Generic, palIndex); - volume->setVoxel(position.x + x, position.y + y, position.z + z, voxel); + volume->setVoxel(position.x + (int)x, position.y + y, position.z + (int)z, voxel); ++y; } } @@ -481,7 +481,7 @@ bool QBCLFormat::loadGroups(const core::String &filename, io::SeekableReadStream wrap(stream.readUInt32(thumbWidth)) uint32_t thumbHeight; wrap(stream.readUInt32(thumbHeight)) - if (stream.skip((int64_t)(thumbWidth * thumbHeight * 4)) == -1) { + if (stream.skip(((int64_t)thumbWidth * (int64_t)thumbHeight * 4)) == -1) { Log::error("Could not load qbcl file: Not enough data in stream " CORE_STRINGIFY(read)); return false; } diff --git a/src/modules/voxelformat/QBFormat.cpp b/src/modules/voxelformat/QBFormat.cpp index 5d069d722..2667531bd 100644 --- a/src/modules/voxelformat/QBFormat.cpp +++ b/src/modules/voxelformat/QBFormat.cpp @@ -9,6 +9,7 @@ #include "core/Log.h" #include "io/FileStream.h" #include "io/Stream.h" +#include "voxel/MaterialColor.h" namespace voxel { @@ -70,31 +71,29 @@ bool QBFormat::saveMatrix(io::SeekableWriteStream& stream, const SceneGraphNode& wrapSave(stream.writeUInt32(region.getLowerZ())); constexpr voxel::Voxel Empty; - const glm::ivec4 EmptyColor(0); + const glm::u8vec4 EmptyColor(0); const glm::ivec3& mins = region.getLowerCorner(); const glm::ivec3& maxs = region.getUpperCorner(); - glm::ivec4 currentColor = EmptyColor; + glm::u8vec4 currentColor = EmptyColor; int count = 0; + const voxel::Palette& palette = voxel::getPalette(); + for (int z = mins.z; z <= maxs.z; ++z) { for (int y = mins.y; y <= maxs.y; ++y) { for (int x = mins.x; x <= maxs.x; ++x) { const Voxel& voxel = node.volume()->voxel(x, y, z); - glm::ivec4 newColor; + glm::u8vec4 newColor; if (voxel == Empty) { newColor = EmptyColor; Log::trace("Save empty voxel: x %i, y %i, z %i", x, y, z); } else { - const glm::vec4& voxelColor = getColor(voxel); - const uint8_t red = (uint8_t)(voxelColor.r * 255.0f); - const uint8_t green = (uint8_t)(voxelColor.g * 255.0f); - const uint8_t blue = (uint8_t)(voxelColor.b * 255.0f); - const uint8_t alpha = (uint8_t)(voxelColor.a * 255.0f); - newColor = glm::ivec4(red, green, blue, alpha); + const uint32_t voxelColor = palette.colors[voxel.getColor()]; + newColor = core::Color::toRGBA(voxelColor); Log::trace("Save voxel: x %i, y %i, z %i (color: index(%i) => rgba(%i:%i:%i:%i))", - x, y, z, (int)voxel.getColor(), (int)red, (int)green, (int)blue, (int)alpha); + x, y, z, (int)voxel.getColor(), (int)newColor.r, (int)newColor.g, (int)newColor.b, (int)newColor.a); } if (newColor != currentColor) { @@ -238,7 +237,7 @@ bool QBFormat::loadMatrix(State& state, io::SeekableReadStream& stream, SceneGra for (uint32_t y = 0; y < size.y; ++y) { for (uint32_t x = 0; x < size.x; ++x) { const voxel::Voxel& voxel = getVoxel(state, stream); - v->setVoxel(offset.x + x, offset.y + y, offset.z + z, voxel); + v->setVoxel(offset.x + (int)x, offset.y + (int)y, offset.z + (int)z, voxel); } } } @@ -273,7 +272,7 @@ bool QBFormat::loadMatrix(State& state, io::SeekableReadStream& stream, SceneGra for (uint32_t j = 0; j < count; ++j) { const uint32_t x = (index + j) % size.x; const uint32_t y = (index + j) / size.x; - v->setVoxel(offset.x + x, offset.y + y, offset.z + z, voxel); + v->setVoxel(offset.x + (int)x, offset.y + (int)y, offset.z + (int)z, voxel); } index += count; } diff --git a/src/modules/voxelformat/QBTFormat.cpp b/src/modules/voxelformat/QBTFormat.cpp index 7dc873c45..5f8bb921c 100644 --- a/src/modules/voxelformat/QBTFormat.cpp +++ b/src/modules/voxelformat/QBTFormat.cpp @@ -62,6 +62,7 @@ bool QBTFormat::saveMatrix(io::SeekableWriteStream& stream, const SceneGraphNode uint8_t * const zlibBuffer = new uint8_t[zlibBufSize]; const uint32_t compressedBufSize = core::zip::compressBound(zlibBufSize); uint8_t *compressedBuf = new uint8_t[compressedBufSize]; + const voxel::Palette& palette = voxel::getPalette(); uint8_t* zlibBuf = zlibBuffer; for (int x = mins.x; x <= maxs.x; ++x) { @@ -80,14 +81,11 @@ bool QBTFormat::saveMatrix(io::SeekableWriteStream& stream, const SceneGraphNode *zlibBuf++ = 0; *zlibBuf++ = 0; } else { - const glm::vec4& voxelColor = getColor(voxel); - const uint8_t red = (uint8_t)(voxelColor.r * 255.0f); - const uint8_t green = (uint8_t)(voxelColor.g * 255.0f); - const uint8_t blue = (uint8_t)(voxelColor.b * 255.0f); + const glm::u8vec4 &voxelColor = core::Color::toRGBA(palette.colors[voxel.getColor()]); //const uint8_t alpha = voxelColor.a * 255.0f; - *zlibBuf++ = red; - *zlibBuf++ = green; - *zlibBuf++ = blue; + *zlibBuf++ = voxelColor.r; + *zlibBuf++ = voxelColor.g; + *zlibBuf++ = voxelColor.b; } // mask != 0 means solid, 1 is core (surrounded by others and not visible) *zlibBuf++ = 0xff; @@ -154,11 +152,10 @@ bool QBTFormat::saveMatrix(io::SeekableWriteStream& stream, const SceneGraphNode bool QBTFormat::saveColorMap(io::SeekableWriteStream& stream) const { wrapSave(stream.writeString("COLORMAP", false)); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); - wrapSave(stream.writeUInt32(materialColors.size())); - for (const glm::vec4& c : materialColors) { - const uint32_t rgba = core::Color::getRGBA(c); - wrapSave(stream.writeUInt32(rgba)); + const voxel::Palette& palette = voxel::getPalette(); + wrapSave(stream.writeUInt32(palette.colorCount)); + for (int i = 0; i < palette.colorCount; ++i) { + wrapSave(stream.writeUInt32(palette.colors[i])); } return true; } @@ -363,7 +360,7 @@ bool QBTFormat::loadMatrix(io::SeekableReadStream& stream, SceneGraph& sceneGrap if (mask == 0u) { continue; } - if (_paletteColors.colorCount > 0) { + if (_palette.colorCount > 0) { const voxel::Voxel& voxel = voxel::createVoxel(voxel::VoxelType::Generic, red); volume->setVoxel(position.x + x, position.y + y, position.z + z, voxel); } else { @@ -459,7 +456,7 @@ bool QBTFormat::loadColorMap(io::SeekableReadStream& stream) { Log::error("Sanity check for max colors failed (%u)", colorCount); return false; } - _paletteColors.colorCount = colorCount; + _palette.colorCount = (int)colorCount; for (uint32_t i = 0; i < colorCount; ++i) { uint8_t colorByteR; uint8_t colorByteG; @@ -476,7 +473,7 @@ bool QBTFormat::loadColorMap(io::SeekableReadStream& stream) { const uint32_t alpha = ((uint32_t)255) << 0; const glm::vec4& color = core::Color::fromRGBA(red | green | blue | alpha); - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); const uint8_t index = findClosestIndex(color); _paletteMapping[i] = index; } @@ -529,7 +526,7 @@ bool QBTFormat::loadFromStream(io::SeekableReadStream& stream, SceneGraph& scene Log::error("Failed to load color map"); return false; } - if (_paletteColors.colorCount == 0) { + if (_palette.colorCount == 0) { Log::debug("No color map found"); } else { Log::debug("Color map loaded"); diff --git a/src/modules/voxelformat/QEFFormat.cpp b/src/modules/voxelformat/QEFFormat.cpp index 170a36aed..92180c8dc 100644 --- a/src/modules/voxelformat/QEFFormat.cpp +++ b/src/modules/voxelformat/QEFFormat.cpp @@ -79,7 +79,7 @@ bool QEFFormat::loadGroups(const core::String &filename, io::SeekableReadStream return false; } - _paletteColors.colorCount = paletteSize; + _palette.colorCount = paletteSize; for (int i = 0; i < paletteSize; ++i) { float r, g, b; @@ -89,7 +89,7 @@ bool QEFFormat::loadGroups(const core::String &filename, io::SeekableReadStream return false; } const glm::vec4 color(r, g, b, 1.0f); - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); _paletteMapping[i] = findClosestIndex(color); } voxel::RawVolume* volume = new voxel::RawVolume(region); @@ -123,15 +123,16 @@ bool QEFFormat::saveGroups(const SceneGraph &sceneGraph, const core::String &fil RawVolume::Sampler sampler(mergedVolume); const glm::ivec3& lower = region.getLowerCorner(); - const MaterialColorArray& materialColors = getMaterialColors(); - const uint32_t width = region.getWidthInVoxels(); const uint32_t height = region.getHeightInVoxels(); const uint32_t depth = region.getDepthInVoxels(); stream.writeStringFormat(false, "%i %i %i\n", width, depth, height); - stream.writeStringFormat(false, "%i\n", (int)materialColors.size()); - for (size_t i = 0; i < materialColors.size(); ++i) { - stream.writeStringFormat(false, "%f %f %f\n", materialColors[i].r, materialColors[i].g, materialColors[i].b); + const voxel::Palette& palette = voxel::getPalette(); + stream.writeStringFormat(false, "%i\n", palette.colorCount); + for (int i = 0; i < palette.colorCount; ++i) { + const uint32_t c = palette.colors[i]; + const glm::vec4 &cv = core::Color::fromRGBA(c); + stream.writeStringFormat(false, "%f %f %f\n", cv.r, cv.g, cv.b); } for (uint32_t x = 0u; x < width; ++x) { diff --git a/src/modules/voxelformat/SproxelFormat.cpp b/src/modules/voxelformat/SproxelFormat.cpp index 1d4e7e021..02044b89b 100644 --- a/src/modules/voxelformat/SproxelFormat.cpp +++ b/src/modules/voxelformat/SproxelFormat.cpp @@ -7,6 +7,7 @@ #include "core/Log.h" #include "core/StringUtil.h" #include "core/Tokenizer.h" +#include "voxel/MaterialColor.h" namespace voxel { @@ -100,6 +101,7 @@ bool SproxelFormat::saveGroups(const SceneGraph &sceneGraph, const core::String return false; } + const voxel::Palette& palette = voxel::getPalette(); for (int y = height - 1; y >= 0; y--) { for (int z = 0u; z < depth; ++z) { for (int x = 0u; x < width; ++x) { @@ -108,8 +110,7 @@ bool SproxelFormat::saveGroups(const SceneGraph &sceneGraph, const core::String if (voxel.getMaterial() == VoxelType::Air) { stream.writeString("#00000000", false); } else { - const glm::vec4 &color = getColor(voxel); - const glm::u8vec4 &rgba = core::Color::getRGBAVec(color); + const glm::u8vec4 &rgba = core::Color::toRGBA(palette.colors[voxel.getColor()]); stream.writeStringFormat(false, "#%02X%02X%02X%02X", rgba.r, rgba.g, rgba.b, rgba.a); } if (x != width - 1) { diff --git a/src/modules/voxelformat/VXLFormat.cpp b/src/modules/voxelformat/VXLFormat.cpp index 7f85ff20f..a905a5702 100644 --- a/src/modules/voxelformat/VXLFormat.cpp +++ b/src/modules/voxelformat/VXLFormat.cpp @@ -43,7 +43,7 @@ bool VXLFormat::writeLimbBodyEntry(io::SeekableWriteStream& stream, const voxel: } bool VXLFormat::writeLimb(io::SeekableWriteStream& stream, const SceneGraph& sceneGraph, uint32_t limbIdx, LimbOffset& offsets, uint64_t limbSectionOffset) const { - const SceneGraphNode* node = sceneGraph[limbIdx]; + const SceneGraphNode* node = sceneGraph[(int)limbIdx]; core_assert_always(node != nullptr); const voxel::Region& region = node->region(); const glm::ivec3& size = region.getDimensionsInVoxels(); @@ -113,7 +113,7 @@ bool VXLFormat::writeLimb(io::SeekableWriteStream& stream, const SceneGraph& sce bool VXLFormat::writeLimbHeader(io::SeekableWriteStream& stream, const SceneGraph& sceneGraph, uint32_t limbIdx) const { core_assert((uint64_t)stream.pos() == (uint64_t)(HeaderSize + limbIdx * LimbHeaderSize)); - const SceneGraphNode* node = sceneGraph[limbIdx]; + const SceneGraphNode* node = sceneGraph[(int)limbIdx]; core_assert_always(node != nullptr); char name[15]; core_memcpy(name, node->name().c_str(), sizeof(name)); @@ -129,7 +129,7 @@ bool VXLFormat::writeLimbHeader(io::SeekableWriteStream& stream, const SceneGrap } bool VXLFormat::writeLimbFooter(io::SeekableWriteStream& stream, const SceneGraph& sceneGraph, uint32_t limbIdx, const LimbOffset& offsets) const { - const SceneGraphNode* node = sceneGraph[limbIdx]; + const SceneGraphNode* node = sceneGraph[(int)limbIdx]; core_assert_always(node != nullptr); wrapBool(stream.writeUInt32(offsets.start)) wrapBool(stream.writeUInt32(offsets.end)) @@ -158,10 +158,10 @@ bool VXLFormat::writeHeader(io::SeekableWriteStream& stream, const SceneGraph& s wrapBool(stream.writeUInt32(sceneGraph.size())) wrapBool(stream.writeUInt32(0)) // bodysize is filled later wrapBool(stream.writeUInt16(0x1f10U)) - const MaterialColorArray& materialColors = getMaterialColors(); - const uint32_t paletteSize = materialColors.size(); - for (uint32_t i = 0; i < paletteSize; ++i) { - const glm::u8vec4& rgba = core::Color::getRGBAVec(materialColors[i]); + + const voxel::Palette &palette = voxel::getPalette(); + for (int i = 0; i < palette.colorCount; ++i) { + const glm::u8vec4& rgba = core::Color::toRGBA(palette.colors[i]); wrapBool(stream.writeUInt8(rgba[0])) wrapBool(stream.writeUInt8(rgba[1])) wrapBool(stream.writeUInt8(rgba[2])) @@ -215,12 +215,12 @@ bool VXLFormat::readLimb(io::SeekableReadStream& stream, vxl_mdl& mdl, uint32_t wrap(stream.seek(limbOffset)) Log::debug("limbOffset: %u", (uint32_t)limbOffset); for (uint32_t i = 0; i < baseSize; ++i) { - uint32_t v; - wrap(stream.readUInt32(v)) + int32_t v; + wrap(stream.readInt32(v)) colStart[i] = v; } // skip spanPosEnd values - stream.skip(sizeof(uint32_t) * baseSize); + stream.skip((int64_t)sizeof(uint32_t) * baseSize); const uint64_t dataStart = stream.pos(); @@ -357,9 +357,9 @@ bool VXLFormat::readHeader(io::SeekableReadStream& stream, vxl_mdl& mdl) { Log::debug("Found %u limbs", hdr.n_limbs); - _paletteColors.colorCount = _paletteMapping.size(); + _palette.colorCount = voxel::PaletteMaxColors; bool valid = false; - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + for (int i = 0; i < _palette.colorCount; ++i) { wrap(stream.readUInt8(hdr.palette[i][0])) wrap(stream.readUInt8(hdr.palette[i][1])) wrap(stream.readUInt8(hdr.palette[i][2])) @@ -370,15 +370,15 @@ bool VXLFormat::readHeader(io::SeekableReadStream& stream, vxl_mdl& mdl) { if (valid) { // convert to our palette - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + for (int i = 0; i < _palette.colorCount; ++i) { const uint8_t *p = hdr.palette[i]; const glm::vec4& color = core::Color::fromRGBA(p[0], p[1], p[2], 0xffu); const int index = findClosestIndex(color); - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); _paletteMapping[i] = index; } } else { - _paletteColors.colorCount = 0; + _palette.colorCount = 0; } return true; diff --git a/src/modules/voxelformat/VXMFormat.cpp b/src/modules/voxelformat/VXMFormat.cpp index bbfa75ae7..ce2bd4792 100644 --- a/src/modules/voxelformat/VXMFormat.cpp +++ b/src/modules/voxelformat/VXMFormat.cpp @@ -128,8 +128,9 @@ bool VXMFormat::saveGroups(const SceneGraph& sceneGraph, const core::String &fil #endif } - MaterialColorArray materialColors = getMaterialColors(); - const MaterialColorArray &glowColors = getGlowColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); core::ScopedPtr scopedPtr(mergedVolume); const voxel::Region& region = mergedVolume->region(); @@ -150,23 +151,22 @@ bool VXMFormat::saveGroups(const SceneGraph& sceneGraph, const core::String &fil const glm::vec4 emptyColor = materialColors[EMPTY_PALETTE]; materialColors.pop(); const uint8_t emptyColorReplacement = core::Color::getClosestMatch(emptyColor, materialColors); - materialColors.push_back(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - int numColors = (int)materialColors.size(); + int numColors = palette.colorCount; if (numColors > 255) { numColors = 255; } if (numColors <= 0) { return false; } - wrapBool(stream.writeUInt8(numColors)) + wrapBool(stream.writeUInt8(materialColors.size())) for (int i = 0; i < numColors; ++i) { - const glm::u8vec4 &matcolor = core::Color::getRGBAVec(materialColors[i]); + const glm::u8vec4 &matcolor = core::Color::toRGBA(palette.colors[i]); wrapBool(stream.writeUInt8(matcolor.b)) wrapBool(stream.writeUInt8(matcolor.g)) wrapBool(stream.writeUInt8(matcolor.r)) wrapBool(stream.writeUInt8(matcolor.a)) - const glm::u8vec4 &glowcolor = core::Color::getRGBAVec(glowColors[i]); + const glm::u8vec4 &glowcolor = core::Color::toRGBA(palette.glowColors[i]); const bool emissive = glowcolor.a > 0; wrapBool(stream.writeBool(emissive)) } @@ -410,15 +410,15 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream& uint8_t emissive; wrap(stream.readUInt8(emissive)); const glm::vec4& rgbaColor = core::Color::fromRGBA(red, green, blue, alpha); - _paletteColors._colors[i] = core::Color::getRGBA(rgbaColor); + _palette.colors[i] = core::Color::getRGBA(rgbaColor); _paletteMapping[i] = findClosestIndex(rgbaColor); if (emissive) { - _paletteColors._glowColors[i] = _paletteColors._colors[i]; + _palette.setGlow(i); } else { - _paletteColors._glowColors[i] = 0; + _palette.removeGlow(i); } } - _paletteColors.colorCount = materialAmount; + _palette.colorCount = materialAmount; const Region region(glm::ivec3(0), glm::ivec3(size) - 1); diff --git a/src/modules/voxelformat/VolumeFormat.h b/src/modules/voxelformat/VolumeFormat.h index a6b8f5a01..dd9ced614 100644 --- a/src/modules/voxelformat/VolumeFormat.h +++ b/src/modules/voxelformat/VolumeFormat.h @@ -12,7 +12,7 @@ #include "core/collection/Array.h" namespace voxel { -struct Palette; +class Palette; } namespace voxelformat { diff --git a/src/modules/voxelformat/VoxFormat.cpp b/src/modules/voxelformat/VoxFormat.cpp index 7953f5a11..95e29a319 100644 --- a/src/modules/voxelformat/VoxFormat.cpp +++ b/src/modules/voxelformat/VoxFormat.cpp @@ -61,17 +61,16 @@ size_t VoxFormat::loadPalette(const core::String &filename, io::SeekableReadStre Log::error("Could not load scene %s", filename.c_str()); return 0; } - _paletteColors.colorCount = lengthof(scene->palette.color); - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + palette.colorCount = lengthof(scene->palette.color); + for (int i = 0; i < palette.colorCount; ++i) { const ogt_vox_rgba& c = scene->palette.color[i]; const ogt_vox_matl& matl = scene->materials.matl[i]; - _paletteColors._colors[i] = palette._colors[i] = core::Color::getRGBA(c.r, c.g, c.b, c.a); + palette.colors[i] = core::Color::getRGBA(c.r, c.g, c.b, c.a); if (matl.emit > 0.0f) { - _paletteColors._glowColors[i] = _paletteColors._colors[i]; // TODO: multiply by matl.emit? + palette.setGlow(i, matl.emit); } else { - _paletteColors._glowColors[i] = 0; + palette.removeGlow(i); } - _paletteMapping[i] = i; } ogt_vox_destroy_scene(scene); return palette.size(); @@ -202,20 +201,19 @@ bool VoxFormat::loadGroups(const core::String &filename, io::SeekableReadStream return false; } - for (int i = 0; i < (int)_paletteMapping.size(); ++i) { + _palette.colorCount = lengthof(scene->palette.color); + for (int i = 0; i < _palette.colorCount; ++i) { const ogt_vox_rgba color = scene->palette.color[i]; const glm::vec4& colorVec = core::Color::fromRGBA(color.r, color.g, color.b, color.a); - _paletteColors._colors[i] = core::Color::getRGBA(colorVec); - const uint8_t index = findClosestIndex(colorVec); - _paletteMapping[i] = index; + _palette.colors[i] = core::Color::getRGBA(colorVec); const ogt_vox_matl& matl = scene->materials.matl[i]; if (matl.emit > 0.0f) { - _paletteColors._glowColors[i] = _paletteColors._colors[i]; // TODO: multiply by matl.emit? + _palette.setGlow(i, matl.emit); } else { - _paletteColors._glowColors[i] = 0; + _palette.removeGlow(i); } + _paletteMapping[i] = findClosestIndex(colorVec); } - _paletteColors.colorCount = _paletteColors.size(); // rotation matrix to convert into our coordinate system (z pointing upwards) const glm::mat4 zUpMat = glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)); @@ -252,7 +250,9 @@ bool VoxFormat::loadGroups(const core::String &filename, io::SeekableReadStream int VoxFormat::findClosestPaletteIndex() { // we have to find a replacement for the first palette entry - as this is used // as the empty voxel in magicavoxel - voxel::MaterialColorArray materialColors = voxel::getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); const glm::vec4 first = materialColors[0]; materialColors.erase(materialColors.begin()); return core::Color::getClosestMatch(first, materialColors) + 1; @@ -268,9 +268,10 @@ bool VoxFormat::saveGroups(const SceneGraph &sceneGraph, const core::String &fil default_group.parent_group_index = k_invalid_group_index; default_group.transform = ogt_identity_transform; + const voxel::Palette &palette = voxel::getPalette(); const int replacement = findClosestPaletteIndex(); - const glm::vec4 emptyColor = getColor(voxel::Voxel(voxel::VoxelType::Generic, 0)); - const glm::vec4 replaceColor = getColor(voxel::Voxel(voxel::VoxelType::Generic, replacement)); + const glm::vec4 emptyColor = core::Color::toRGBA(palette.colors[0]); + const glm::vec4 replaceColor = core::Color::toRGBA(palette.colors[replacement]); Log::debug("Replacement for %f:%f:%f:%f is at %i (%f:%f:%f:%f)", emptyColor.r, emptyColor.g, emptyColor.b, emptyColor.a, replacement, replaceColor.r, replaceColor.g, replaceColor.b, replaceColor.a); @@ -336,16 +337,16 @@ bool VoxFormat::saveGroups(const SceneGraph &sceneGraph, const core::String &fil ogt_vox_palette& pal = output_scene.palette; ogt_vox_matl_array& mat = output_scene.materials; - const MaterialColorArray& materialColors = getMaterialColors(); - const MaterialColorArray& glowColors = getGlowColors(); for (int i = 0; i < 256; ++i) { - pal.color[i].r = (uint8_t)(materialColors[i].r * 255.0f); - pal.color[i].g = (uint8_t)(materialColors[i].g * 255.0f); - pal.color[i].b = (uint8_t)(materialColors[i].b * 255.0f); - pal.color[i].a = (uint8_t)(materialColors[i].a * 255.0f); + const glm::u8vec4 rgba = core::Color::toRGBA(palette.colors[i]); + pal.color[i].r = rgba.r; + pal.color[i].g = rgba.g; + pal.color[i].b = rgba.b; + pal.color[i].a = rgba.a; - if (glowColors[i].a != 0) { + const glm::u8vec4 glowColor = core::Color::toRGBA(palette.glowColors[i]); + if (glowColor.a != 0) { mat.matl[i].content_flags |= k_ogt_vox_matl_have_emit; mat.matl[i].type = ogt_matl_type::ogt_matl_type_emit; mat.matl[i].emit = 1.0f; diff --git a/src/modules/voxelformat/VoxOldFormat.cpp b/src/modules/voxelformat/VoxOldFormat.cpp index fbf5ccc61..1ef9058cf 100644 --- a/src/modules/voxelformat/VoxOldFormat.cpp +++ b/src/modules/voxelformat/VoxOldFormat.cpp @@ -44,15 +44,15 @@ bool VoxOldFormat::loadGroups(const core::String &filename, io::SeekableReadStre const int64_t voxelPos = stream.pos(); stream.skip((int64_t)width * height * depth); - _paletteColors.colorCount = 256; - for (size_t i = 0; i < _paletteColors.colorCount; ++i) { + _palette.colorCount = 256; + for (int i = 0; i < _palette.colorCount; ++i) { uint8_t r, g, b; wrap(stream.readUInt8(r)) wrap(stream.readUInt8(g)) wrap(stream.readUInt8(b)) const glm::vec4 color = core::Color::fromRGBA(r, g, b, 255); - _paletteColors._colors[i] = core::Color::getRGBA(color); + _palette.colors[i] = core::Color::getRGBA(color); _paletteMapping[i] = findClosestIndex(color); } diff --git a/src/modules/voxelgenerator/LUAGenerator.cpp b/src/modules/voxelgenerator/LUAGenerator.cpp index ad6d04554..4278c07a0 100644 --- a/src/modules/voxelgenerator/LUAGenerator.cpp +++ b/src/modules/voxelgenerator/LUAGenerator.cpp @@ -86,11 +86,11 @@ static int luaVoxel_volumewrapper_setvoxel(lua_State* s) { } static int luaVoxel_palette_colors(lua_State* s) { - const voxel::MaterialColorArray& colors = voxel::getMaterialColors(); - lua_createtable(s, (int)colors.size(), 0); - for (size_t i = 0; i < colors.size(); ++i) { - const glm::vec4& c = colors[i]; - lua_pushinteger(s, (int)i + 1); + const voxel::Palette &palette = voxel::getPalette(); + lua_createtable(s, palette.colorCount, 0); + for (int i = 0; i < palette.colorCount; ++i) { + const glm::vec4& c = core::Color::fromRGBA(palette.colors[i]); + lua_pushinteger(s, i + 1); clua_push(s, c); lua_settable(s, -3); } @@ -99,17 +99,20 @@ static int luaVoxel_palette_colors(lua_State* s) { static int luaVoxel_palette_color(lua_State* s) { const uint8_t color = luaL_checkinteger(s, 1); - const glm::vec4& rgba = voxel::getMaterialColor(voxel::createVoxel(voxel::VoxelType::Generic, color)); + const voxel::Palette &palette = voxel::getPalette(); + const glm::vec4& rgba = core::Color::fromRGBA(palette.colors[color]); return clua_push(s, rgba); } static int luaVoxel_palette_closestmatch(lua_State* s) { - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); const float r = (float)luaL_checkinteger(s, 1) / 255.0f; const float g = (float)luaL_checkinteger(s, 2) / 255.0f; const float b = (float)luaL_checkinteger(s, 3) / 255.0f; const int match = core::Color::getClosestMatch(glm::vec4(r, b, g, 1.0f), materialColors); - if (match < 0 || match > (int)materialColors.size()) { + if (match < 0 || match > palette.colorCount) { return clua_error(s, "Given color index is not valid or palette is not loaded"); } lua_pushinteger(s, match); @@ -119,10 +122,13 @@ static int luaVoxel_palette_closestmatch(lua_State* s) { static int luaVoxel_palette_similar(lua_State* s) { const int paletteIndex = lua_tointeger(s, 1); const int colorCount = lua_tointeger(s, 2); - voxel::MaterialColorArray colors = voxel::getMaterialColors(); - if (paletteIndex < 0 || paletteIndex >= (int)colors.size()) { + const voxel::Palette &palette = voxel::getPalette(); + if (paletteIndex < 0 || paletteIndex >= palette.colorCount) { return clua_error(s, "Palette index out of bounds"); } + core::DynamicArray colors; + palette.toVec4f(colors); + const core::DynamicArray materialColors = colors; const glm::vec4 color = colors[paletteIndex]; voxel::MaterialColorIndices newColorIndices; newColorIndices.resize(colorCount); @@ -134,7 +140,7 @@ static int luaVoxel_palette_similar(lua_State* s) { break; } const glm::vec4& c = colors[index]; - const int materialIndex = core::Color::getClosestMatch(c, voxel::getMaterialColors()); + const int materialIndex = core::Color::getClosestMatch(c, materialColors); colors.erase(index); newColorIndices[maxColorIndices] = materialIndex; } diff --git a/src/modules/voxelgenerator/tests/LUAGeneratorTest.cpp b/src/modules/voxelgenerator/tests/LUAGeneratorTest.cpp index 4bbfd89e1..c1c5674ce 100644 --- a/src/modules/voxelgenerator/tests/LUAGeneratorTest.cpp +++ b/src/modules/voxelgenerator/tests/LUAGeneratorTest.cpp @@ -48,7 +48,7 @@ TEST_F(LUAGeneratorTest, testExecute) { end )"; - ASSERT_TRUE(voxel::initDefaultMaterialColors()); + ASSERT_TRUE(voxel::initDefaultPalette()); voxel::Region region(0, 0, 0, 7, 7, 7); voxel::RawVolume volume(region); @@ -85,7 +85,7 @@ TEST_F(LUAGeneratorTest, testArguments) { end )"; - ASSERT_TRUE(voxel::initDefaultMaterialColors()); + ASSERT_TRUE(voxel::initDefaultPalette()); voxel::Region region(0, 0, 0, 7, 7, 7); voxel::RawVolume volume(region); diff --git a/src/modules/voxelgenerator/tests/ShapeGeneratorTest.cpp b/src/modules/voxelgenerator/tests/ShapeGeneratorTest.cpp index 62ab16fe9..a92ae6265 100644 --- a/src/modules/voxelgenerator/tests/ShapeGeneratorTest.cpp +++ b/src/modules/voxelgenerator/tests/ShapeGeneratorTest.cpp @@ -42,7 +42,7 @@ protected: public: void SetUp() override { Super::SetUp(); - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _volume = new voxel::RawVolume(_region); } diff --git a/src/modules/voxelrender/CMakeLists.txt b/src/modules/voxelrender/CMakeLists.txt index 72ed0f6c8..21379c260 100644 --- a/src/modules/voxelrender/CMakeLists.txt +++ b/src/modules/voxelrender/CMakeLists.txt @@ -19,14 +19,3 @@ endforeach() engine_add_module(TARGET ${LIB} SRCS ${SRCS} ${SRCS_SHADERS} DEPENDENCIES render voxelfont voxelformat) generate_shaders(${LIB} ${SHADERS}) - -set(TEST_SRCS - tests/MaterialTest.cpp -) -gtest_suite_sources(tests ${TEST_SRCS}) -gtest_suite_deps(tests ${LIB} test-app image) - -gtest_suite_begin(tests-${LIB} TEMPLATE ${ROOT_DIR}/src/modules/core/tests/main.cpp.in) -gtest_suite_sources(tests-${LIB} ${TEST_SRCS}) -gtest_suite_deps(tests-${LIB} ${LIB} test-app image) -gtest_suite_end(tests-${LIB}) diff --git a/src/modules/voxelrender/MeshRenderer.cpp b/src/modules/voxelrender/MeshRenderer.cpp index 641664ecc..9aed8b817 100644 --- a/src/modules/voxelrender/MeshRenderer.cpp +++ b/src/modules/voxelrender/MeshRenderer.cpp @@ -54,8 +54,14 @@ bool MeshRenderer::init() { mesh.buffer.addAttribute(attributeInfo); } + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + const int shaderMaterialColorsArraySize = lengthof(shader::VoxelData::MaterialblockData::materialcolor); - const int materialColorsArraySize = voxel::getMaterialColors().size(); + const int materialColorsArraySize = palette.colorCount; if (shaderMaterialColorsArraySize != materialColorsArraySize) { Log::error("Shader parameters and material colors don't match in their size: %i - %i", shaderMaterialColorsArraySize, materialColorsArraySize); @@ -69,8 +75,8 @@ bool MeshRenderer::init() { } shader::VoxelData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); _materialBlock.create(materialBlock); return true; diff --git a/src/modules/voxelrender/RawVolumeRenderer.cpp b/src/modules/voxelrender/RawVolumeRenderer.cpp index a75e51196..fcff84f0a 100644 --- a/src/modules/voxelrender/RawVolumeRenderer.cpp +++ b/src/modules/voxelrender/RawVolumeRenderer.cpp @@ -109,8 +109,14 @@ bool RawVolumeRenderer::init() { } } + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + const int shaderMaterialColorsArraySize = lengthof(shader::VoxelData::MaterialblockData::materialcolor); - const int materialColorsArraySize = (int)voxel::getMaterialColors().size(); + const int materialColorsArraySize = (int)materialColors.size(); if (shaderMaterialColorsArraySize != materialColorsArraySize) { Log::error("Shader parameters and material colors don't match in their size: %i - %i", shaderMaterialColorsArraySize, materialColorsArraySize); @@ -137,8 +143,8 @@ bool RawVolumeRenderer::init() { } shader::VoxelData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); _materialBlock.create(materialBlock); _meshSize = core::Var::getSafe(cfg::VoxelMeshSize); @@ -451,9 +457,15 @@ void RawVolumeRenderer::render(const video::Camera& camera, bool shadow) { core_trace_scoped(RawVolumeRendererRender); if (voxel::materialColorChanged()) { + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + shader::VoxelData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); _materialBlock.update(materialBlock); // TODO: updating the global state is crap - what about others - use an event voxel::materialColorMarkClean(); diff --git a/src/modules/voxelrender/tests/MaterialTest.cpp b/src/modules/voxelrender/tests/MaterialTest.cpp deleted file mode 100644 index cf5508f14..000000000 --- a/src/modules/voxelrender/tests/MaterialTest.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file - */ - -#include "app/tests/AbstractTest.h" -#include "image/Image.h" -#include "core/GLM.h" -#include "core/Color.h" -#include "voxel/MaterialColor.h" -#include "core/collection/DynamicArray.h" - -namespace voxelrender { - -class MaterialTest: public app::AbstractTest { -protected: - const int components = 4; - const int w = 256; - const int h = 256; - - bool WriteImage(const char* name, uint8_t* buffer, int w = 256, int h = 256, int components = 4) { - return image::Image::writePng(name, buffer, w, h, components); - } -}; - -TEST_F(MaterialTest, testMaterial) { - const int w = 256; - const int h = 1024; - core::DynamicArray buffer(w * h * components); - - ASSERT_TRUE(voxel::initDefaultMaterialColors()); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); - const int amount = materialColors.size(); - ASSERT_GT(amount, 0) << "No material colors are defined"; - auto line_height = h / amount; - - int y = 0; - for (int color_index = 0; color_index < amount; ++color_index) { - auto line_y = 0; - auto color = materialColors[color_index]; - for (; line_y < line_height; ++y, ++line_y) { - for (int x = 0; x < w; ++x) { - int index = y * (w * components) + (x * components); - buffer[index++] = line_y == 0 ? 0 : color.r * 255; - buffer[index++] = line_y == 0 ? 0 : color.g * 255; - buffer[index++] = line_y == 0 ? 0 : color.b * 255; - buffer[index++] = line_y == 0 ? 255 : color.a * 255; - } - } - } - ASSERT_TRUE(WriteImage("material.png", &buffer[0], w, h)); -} - -} diff --git a/src/modules/voxelutil/ImageUtils.cpp b/src/modules/voxelutil/ImageUtils.cpp index 16502a80d..fcaea52c9 100644 --- a/src/modules/voxelutil/ImageUtils.cpp +++ b/src/modules/voxelutil/ImageUtils.cpp @@ -65,7 +65,9 @@ voxel::RawVolume* importAsPlane(const image::ImagePtr& image, uint8_t thickness) } Log::info("Import image as plane: w(%i), h(%i), d(%i)", imageWidth, imageHeight, thickness); const voxel::Region region(0, 0, 0, imageWidth - 1, imageHeight - 1, thickness - 1); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); voxel::RawVolume* volume = new voxel::RawVolume(region); for (int x = 0; x < imageWidth; ++x) { for (int y = 0; y < imageHeight; ++y) { diff --git a/src/modules/voxelutil/VolumeRescaler.h b/src/modules/voxelutil/VolumeRescaler.h index f2ed80e90..cfc6cbb76 100644 --- a/src/modules/voxelutil/VolumeRescaler.h +++ b/src/modules/voxelutil/VolumeRescaler.h @@ -46,7 +46,9 @@ void rescaleVolume(const SourceVolume& sourceVolume, const Region& sourceRegion, core_trace_scoped(RescaleVolume); typename SourceVolume::Sampler srcSampler(sourceVolume); - const MaterialColorArray& colors = getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); const int32_t depth = destRegion.getDepthInVoxels(); const int32_t height = destRegion.getHeightInVoxels(); @@ -81,7 +83,7 @@ void rescaleVolume(const SourceVolume& sourceVolume, const Region& sourceRegion, colorGuardVoxel = child; continue; } - const glm::vec4& color = colors[child.getColor()]; + const glm::vec4& color = core::Color::fromRGBA(palette.colors[child.getColor()]); avgColorRed += color.r; avgColorGreen += color.g; avgColorBlue += color.b; @@ -95,14 +97,14 @@ void rescaleVolume(const SourceVolume& sourceVolume, const Region& sourceRegion, // means that higher LOD meshes actually shrink away which ensures cracks aren't visible. if (solidVoxels >= 7.0f) { if (colorContributors <= 0.0f) { - const glm::vec4 &color = colors[colorGuardVoxel.getColor()]; + const glm::vec4 &color = core::Color::fromRGBA(palette.colors[colorGuardVoxel.getColor()]); avgColorRed += color.r; avgColorGreen += color.g; avgColorBlue += color.b; ++colorContributors; } const glm::vec4 avgColor(avgColorRed / colorContributors, avgColorGreen / colorContributors, avgColorBlue / colorContributors, 1.0f); - const int index = core::Color::getClosestMatch(avgColor, colors); + const int index = core::Color::getClosestMatch(avgColor, materialColors); Voxel voxel = createVoxel(VoxelType::Generic, index); destVolume.setVoxel(dstPos, voxel); } else { @@ -178,7 +180,7 @@ void rescaleVolume(const SourceVolume& sourceVolume, const Region& sourceRegion, ++exposedFaces; } - const glm::vec4& color = colors[child.getColor()]; + const glm::vec4& color = core::Color::fromRGBA(palette.colors[child.getColor()]); totalRed += color.r * exposedFaces; totalGreen += color.g * exposedFaces; totalBlue += color.b * exposedFaces; @@ -194,7 +196,7 @@ void rescaleVolume(const SourceVolume& sourceVolume, const Region& sourceRegion, } const glm::vec4 avgColor(totalRed / totalExposedFaces, totalGreen / totalExposedFaces, totalBlue / totalExposedFaces, 1.0f); - const int index = core::Color::getClosestMatch(avgColor, colors); + const int index = core::Color::getClosestMatch(avgColor, materialColors); const Voxel voxel = createVoxel(VoxelType::Generic, index); destVolume.setVoxel(dstPos, voxel); } diff --git a/src/modules/voxelutil/tests/ImageUtilsTest.cpp b/src/modules/voxelutil/tests/ImageUtilsTest.cpp index b621f2e5e..a73cdb960 100644 --- a/src/modules/voxelutil/tests/ImageUtilsTest.cpp +++ b/src/modules/voxelutil/tests/ImageUtilsTest.cpp @@ -14,9 +14,9 @@ class ImageUtilsTest: public app::AbstractTest { TEST_F(ImageUtilsTest, testCreateAndLoadPalette) { const image::ImagePtr& img = image::loadImage("test-palette-in.png", false); ASSERT_TRUE(img->isLoaded()) << "Failed to load image: " << img->name(); - uint32_t buf[256]; - EXPECT_TRUE(voxel::createPalette(img, buf, 256)) << "Failed to create palette image"; - EXPECT_TRUE(voxel::overrideMaterialColors((const uint8_t*)buf, sizeof(buf), "")); + voxel::Palette palette; + EXPECT_TRUE(voxel::Palette::createPalette(img, palette)) << "Failed to create palette image"; + EXPECT_TRUE(voxel::overridePalette(palette)); } } diff --git a/src/modules/voxelworld/benchmarks/VoxelBenchmark.cpp b/src/modules/voxelworld/benchmarks/VoxelBenchmark.cpp index 0d1701088..c3b002fdf 100644 --- a/src/modules/voxelworld/benchmarks/VoxelBenchmark.cpp +++ b/src/modules/voxelworld/benchmarks/VoxelBenchmark.cpp @@ -21,7 +21,7 @@ public: } bool onInitApp() override { - voxel::initDefaultMaterialColors(); + voxel::initDefaultPalette(); _volumeCache = std::make_shared(); return _volumeCache->init(); } diff --git a/src/modules/voxelworld/tests/AbstractVoxelWorldTest.h b/src/modules/voxelworld/tests/AbstractVoxelWorldTest.h index a57925ddf..1fdb7e0fe 100644 --- a/src/modules/voxelworld/tests/AbstractVoxelWorldTest.h +++ b/src/modules/voxelworld/tests/AbstractVoxelWorldTest.h @@ -67,7 +67,7 @@ public: void SetUp() override { _volData.flushAll(); app::AbstractTest::SetUp(); - ASSERT_TRUE(voxel::initDefaultMaterialColors()); + ASSERT_TRUE(voxel::initDefaultPalette()); _random.setSeed(_seed); _ctx = voxel::PagedVolumeWrapper(&_volData, _volData.chunk(_region.getCenter()), _region); } diff --git a/src/modules/voxelworldrender/WorldRenderer.cpp b/src/modules/voxelworldrender/WorldRenderer.cpp index ab8089cc8..66854e9c7 100644 --- a/src/modules/voxelworldrender/WorldRenderer.cpp +++ b/src/modules/voxelworldrender/WorldRenderer.cpp @@ -101,13 +101,14 @@ int WorldRenderer::renderPostProcessEffects(const video::Camera& camera) { const int currentEyeHeight = (int)camera.eye().y; if (currentEyeHeight <= voxel::MAX_WATER_HEIGHT) { static const voxel::Voxel waterVoxel = voxel::createColorVoxel(voxel::VoxelType::Water, 0); - const glm::vec4& waterColor = voxel::getMaterialColor(waterVoxel); + const voxel::Palette &palette = voxel::getPalette(); + const glm::vec4& waterColor = core::Color::fromRGBA(palette.colors[waterVoxel.getColor()]); _postProcessShader.setColor(waterColor); } else { _postProcessShader.setColor(glm::one()); } _postProcessShader.setTexture(video::TextureUnit::Zero); - const int elements = _postProcessBuf.elements(_postProcessBufId, _postProcessShader.getComponentsPos()); + const int elements = (int)_postProcessBuf.elements(_postProcessBufId, _postProcessShader.getComponentsPos()); video::drawArrays(video::Primitive::Triangles, elements); return 1; } @@ -279,7 +280,7 @@ int WorldRenderer::renderWater(const video::Camera& camera, const glm::vec4& cli _waterShader.setCamerapos(camera.worldPosition()); _waterShader.setLightdir(_shadow.sunDirection()); _waterShader.setFogrange(_fogRange); - _waterShader.setTime(_seconds); + _waterShader.setTime((float)_seconds); _waterShader.setFar(camera.farPlane()); _waterShader.setNear(camera.nearPlane()); _skybox.bind(video::TextureUnit::Two); @@ -298,7 +299,7 @@ int WorldRenderer::renderWater(const video::Camera& camera, const glm::vec4& cli } video::ScopedBuffer scopedBuf(_waterBuffer); - const int elements = _waterBuffer.elements(_waterVbo, core::remove_reference::type::length()); + const int elements = (int)_waterBuffer.elements(_waterVbo, core::remove_reference::type::length()); video::drawArrays(video::Primitive::Triangles, elements); _skybox.unbind(video::TextureUnit::Two); @@ -393,8 +394,15 @@ bool WorldRenderer::init(voxel::PagedVolume* volume, const glm::ivec2& position, Log::error("Failed to init shadowmap shader"); return false; } + + const voxel::Palette &palette = voxel::getPalette(); + core::DynamicArray materialColors; + palette.toVec4f(materialColors); + core::DynamicArray glowColors; + palette.glowToVec4f(glowColors); + const int shaderMaterialColorsArraySize = lengthof(shader::WorldData::MaterialblockData::materialcolor); - const int materialColorsArraySize = (int)voxel::getMaterialColors().size(); + const int materialColorsArraySize = palette.colorCount; if (shaderMaterialColorsArraySize != materialColorsArraySize) { Log::error("Shader parameters and material colors don't match in their size: %i - %i", shaderMaterialColorsArraySize, materialColorsArraySize); @@ -402,8 +410,8 @@ bool WorldRenderer::init(voxel::PagedVolume* volume, const glm::ivec2& position, } shader::WorldData::MaterialblockData materialBlock; - core_memcpy(materialBlock.materialcolor, &voxel::getMaterialColors().front(), sizeof(materialBlock.materialcolor)); - core_memcpy(materialBlock.glowcolor, &voxel::getGlowColors().front(), sizeof(materialBlock.glowcolor)); + core_memcpy(materialBlock.materialcolor, &materialColors.front(), sizeof(materialBlock.materialcolor)); + core_memcpy(materialBlock.glowcolor, &glowColors.front(), sizeof(materialBlock.glowcolor)); _materialBlock.create(materialBlock); _waterVbo = _waterBuffer.create(waterPlaneVecs, sizeof(waterPlaneVecs)); diff --git a/src/tests/testanimation/TestAnimation.cpp b/src/tests/testanimation/TestAnimation.cpp index 145d19e94..9c90a31bb 100644 --- a/src/tests/testanimation/TestAnimation.cpp +++ b/src/tests/testanimation/TestAnimation.cpp @@ -150,7 +150,7 @@ app::AppState TestAnimation::onInit() { camera().setWorldPosition(glm::vec3(10.0f, 5.0f, 10.0f)); camera().lookAt(glm::zero()); - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the default material colors"); return app::AppState::InitFailure; } diff --git a/src/tests/testbiomes/TestBiomes.cpp b/src/tests/testbiomes/TestBiomes.cpp index 2d6dc121c..362adac54 100644 --- a/src/tests/testbiomes/TestBiomes.cpp +++ b/src/tests/testbiomes/TestBiomes.cpp @@ -43,7 +43,7 @@ app::AppState TestBiomes::onInit() { return app::AppState::InitFailure; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the material colors"); return app::AppState::InitFailure; } diff --git a/src/tests/testcomputetexture3d/TestComputeTexture3D.cpp b/src/tests/testcomputetexture3d/TestComputeTexture3D.cpp index 7f89a45ab..dd2a52ad0 100644 --- a/src/tests/testcomputetexture3d/TestComputeTexture3D.cpp +++ b/src/tests/testcomputetexture3d/TestComputeTexture3D.cpp @@ -40,7 +40,7 @@ app::AppState TestComputeTexture3D::onInit() { return app::AppState::InitFailure; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tests/testgpumc/TestGPUMC.cpp b/src/tests/testgpumc/TestGPUMC.cpp index ad4ea0c8c..aa38bde67 100644 --- a/src/tests/testgpumc/TestGPUMC.cpp +++ b/src/tests/testgpumc/TestGPUMC.cpp @@ -70,7 +70,7 @@ app::AppState TestGPUMC::onInit() { Log::info("write to buffers"); } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tests/testmeshrenderer/TestMeshRenderer.cpp b/src/tests/testmeshrenderer/TestMeshRenderer.cpp index 6e9662aa5..192550940 100644 --- a/src/tests/testmeshrenderer/TestMeshRenderer.cpp +++ b/src/tests/testmeshrenderer/TestMeshRenderer.cpp @@ -21,7 +21,7 @@ app::AppState TestMeshRenderer::onInit() { return state; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tests/testtextureatlasrenderer/TestTextureAtlasRenderer.cpp b/src/tests/testtextureatlasrenderer/TestTextureAtlasRenderer.cpp index 8b88d8867..dda39a484 100644 --- a/src/tests/testtextureatlasrenderer/TestTextureAtlasRenderer.cpp +++ b/src/tests/testtextureatlasrenderer/TestTextureAtlasRenderer.cpp @@ -25,7 +25,7 @@ app::AppState TestTextureAtlasRenderer::onInit() { return state; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tests/testvoxelfont/TestVoxelFont.cpp b/src/tests/testvoxelfont/TestVoxelFont.cpp index 96acb293b..e860c4051 100644 --- a/src/tests/testvoxelfont/TestVoxelFont.cpp +++ b/src/tests/testvoxelfont/TestVoxelFont.cpp @@ -22,7 +22,7 @@ app::AppState TestVoxelFont::onInit() { return state; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tests/testvoxelgpu/TestVoxelGPU.cpp b/src/tests/testvoxelgpu/TestVoxelGPU.cpp index d9e56f79f..2a93f65ac 100644 --- a/src/tests/testvoxelgpu/TestVoxelGPU.cpp +++ b/src/tests/testvoxelgpu/TestVoxelGPU.cpp @@ -30,7 +30,7 @@ app::AppState TestVoxelGPU::onInit() { return app::AppState::InitFailure; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tools/mapview/MapView.cpp b/src/tools/mapview/MapView.cpp index c7e83d384..d406b5314 100644 --- a/src/tools/mapview/MapView.cpp +++ b/src/tools/mapview/MapView.cpp @@ -135,7 +135,7 @@ app::AppState MapView::onInit() { Log::warn("Failed to initialize the sound manager"); } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return app::AppState::InitFailure; } diff --git a/src/tools/thumbnailer/ImageGenerator.cpp b/src/tools/thumbnailer/ImageGenerator.cpp index c07f9efc9..7d959aa3d 100644 --- a/src/tools/thumbnailer/ImageGenerator.cpp +++ b/src/tools/thumbnailer/ImageGenerator.cpp @@ -23,7 +23,7 @@ image::ImagePtr volumeThumbnail(const core::String &fileName, io::SeekableReadSt if (image && image->isLoaded()) { return image; } - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::warn("Failed to initialize the default materials"); } @@ -31,7 +31,7 @@ image::ImagePtr volumeThumbnail(const core::String &fileName, io::SeekableReadSt voxel::Palette palette; const size_t paletteCount = voxelformat::loadPalette(fileName, stream, palette); if (paletteCount > 0) { - voxel::overrideMaterialColors(palette); + voxel::overridePalette(palette); } voxel::SceneGraph sceneGraph; diff --git a/src/tools/voxconvert/VoxConvert.cpp b/src/tools/voxconvert/VoxConvert.cpp index 2d8d7f79b..9ac988666 100644 --- a/src/tools/voxconvert/VoxConvert.cpp +++ b/src/tools/voxconvert/VoxConvert.cpp @@ -68,7 +68,7 @@ app::AppState VoxConvert::onConstruct() { _quads = core::Var::get(cfg::VoxformatQuads, "true", core::CV_NOPERSIST, "Export as quads. If this false, triangles will be used."); _withColor = core::Var::get(cfg::VoxformatWithcolor, "true", core::CV_NOPERSIST, "Export with vertex colors"); _withTexCoords = core::Var::get(cfg::VoxformatWithtexcoords, "true", core::CV_NOPERSIST, "Export with uv coordinates of the palette image"); - _palette = core::Var::get("palette", voxel::getDefaultPaletteName(), "This is the NAME part of palette-.png or absolute png file to use (1x256)"); + _palette = core::Var::get("palette", voxel::Palette::getDefaultPaletteName(), "This is the NAME part of palette-.png or absolute png file to use (1x256)"); if (!filesystem()->registerPath("scripts/")) { Log::warn("Failed to register lua generator script path"); @@ -177,13 +177,11 @@ app::AppState VoxConvert::onInit() { Log::info("* resize volumes: - %s", (_resizeVolumes ? "true" : "false")); if (!_srcPalette) { - io::FilePtr paletteFile = filesystem()->open(_palette->strVal()); - if (!paletteFile->exists()) { - paletteFile = filesystem()->open(core::string::format("palette-%s.png", _palette->strVal().c_str())); - } - if (paletteFile->exists() && !voxel::initMaterialColors(paletteFile, io::FilePtr())) { + voxel::Palette palette; + if (!palette.load(_palette->strVal().c_str())) { Log::warn("Failed to init material colors"); } + voxel::initPalette(palette); } io::FilePtr outputFile; @@ -339,7 +337,7 @@ bool VoxConvert::handleInputFile(const core::String &infile, voxel::SceneGraph & Log::error("Failed to load palette"); return false; } - if (!voxel::initMaterialColors((const uint8_t*)palette._colors.begin(), numColors * 4, "")) { + if (!voxel::initPalette(palette)) { Log::error("Failed to initialize material colors from loaded palette"); return false; } @@ -380,7 +378,7 @@ bool VoxConvert::handleInputFile(const core::String &infile, voxel::SceneGraph & if (_exportPalette) { const core::String &paletteFile = core::string::stripExtension(infile) + ".png"; - voxel::saveMaterialColorPng(paletteFile); + voxel::getPalette().save(paletteFile.c_str()); if (!_srcPalette) { Log::info(" .. not using the input file palette"); } diff --git a/src/tools/voxedit/modules/voxedit-ui/PalettePanel.cpp b/src/tools/voxedit/modules/voxedit-ui/PalettePanel.cpp index feac7c9a2..74aef9a52 100644 --- a/src/tools/voxedit/modules/voxedit-ui/PalettePanel.cpp +++ b/src/tools/voxedit/modules/voxedit-ui/PalettePanel.cpp @@ -14,7 +14,7 @@ namespace voxedit { PalettePanel::PalettePanel() { - _currentSelectedPalette = voxel::getDefaultPaletteName(); + _currentSelectedPalette = voxel::Palette::getDefaultPaletteName(); } void PalettePanel::reloadAvailablePalettes() { @@ -28,14 +28,14 @@ void PalettePanel::reloadAvailablePalettes() { if (file.type != io::Filesystem::DirEntry::Type::file) { continue; } - const core::String& name = voxel::extractPaletteName(file.name); + const core::String& name = voxel::Palette::extractPaletteName(file.name); _availablePalettes.push_back(name); } } void PalettePanel::update(const char *title, command::CommandExecutionListener &listener) { - const voxel::MaterialColorArray &colors = voxel::getMaterialColors(); - const int maxPaletteEntries = (int)colors.size(); + voxel::Palette &palette = voxel::getPalette(); + const int maxPaletteEntries = palette.colorCount; const float height = ImGui::GetContentRegionMax().y; const ImVec2 windowSize(120.0f, height); ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver); @@ -62,7 +62,7 @@ void PalettePanel::update(const char *title, command::CommandExecutionListener & const ImVec2 v1(globalCursorPos.x + borderWidth, globalCursorPos.y + borderWidth); const ImVec2 v2(globalCursorPos.x + colorButtonSize.x, globalCursorPos.y + colorButtonSize.y); - drawList->AddRectFilled(v1, v2, ImGui::GetColorU32(colors[palIdx])); + drawList->AddRectFilled(v1, v2, palette.colors[palIdx]); const core::String &id = core::string::format("##palitem-%i", palIdx); if (ImGui::InvisibleButton(id.c_str(), colorButtonSize)) { @@ -72,13 +72,13 @@ void PalettePanel::update(const char *title, command::CommandExecutionListener & if (ImGui::BeginPopupContextItem(contextMenuId.c_str())) { const core::String &layerFromColorCmd = core::string::format("colortolayer %i", palIdx); ImGui::CommandMenuItem(ICON_FA_OBJECT_UNGROUP " Layer from color" PALETTEACTIONPOPUP, layerFromColorCmd.c_str(), true, &listener); - if (voxel::materialColorIsGlow(palIdx)) { + if (palette.hasGlow(palIdx)) { if (ImGui::MenuItem("Remove Glow")) { - voxel::materialColorRemoveGlow(palIdx); + palette.removeGlow(palIdx); } } else { if (ImGui::MenuItem("Glow")) { - voxel::materialColorSetGlow(palIdx); + palette.setGlow(palIdx); } } ImGui::EndPopup(); diff --git a/src/tools/voxedit/modules/voxedit-ui/ScriptPanel.cpp b/src/tools/voxedit/modules/voxedit-ui/ScriptPanel.cpp index 1683ea708..613a6f009 100644 --- a/src/tools/voxedit/modules/voxedit-ui/ScriptPanel.cpp +++ b/src/tools/voxedit/modules/voxedit-ui/ScriptPanel.cpp @@ -10,6 +10,7 @@ #include "ui/imgui/IMGUIEx.h" #include "ui/imgui/IconsForkAwesome.h" #include "ui/imgui/IconsFontAwesome5.h" +#include "voxel/MaterialColor.h" namespace voxedit { @@ -48,19 +49,19 @@ void ScriptPanel::update(const char *title, const char *scriptEditorTitle, ui::i const voxelgenerator::LUAParameterDescription &p = _scriptParameterDescription[i]; switch (p.type) { case voxelgenerator::LUAParameterType::ColorIndex: { - const voxel::MaterialColorArray &colors = voxel::getMaterialColors(); + const voxel::Palette &palette = voxel::getPalette(); core::String &str = _scriptParameters[i]; int val = core::string::toInt(str); - if (val >= 0 && val < (int)colors.size()) { + if (val >= 0 && val < palette.colorCount) { const float size = 20; const ImVec2 v1(ImGui::GetWindowPos().x + ImGui::GetCursorPosX(), ImGui::GetWindowPos().y + ImGui::GetCursorPosY()); const ImVec2 v2(v1.x + size, v1.y + size); ImDrawList* drawList = ImGui::GetWindowDrawList(); - drawList->AddRectFilled(v1, v2, ImGui::GetColorU32(colors[val])); + drawList->AddRectFilled(v1, v2, ImGui::GetColorU32(palette.colors[val])); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + size); } if (ImGui::InputInt(p.name.c_str(), &val)) { - if (val >= 0 && val < (int)colors.size()) { + if (val >= 0 && val < palette.colorCount) { str = core::string::toString(val); } } diff --git a/src/tools/voxedit/modules/voxedit-util/SceneManager.cpp b/src/tools/voxedit/modules/voxedit-util/SceneManager.cpp index 8de472110..ab428cb52 100644 --- a/src/tools/voxedit/modules/voxedit-util/SceneManager.cpp +++ b/src/tools/voxedit/modules/voxedit-util/SceneManager.cpp @@ -71,10 +71,11 @@ SceneManager::~SceneManager() { } bool SceneManager::loadPalette(const core::String& paletteName) { - const io::FilesystemPtr& filesystem = io::filesystem(); - const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", paletteName.c_str())); - const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", paletteName.c_str())); - if (voxel::overrideMaterialColors(paletteFile, luaFile)) { + voxel::Palette palette; + if (!palette.load(paletteName.c_str())) { + return false; + } + if (voxel::overridePalette(palette)) { core::Var::getSafe(cfg::VoxEditLastPalette)->setVal(paletteName); return true; } @@ -82,11 +83,10 @@ bool SceneManager::loadPalette(const core::String& paletteName) { } bool SceneManager::importPalette(const core::String& file) { - const core::String luaString = ""; const core::String& ext = core::string::extractExtension(file); const core::String paletteName(core::string::extractFilename(file.c_str())); const core::String& paletteFilename = core::string::format("palette-%s.png", paletteName.c_str()); - + voxel::Palette palette; bool paletteLoaded = false; for (const io::FormatDescription* desc = io::format::images(); desc->name != nullptr; ++desc) { if (ext == desc->ext) { @@ -95,12 +95,11 @@ bool SceneManager::importPalette(const core::String& file) { Log::warn("Failed to load image %s", file.c_str()); break; } - core::Array buf; - if (!voxel::createPalette(img, buf.begin(), buf.size())) { + if (!voxel::Palette::createPalette(img, palette)) { Log::warn("Failed to create palette for image %s", file.c_str()); return false; } - if (!voxel::overrideMaterialColors((const uint8_t*)buf.begin(), buf.size() * sizeof(uint32_t), luaString)) { + if (!voxel::overridePalette(palette)) { Log::warn("Failed to import palette for image %s", file.c_str()); return false; } @@ -116,20 +115,17 @@ bool SceneManager::importPalette(const core::String& file) { return false; } io::FileStream stream(palFile); - voxel::Palette pal; - if (voxelformat::loadPalette(file, stream, pal) <= 0) { + if (voxelformat::loadPalette(file, stream, palette) <= 0) { Log::warn("Failed to load palette from %s", file.c_str()); return false; } - if (!voxel::overrideMaterialColors((const uint8_t*)pal._colors.begin(), pal.size() * sizeof(uint32_t), luaString)) { + if (!voxel::overridePalette(palette)) { Log::warn("Failed to import palette for model %s", file.c_str()); return false; } } const io::FilePtr& pngFile = fs->open(paletteFilename, io::FileMode::Write); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); - if (image::Image::writePng(pngFile->name().c_str(), (const uint8_t*)materialColors.data(), (int)materialColors.size(), 1, 4)) { - fs->write(core::string::format("palette-%s.lua", paletteName.c_str()), luaString); + if (palette.save(pngFile->name().c_str())) { core::Var::getSafe(cfg::VoxEditLastPalette)->setVal(paletteName); } else { Log::warn("Failed to write image"); @@ -1492,7 +1488,9 @@ void SceneManager::construct() { const float green = core::string::toFloat(args[1]); const float blue = core::string::toFloat(args[2]); const glm::vec4 color(red / 255.0f, green / 255.0, blue / 255.0, 1.0f); - const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors(); + core::DynamicArray materialColors; + const voxel::Palette &palette = voxel::getPalette(); + palette.toVec4f(materialColors); const int index = core::Color::getClosestMatch(color, materialColors); const voxel::Voxel voxel = voxel::createVoxel(voxel::VoxelType::Generic, index); _modifier.setCursorVoxel(voxel); @@ -1679,7 +1677,7 @@ void SceneManager::construct() { core::Var::get(cfg::VoxformatQuads, "true", core::CV_NOPERSIST, "Export as quads. If this false, triangles will be used."); core::Var::get(cfg::VoxformatWithcolor, "true", core::CV_NOPERSIST, "Export with vertex colors"); core::Var::get(cfg::VoxformatWithtexcoords, "true", core::CV_NOPERSIST, "Export with uv coordinates of the palette image"); - core::Var::get("palette", voxel::getDefaultPaletteName(), "This is the NAME part of palette-.png or absolute png file to use (1x256)"); + core::Var::get("palette", voxel::Palette::getDefaultPaletteName(), "This is the NAME part of palette-.png or absolute png file to use (1x256)"); } int SceneManager::addModelChild(const core::String& name, int width, int height, int depth) { @@ -1733,12 +1731,13 @@ bool SceneManager::init() { } const char *paletteName = core::Var::getSafe(cfg::VoxEditLastPalette)->strVal().c_str(); - const io::FilesystemPtr& filesystem = io::filesystem(); - const io::FilePtr& paletteFile = filesystem->open(core::string::format("palette-%s.png", paletteName)); - const io::FilePtr& luaFile = filesystem->open(core::string::format("palette-%s.lua", paletteName)); - if (!voxel::initMaterialColors(paletteFile, luaFile)) { + voxel::Palette palette; + if (!palette.load(paletteName)) { + Log::warn("Failed to load the palette data"); + } + if (!voxel::initPalette(palette)) { Log::warn("Failed to initialize the palette data for %s, falling back to default", paletteName); - if (!voxel::initDefaultMaterialColors()) { + if (!voxel::initDefaultPalette()) { Log::error("Failed to initialize the palette data"); return false; } diff --git a/src/tools/voxedit/modules/voxedit-util/modifier/ModifierRenderer.cpp b/src/tools/voxedit/modules/voxedit-util/modifier/ModifierRenderer.cpp index 409b4c715..369912760 100644 --- a/src/tools/voxedit/modules/voxedit-util/modifier/ModifierRenderer.cpp +++ b/src/tools/voxedit/modules/voxedit-util/modifier/ModifierRenderer.cpp @@ -33,7 +33,9 @@ void ModifierRenderer::shutdown() { void ModifierRenderer::updateCursor(const voxel::Voxel& voxel) { _shapeBuilder.clear(); - _shapeBuilder.setColor(core::Color::alpha(core::Color::darker(voxel::getMaterialColor(voxel)), 0.6f)); + const voxel::Palette &palette = voxel::getPalette(); + const glm::vec4& color = core::Color::fromRGBA(palette.colors[voxel.getColor()]); + _shapeBuilder.setColor(core::Color::alpha(core::Color::darker(color), 0.6f)); _shapeBuilder.cube(glm::vec3(-0.01f), glm::vec3(1.01f)); _shapeRenderer.createOrUpdate(_voxelCursorMesh, _shapeBuilder); }