VOXEL: started to refactor the palette handling
export the palette image for ply mesh exportsmaster
parent
0a9a5ee7df
commit
c29f5d3548
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
};
|
||||
|
||||
bool onInitApp() override {
|
||||
if (!voxel::initDefaultMaterialColors()) {
|
||||
if (!voxel::initDefaultPalette()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "core/collection/Array.h"
|
||||
|
||||
namespace voxel {
|
||||
struct Palette;
|
||||
class Palette;
|
||||
}
|
||||
|
||||
namespace voxelformat {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -42,7 +42,7 @@ protected:
|
|||
public:
|
||||
void SetUp() override {
|
||||
Super::SetUp();
|
||||
voxel::initDefaultMaterialColors();
|
||||
voxel::initDefaultPalette();
|
||||
_volume = new voxel::RawVolume(_region);
|
||||
}
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
}
|
||||
|
||||
bool onInitApp() override {
|
||||
voxel::initDefaultMaterialColors();
|
||||
voxel::initDefaultPalette();
|
||||
_volumeCache = std::make_shared<voxelformat::VolumeCache>();
|
||||
return _volumeCache->init();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue