VOXEL: started to refactor the palette handling

export the palette image for ply mesh exports
master
Martin Gerhardy 2022-02-28 19:03:15 +01:00
parent 0a9a5ee7df
commit c29f5d3548
66 changed files with 651 additions and 674 deletions

View File

@ -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;
}

View File

@ -37,8 +37,14 @@ bool AnimationRenderer::init() {
return false;
}
const voxel::Palette &palette = voxel::getPalette();
core::DynamicArray<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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;

View File

@ -335,7 +335,7 @@ bool ServerLoop::init() {
r->registerHandler(network::ClientMsgType::VarUpdate, std::make_shared<VarUpdateHandler>());
Log::info("Init material");
if (!voxel::initDefaultMaterialColors()) {
if (!voxel::initDefaultPalette()) {
Log::error("Failed to initialize the palette data");
return false;
}

View File

@ -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<EntityStorage>(_testApp->eventBus());
protocolHandlerRegistry = core::make_shared<network::ProtocolHandlerRegistry>();
network = std::make_shared<network::ServerNetwork>(protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());

View File

@ -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<EntityStorage>(_testApp->eventBus());
ASSERT_TRUE(_entityStorage->init());
_protocolHandlerRegistry = core::make_shared<network::ProtocolHandlerRegistry>();

View File

@ -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<EntityStorage>(_testApp->eventBus());
ASSERT_TRUE(_entityStorage->init());
_protocolHandlerRegistry = core::make_shared<network::ProtocolHandlerRegistry>();

View File

@ -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<EntityStorage>(_testApp->eventBus());
_protocolHandlerRegistry = core::make_shared<network::ProtocolHandlerRegistry>();
_network = std::make_shared<network::ServerNetwork>(_protocolHandlerRegistry, _testApp->eventBus(), _testApp->metric());

View File

@ -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<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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<ClientEntity*>& entiti
_chrShader.setFogrange(_fogRange);
_chrShader.setFocuspos(_focusPos);
_chrShader.setLightdir(shadow.sunDirection());
_chrShader.setTime(_seconds);
_chrShader.setTime((float)_seconds);
_chrShader.setClipplane(clipPlane);
_chrShader.setViewprojection(viewProjectionMatrix);

View File

@ -28,7 +28,7 @@ protected:
voxelformat::VolumeCachePtr _volumeCache;
bool onInitApp() override {
voxel::initDefaultMaterialColors();
voxel::initDefaultPalette();
_volumeCache = std::make_shared<voxelformat::VolumeCache>();
if (!_volumeCache->init()) {
return false;

View File

@ -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;
}

View File

@ -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

View File

@ -34,58 +34,37 @@ static MaterialColor* luamaterial_getmaterialcolor(lua_State*s) {
class MaterialColor {
private:
MaterialColorArray _materialColors;
MaterialColorArray _glowColors;
core::Map<VoxelType, MaterialColorIndices, 8, EnumClassHash> _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<uint32_t, 256> 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<uint32_t, bool, 64> 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);
}
}

View File

@ -6,12 +6,6 @@
#include "voxel/Voxel.h"
#include "voxel/Palette.h"
#include "io/File.h"
#include "image/Image.h"
#include <glm/vec4.hpp>
#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<glm::vec4> MaterialColorArray;
typedef core::DynamicArray<uint8_t> 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<uint8_t> 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);

View File

@ -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<uint32_t, bool, 64> 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<glm::vec4> &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<glm::vec4> &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

View File

@ -6,19 +6,54 @@
#include "core/String.h"
#include "core/collection/Array.h"
#include "core/collection/DynamicArray.h"
#include "image/Image.h"
#include <stdint.h>
#include <glm/vec4.hpp>
namespace voxel {
struct Palette {
core::Array<uint32_t, 256> _colors;
core::Array<uint32_t, 256> _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<glm::vec4> &rgba) const;
void glowToVec4f(core::DynamicArray<glm::vec4> &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);
};
}
} // namespace voxel

View File

@ -41,7 +41,7 @@ public:
};
bool onInitApp() override {
if (!voxel::initDefaultMaterialColors()) {
if (!voxel::initDefaultPalette()) {
return false;
}
return true;

View File

@ -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();
}
};
}

View File

@ -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<glm::vec4> 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) {

View File

@ -27,7 +27,6 @@
#include "voxel/RawVolume.h"
#include "voxel/CubicSurfaceExtractor.h"
#include "voxel/IsQuadNeeded.h"
#include "voxel/MaterialColor.h"
#include <glm/common.hpp>
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;

View File

@ -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;

View File

@ -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))

View File

@ -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<glm::vec4> 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;
}

View File

@ -28,10 +28,8 @@ class Mesh;
class Format {
protected:
core::Array<uint8_t, 256> _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

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}

View File

@ -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<i
core::DynamicArray<uint8_t> palette;
palette.reserve(subdivided.size());
const voxel::MaterialColorArray& materialColors = voxel::getMaterialColors();
const voxel::Palette &pal = voxel::getPalette();
core::DynamicArray<glm::vec4> materialColors;
pal.toVec4f(materialColors);
for (const Tri &tri : subdivided) {
const glm::vec2 &uv = tri.centerUV();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::ScopedPtr<RawVolume> 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);

View File

@ -12,7 +12,7 @@
#include "core/collection/Array.h"
namespace voxel {
struct Palette;
class Palette;
}
namespace voxelformat {

View File

@ -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<glm::vec4> 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;

View File

@ -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);
}

View File

@ -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<glm::vec4> 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<glm::vec4> colors;
palette.toVec4f(colors);
const core::DynamicArray<glm::vec4> 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;
}

View File

@ -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);

View File

@ -42,7 +42,7 @@ protected:
public:
void SetUp() override {
Super::SetUp();
voxel::initDefaultMaterialColors();
voxel::initDefaultPalette();
_volume = new voxel::RawVolume(_region);
}

View File

@ -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})

View File

@ -54,8 +54,14 @@ bool MeshRenderer::init() {
mesh.buffer.addAttribute(attributeInfo);
}
const voxel::Palette &palette = voxel::getPalette();
core::DynamicArray<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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;

View File

@ -109,8 +109,14 @@ bool RawVolumeRenderer::init() {
}
}
const voxel::Palette &palette = voxel::getPalette();
core::DynamicArray<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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();

View File

@ -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<uint8_t> 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));
}
}

View File

@ -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<glm::vec4> 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) {

View File

@ -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<glm::vec4> 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);
}

View File

@ -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));
}
}

View File

@ -21,7 +21,7 @@ public:
}
bool onInitApp() override {
voxel::initDefaultMaterialColors();
voxel::initDefaultPalette();
_volumeCache = std::make_shared<voxelformat::VolumeCache>();
return _volumeCache->init();
}

View File

@ -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);
}

View File

@ -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<glm::vec4>());
}
_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<decltype(waterPlaneVecs[0])>::type::length());
const int elements = (int)_waterBuffer.elements(_waterVbo, core::remove_reference<decltype(waterPlaneVecs[0])>::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<glm::vec4> materialColors;
palette.toVec4f(materialColors);
core::DynamicArray<glm::vec4> 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));

View File

@ -150,7 +150,7 @@ app::AppState TestAnimation::onInit() {
camera().setWorldPosition(glm::vec3(10.0f, 5.0f, 10.0f));
camera().lookAt(glm::zero<glm::vec3>());
if (!voxel::initDefaultMaterialColors()) {
if (!voxel::initDefaultPalette()) {
Log::error("Failed to initialize the default material colors");
return app::AppState::InitFailure;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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-<NAME>.png or absolute png file to use (1x256)");
_palette = core::Var::get("palette", voxel::Palette::getDefaultPaletteName(), "This is the NAME part of palette-<NAME>.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");
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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<uint32_t, 256> 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<glm::vec4> 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-<NAME>.png or absolute png file to use (1x256)");
core::Var::get("palette", voxel::Palette::getDefaultPaletteName(), "This is the NAME part of palette-<NAME>.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;
}

View File

@ -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);
}