From 1ab857e00851ee270408072c84c8f963bb3c8d21 Mon Sep 17 00:00:00 2001 From: James Lambert Date: Sat, 5 Aug 2023 13:07:08 -0600 Subject: [PATCH] Bring changes over from work done for n64 game jam --- skelatool64/lua/sk_definition_writer.lua | 33 ++++ skelatool64/lua/sk_math.lua | 57 +++++++ skelatool64/src/definitions/DataChunk.cpp | 50 +++++- skelatool64/src/definitions/DataChunk.h | 13 +- .../src/lua_generator/LuaDefinitionWriter.cpp | 35 +++- skelatool64/src/lua_generator/LuaMesh.cpp | 161 +++++++++++++++++- .../src/lua_generator/LuaTransform.cpp | 64 +++++-- skelatool64/src/materials/CImgu8.cpp | 10 ++ skelatool64/src/materials/CImgu8.h | 23 +++ .../src/materials/TextureDefinition.cpp | 76 +++++++-- skelatool64/src/materials/TextureDefinition.h | 19 +++ 11 files changed, 499 insertions(+), 42 deletions(-) create mode 100644 skelatool64/src/materials/CImgu8.cpp create mode 100644 skelatool64/src/materials/CImgu8.h diff --git a/skelatool64/lua/sk_definition_writer.lua b/skelatool64/lua/sk_definition_writer.lua index 8b7bb5b..9b6e751 100644 --- a/skelatool64/lua/sk_definition_writer.lua +++ b/skelatool64/lua/sk_definition_writer.lua @@ -75,6 +75,39 @@ end exports.is_raw = is_raw +--- @table CommentType +local CommentType = {} + +local function comment(value) + return setmetatable({ value = value}, CommentType) +end + +CommentType.__index = CommentType; + +function CommentType.__tostring(comment) + return 'comment(' .. comment.value .. ')' +end + +--- renders a string as a comment +---@function comment +---@tparam string value +---@treturn CommentType result +exports.comment = comment + +--- returns true if value is a CommentType +---@function is_comment +---@tparam any value +---@treturn boolean result +local function is_comment(value) + return getmetatable(value) == CommentType +end + +exports.is_comment = is_comment + +--- alias for raw("'\n") +--- @table newline +exports.newline = raw('\n') + --- alias for raw("NULL") --- @table null_value local null_value = raw("NULL") diff --git a/skelatool64/lua/sk_math.lua b/skelatool64/lua/sk_math.lua index 294b297..44f1c9b 100644 --- a/skelatool64/lua/sk_math.lua +++ b/skelatool64/lua/sk_math.lua @@ -4,6 +4,7 @@ local Vector3 = {} local Box3 = {} local Quaternion = {} local Color4 = {} +local Plane3 = {} --- creates a new 3d vector --- @function vector3 @@ -69,6 +70,32 @@ local function isQuaternion(obj) return type(obj) == 'table' and type(obj.x) == 'number' and type(obj.y) == 'number' and type(obj.z) == 'number' and type(obj.w) == 'number' end +--- creates a new Plane3 +--- @function plane3 +--- @tparam Vector3 normal the normal of the plane +--- @tparam number d the distance to the origin +--- @treturn Plane3 +local function plane3(normal, d) + return setmetatable({ normal = normal, d = d }, Plane3) +end + +--- creates a new Plane3 using a point and a normal +--- @function plane3 +--- @tparam Vector3 normal the normal of the plane +--- @tparam Vector3 point a point on the plane +--- @treturn Plane3 +local function plane3_with_point(normal, point) + if not isVector3(normal) then + error('plane3_with_point expected vector as first operand got ' .. type(b), 2) + end + + if not isVector3(point) then + error('plane3_with_point expected vector as second operand got ' .. type(b), 2) + end + + return setmetatable({ normal = normal, d = -normal:dot(point) }, Plane3) +end + --- @type Vector3 --- @tfield number x --- @tfield number y @@ -136,6 +163,15 @@ function Vector3.__sub(a, b) return vector3(a.x - b.x, a.y - b.y, a.z - b.z) end +--- @function __unm +--- @tparam number|Vector3 b +--- @treturn Vector3 +function Vector3.__unm(a) + return vector3(-a.x, -a.y, -a.z) +end + + + --- @function __mul --- @tparam number|Vector3 b --- @treturn Vector3 @@ -228,6 +264,9 @@ end --- @tparam Vector3 b --- @treturn number function Vector3.dot(a, b) + if not isVector3(b) then + error('Vector3.dot expected another vector as second operand', 2) + end return a.x * b.x + a.y * b.y + a.z * b.z end @@ -248,6 +287,12 @@ end --- @tparam Vector3 b --- @treturn Vector3 function Vector3.lerp(a, b, lerp) + if not isVector3(b) then + error('Vector3.lerp expected another vector as second operand', 2) + end + if type(lerp) ~= 'number' then + error('Vector3.lerp expected number as third operand', 2) + end return a * (1 - lerp) + b * lerp end @@ -543,6 +588,15 @@ function Color4.lerp(a, b, lerp) return a * (1 - lerp) + b * lerp end +--- @type Plane3 +--- @tfield Vector3 normal +--- @tfield number d +Plane3.__index = Plane3; + +function Plane3.distance_to_point(plane, point) + return plane.normal:dot(point) + plane.d +end + return { vector3 = vector3, Vector3 = Vector3, @@ -555,4 +609,7 @@ return { isQuaternion = isQuaternion, color4 = color4, isColor4 = isColor4, + plane3 = plane3, + plane3_with_point = plane3_with_point, + Plane3 = Plane3, } \ No newline at end of file diff --git a/skelatool64/src/definitions/DataChunk.cpp b/skelatool64/src/definitions/DataChunk.cpp index 21d2baa..89eea82 100644 --- a/skelatool64/src/definitions/DataChunk.cpp +++ b/skelatool64/src/definitions/DataChunk.cpp @@ -72,7 +72,7 @@ int StructureEntryDataChunk::CalculateEstimatedLength() { return mName.length() + 4 + mEntry->GetEstimatedLength(); } -StructureDataChunk::StructureDataChunk(): DataChunk() {} +StructureDataChunk::StructureDataChunk(): DataChunk(), mHasNewlineHints(false) {} StructureDataChunk::StructureDataChunk(const aiVector3D& vector) : StructureDataChunk() { AddPrimitive(vector.x); @@ -96,6 +96,10 @@ StructureDataChunk::StructureDataChunk(const aiAABB& bb) : StructureDataChunk() void StructureDataChunk::Add(std::unique_ptr entry) { + if (dynamic_cast(entry.get()) != nullptr) { + mHasNewlineHints = true; + } + mChildren.push_back(std::move(entry)); } @@ -106,13 +110,18 @@ void StructureDataChunk::Add(const std::string& name, std::unique_ptr ))); } +void StructureDataChunk::AddNewlineHint() { + mHasNewlineHints = true; + mChildren.push_back(std::unique_ptr(new NewlineHintChunk())); +} + #define MAX_CHARS_PER_LINE 80 #define SPACES_PER_INDENT 4 bool StructureDataChunk::Output(std::ostream& output, int indentLevel, int linePrefix) { output << '{'; - OutputChildren(mChildren, output, indentLevel, linePrefix + GetEstimatedLength(), true); + OutputChildren(mChildren, output, indentLevel, linePrefix + GetEstimatedLength(), true, !mHasNewlineHints); output << '}'; return true; @@ -138,7 +147,7 @@ void StructureDataChunk::OutputIndent(std::ostream& output, int indentLevel) { } } -void StructureDataChunk::OutputChildren(std::vector>& children, std::ostream& output, int indentLevel, int totalLength, bool trailingComma) { +void StructureDataChunk::OutputChildren(std::vector>& children, std::ostream& output, int indentLevel, int totalLength, bool trailingComma, bool includeNewlines) { bool needsComma = false; if (totalLength < MAX_CHARS_PER_LINE) { @@ -147,17 +156,33 @@ void StructureDataChunk::OutputChildren(std::vector>& output << ", "; } + if (dynamic_cast(children[i].get()) != nullptr) { + needsComma = false; + continue; + } + needsComma = children[i]->Output(output, indentLevel, 0); } } else { output << '\n'; + bool needsIndent = true; ++indentLevel; for (size_t i = 0; i < children.size(); ++i) { - OutputIndent(output, indentLevel); - if (children[i]->Output(output, indentLevel, indentLevel * SPACES_PER_INDENT) && (i < children.size() - 1 || trailingComma)) { - output << ",\n"; + if (needsIndent) { + OutputIndent(output, indentLevel); + needsIndent = false; } else { + output << ' '; + } + if (children[i]->Output(output, indentLevel, indentLevel * SPACES_PER_INDENT) && (i < children.size() - 1 || trailingComma)) { + output << ","; + } + + if (includeNewlines) { output << "\n"; + needsIndent = true; + } else if (dynamic_cast(children[i].get()) != nullptr) { + needsIndent = true; } } --indentLevel; @@ -176,7 +201,7 @@ void MacroDataChunk::Add(std::unique_ptr entry) { bool MacroDataChunk::Output(std::ostream& output, int indentLevel, int linePrefix) { output << mMacroName << '('; - StructureDataChunk::OutputChildren(mParameters, output, indentLevel, mSingleLine ? 0 : linePrefix + GetEstimatedLength(), false); + StructureDataChunk::OutputChildren(mParameters, output, indentLevel, mSingleLine ? 0 : linePrefix + GetEstimatedLength(), false, true); output << ')'; return true; @@ -206,4 +231,15 @@ bool CommentDataChunk::Output(std::ostream& output, int indentLevel, int linePre int CommentDataChunk::CalculateEstimatedLength() { return 6 + mComment.length(); +} + +NewlineHintChunk::NewlineHintChunk() : DataChunk() {} + +bool NewlineHintChunk::Output(std::ostream& output, int indentLevel, int linePrefix) { + output << "\n"; + return false; +} + +int NewlineHintChunk::CalculateEstimatedLength() { + return 0; } \ No newline at end of file diff --git a/skelatool64/src/definitions/DataChunk.h b/skelatool64/src/definitions/DataChunk.h index 8eef937..4178410 100644 --- a/skelatool64/src/definitions/DataChunk.h +++ b/skelatool64/src/definitions/DataChunk.h @@ -96,14 +96,17 @@ public: ))); } + void AddNewlineHint(); + virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); static void OutputIndent(std::ostream& output, int indentLevel); - static void OutputChildren(std::vector>& children, std::ostream& output, int indentLevel, int totalLength, bool trailingComma); + static void OutputChildren(std::vector>& children, std::ostream& output, int indentLevel, int totalLength, bool trailingComma, bool includeNewlines); protected: virtual int CalculateEstimatedLength(); private: std::vector> mChildren; + bool mHasNewlineHints; }; class MacroDataChunk : public DataChunk { @@ -139,4 +142,12 @@ private: std::string mComment; }; +class NewlineHintChunk : public DataChunk { +public: + NewlineHintChunk(); + virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); +protected: + virtual int CalculateEstimatedLength(); +}; + #endif \ No newline at end of file diff --git a/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp b/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp index af00146..664a1d8 100644 --- a/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp +++ b/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp @@ -88,6 +88,7 @@ std::unique_ptr buildDataChunk(lua_State* L) { } if (type == LUA_TTABLE) { + // check if this is a raw value lua_getglobal(L, "require"); lua_pushstring(L, "sk_definition_writer"); lua_call(L, 1, 1); @@ -103,12 +104,22 @@ std::unique_ptr buildDataChunk(lua_State* L) { // pop the bool lua_pop(L, 1); lua_getfield(L, -1, "value"); - std::unique_ptr result(new PrimitiveDataChunk(lua_tostring(L, -1))); + + const char* buffer = lua_tostring(L, -1); + + if (strcmp(buffer, "\n") == 0) { + std::unique_ptr result(new NewlineHintChunk()); + lua_pop(L, 1); + return result; + } + + std::unique_ptr result(new PrimitiveDataChunk(buffer)); lua_pop(L, 1); return result; } lua_pop(L, 1); + // check if ths is a macro value lua_getglobal(L, "require"); lua_pushstring(L, "sk_definition_writer"); lua_call(L, 1, 1); @@ -127,6 +138,28 @@ std::unique_ptr buildDataChunk(lua_State* L) { } lua_pop(L, 1); + // check if this is a comment + lua_getglobal(L, "require"); + lua_pushstring(L, "sk_definition_writer"); + lua_call(L, 1, 1); + + lua_getfield(L, -1, "is_comment"); + // remove sk_definition_writer module + lua_remove(L, -2); + + lua_pushnil(L); + lua_copy(L, -3, -1); + lua_call(L, 1, 1); + if (lua_toboolean(L, -1)) { + // pop the bool + lua_pop(L, 1); + lua_getfield(L, -1, "value"); + std::unique_ptr result(new CommentDataChunk(lua_tostring(L, -1))); + lua_pop(L, 1); + return result; + } + lua_pop(L, 1); + return buildStructureChunk(L); } diff --git a/skelatool64/src/lua_generator/LuaMesh.cpp b/skelatool64/src/lua_generator/LuaMesh.cpp index 3585cf8..d390b92 100644 --- a/skelatool64/src/lua_generator/LuaMesh.cpp +++ b/skelatool64/src/lua_generator/LuaMesh.cpp @@ -2,6 +2,8 @@ #include "LuaMesh.h" +#include + #include "../definition_generator/MeshDefinitionGenerator.h" #include "../definition_generator/MaterialGenerator.h" #include "./LuaBasicTypes.h" @@ -119,10 +121,135 @@ void toLuaLazyArray(lua_State* L, T* vertices, unsigned count) { lua_setmetatable(L, -2); } +void textureFromLua(lua_State* L, std::shared_ptr& texture) { + lua_getfield(L, -1, "ptr"); + + fromLua(L, texture); + lua_pop(L, 1); +} + +void textureToLua(lua_State* L, std::shared_ptr texture); + +int luaTextureCrop(lua_State* L) { + int x = luaL_checkinteger(L, 2); + int y = luaL_checkinteger(L, 3); + int w = luaL_checkinteger(L, 4); + int h = luaL_checkinteger(L, 5); + + lua_settop(L, 1); + + std::shared_ptr texture; + textureFromLua(L, texture); + + std::shared_ptr result = texture->Crop(x, y, w, h); + textureToLua(L, result); + return 1; +} + +int luaTextureResize(lua_State* L) { + int w = luaL_checkinteger(L, 2); + int h = luaL_checkinteger(L, 3); + + lua_settop(L, 1); + + std::shared_ptr texture; + textureFromLua(L, texture); + + std::shared_ptr result = texture->Resize(w, h); + textureToLua(L, result); + + return 1; +} + +int luaTextureData(lua_State* L) { + lua_settop(L, 1); + + if (lua_isnil(L, 1)) { + lua_pushstring(L, "call to get_data had nil as the first paramter"); + lua_error(L); + return 0; + } + + std::shared_ptr texture; + textureFromLua(L, texture); + + if (!texture) { + return 0; + } + + const std::vector& data = texture->GetData(); + + lua_createtable(L, data.size(), 0); + + for (unsigned i = 0; i < data.size(); ++i) { + std::ostringstream stream; + stream << "0x" << std::hex << std::setw(16) << std::setfill('0') << data[i]; + luaLoadModuleFunction(L, "sk_definition_writer", "raw"); + lua_pushstring(L, stream.str().c_str()); + lua_call(L, 1, 1); + lua_seti(L, -2, i + 1); + } + + return 1; +} + +/** +@table Texture +@tfield number width +@tfield number height +@tfield string name +@tfield function get_data +@tfield function crop +*/ + +void textureToLua(lua_State* L, std::shared_ptr texture) { + if (!texture) { + lua_pushnil(L); + return; + } + + lua_createtable(L, 0, 0); + + luaLoadModuleFunction(L, "sk_mesh", "Texture"); + lua_setmetatable(L, -2); + + toLua(L, texture); + lua_setfield(L, -2, "ptr"); + + lua_pushinteger(L, texture->Width()); + lua_setfield(L, -2, "width"); + + lua_pushinteger(L, texture->Height()); + lua_setfield(L, -2, "height"); + + lua_pushstring(L, texture->Name().c_str()); + lua_setfield(L, -2, "name"); +} + +/** +@table TileState +@tfield string format +@tfield string size +@tfield Texture texture +*/ +void toLua(lua_State* L, TileState& tileState) { + lua_createtable(L, 0, 0); + + lua_pushstring(L, nameForImageFormat(tileState.format)); + lua_setfield(L, -2, "format"); + + lua_pushstring(L, nameForImageSize(tileState.size)); + lua_setfield(L, -2, "size"); + + textureToLua(L, tileState.texture); + lua_setfield(L, -2, "texture"); +} + /*** @table Material @tfield string name @tfield string macro_name + @tfield {...TileState} tiles */ void toLua(lua_State* L, Material* material) { if (!material) { @@ -130,7 +257,7 @@ void toLua(lua_State* L, Material* material) { return; } - lua_createtable(L, 1, 0); + lua_createtable(L, 0, 0); luaLoadModuleFunction(L, "sk_mesh", "Material"); lua_setmetatable(L, -2); @@ -148,6 +275,13 @@ void toLua(lua_State* L, Material* material) { } lua_setfield(L, -2, "properties"); + lua_createtable(L, MAX_TILE_COUNT, 0); + for (int i = 0; i < MAX_TILE_COUNT; ++i) { + toLua(L, material->mState.tiles[i]); + lua_seti(L, -2, i + 1); + } + lua_setfield(L, -2, "tiles"); + lua_pushlightuserdata(L, material); lua_setfield(L, -2, "ptr"); } @@ -195,6 +329,7 @@ int luaTransformMesh(lua_State* L) { @tfield sk_transform.Transform transform @tfield {sk_math.Vector3,...} vertices @tfield {sk_math.Vector3,...} normals + @tfield {sk_math.Vector3,...} uv @tfield {{number,number,number},...} faces @tfield Material material */ @@ -223,6 +358,13 @@ void meshToLua(lua_State* L, std::shared_ptr mesh) { toLuaLazyArray(L, mesh->mMesh->mNormals, mesh->mMesh->mNumVertices); lua_setfield(L, -2, "normals"); + if (mesh->mMesh->mTextureCoords[0]) { + toLuaLazyArray(L, mesh->mMesh->mTextureCoords[0], mesh->mMesh->mNumVertices); + } else { + lua_pushnil(L); + } + lua_setfield(L, -2, "uv"); + toLua(L, mesh->mMesh->mFaces, mesh->mMesh->mNumFaces); lua_setfield(L, -2, "faces"); @@ -449,6 +591,23 @@ int buildMeshModule(lua_State* L) { lua_newtable(L); lua_setfield(L, -2, "Mesh"); + lua_newtable(L); + + lua_pushcfunction(L, luaTextureCrop); + lua_setfield(L, -2, "crop"); + + lua_pushcfunction(L, luaTextureResize); + lua_setfield(L, -2, "resize"); + + lua_pushcfunction(L, luaTextureData); + lua_setfield(L, -2, "get_data"); + + lua_pushnil(L); + lua_copy(L, -2, -1); + lua_setfield(L, -2, "__index"); + + lua_setfield(L, -2, "Texture"); + lua_pushlightuserdata(L, scene); lua_pushlightuserdata(L, fileDefinition); lua_pushlightuserdata(L, settings); diff --git a/skelatool64/src/lua_generator/LuaTransform.cpp b/skelatool64/src/lua_generator/LuaTransform.cpp index 2c65590..3925827 100644 --- a/skelatool64/src/lua_generator/LuaTransform.cpp +++ b/skelatool64/src/lua_generator/LuaTransform.cpp @@ -43,6 +43,39 @@ int luaTransformFromPosRotationScale(lua_State* L) { return 1; } +/*** + @function from_pos_rot_scale + @tparam {...number} data + @treturn Transform + */ +int luaTransformFromArray(lua_State* L) { + lua_type(L, 1); + + if (lua_isnil(L, 1)) { + return 0; + } + + double value[16]; + + for (int i = 0; i < 16; ++i) { + if (lua_geti(L, 1, i + 1) == LUA_TNUMBER) { + value[i] = lua_tonumber(L, -1); + } else { + value[i] = 0.0; + } + lua_pop(L, 1); + } + + aiMatrix4x4 fullTransform( + value[0], value[1], value[2], value[3], + value[4], value[5], value[6], value[7], + value[8], value[9], value[10], value[11], + value[12], value[13], value[14], value[15] + ); + toLua(L, fullTransform); + return 1; +} + /*** A 4x4 matrix transform @type Transform @@ -126,7 +159,7 @@ int luaTransformIndex(lua_State* L) { int row = lua_tointeger(L, -2); int col = lua_tointeger(L, -1); - lua_pushnumber(L, (*mtx)[row][col]); + lua_pushnumber(L, (*mtx)[row - 1][col - 1]); return 1; } } @@ -189,23 +222,23 @@ int luaTransformToString(lua_State* L) { std::ostringstream result; result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->a1 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->b1 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->c1 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->d1 << " |" << std::endl; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->a2 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->a3 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->a4 << " |" << std::endl; - result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->a2 << " "; + result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->b1 << " "; result << std::setprecision(5) << std::fixed << std::setw(5) << a->b2 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->c2 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->d2 << " |" << std::endl; - - result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->a3 << " "; result << std::setprecision(5) << std::fixed << std::setw(5) << a->b3 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->c3 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->d3 << " |" << std::endl; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->b4 << " |" << std::endl; - result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->a4 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->b4 << " "; - result << std::setprecision(5) << std::fixed << std::setw(5) << a->c4 << " "; + result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->c1 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->c2 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->c3 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->c4 << " |" << std::endl; + + result << "| " << std::setprecision(5) << std::fixed << std::setw(5) << a->d1 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->d2 << " "; + result << std::setprecision(5) << std::fixed << std::setw(5) << a->d3 << " "; result << std::setprecision(5) << std::fixed << std::setw(5) << a->d4 << " |" << std::endl; toLua(L, result.str()); @@ -218,6 +251,9 @@ int buildTransformModule(lua_State* L) { lua_pushcfunction(L, luaTransformFromPosRotationScale); lua_setfield(L, -2, "from_pos_rot_scale"); + lua_pushcfunction(L, luaTransformFromArray); + lua_setfield(L, -2, "from_array"); + return 1; } diff --git a/skelatool64/src/materials/CImgu8.cpp b/skelatool64/src/materials/CImgu8.cpp new file mode 100644 index 0000000..52ed2a9 --- /dev/null +++ b/skelatool64/src/materials/CImgu8.cpp @@ -0,0 +1,10 @@ +#include "CImgu8.h" + + +CImgu8::CImgu8(const std::string& filename) : mImg(filename.c_str()) { + +} + +CImgu8::CImgu8(const cimg_library_suffixed::CImg& img) : mImg(img) { + +} \ No newline at end of file diff --git a/skelatool64/src/materials/CImgu8.h b/skelatool64/src/materials/CImgu8.h new file mode 100644 index 0000000..0948c1d --- /dev/null +++ b/skelatool64/src/materials/CImgu8.h @@ -0,0 +1,23 @@ +#ifndef __CIMG_U8_H__ +#define __CIMG_U8_H__ + +#define cimg_display 0 +#define cimg_use_png +#define cimg_use_tiff +// This is a massive header file and I don't +// want it to drive my compile times up by being +// included in every file. That is whey I created +// The CImgu8 class. You should not include this header +// file from other header files +#include "../../cimg/CImg.h" + +#include + +class CImgu8 { +public: + CImgu8(const std::string& filename); + CImgu8(const cimg_library_suffixed::CImg& img); + cimg_library_suffixed::CImg mImg; +}; + +#endif \ No newline at end of file diff --git a/skelatool64/src/materials/TextureDefinition.cpp b/skelatool64/src/materials/TextureDefinition.cpp index 2f0b9b3..fc8a4b9 100644 --- a/skelatool64/src/materials/TextureDefinition.cpp +++ b/skelatool64/src/materials/TextureDefinition.cpp @@ -1,7 +1,3 @@ -#define cimg_display 0 -#define cimg_use_png -#define cimg_use_tiff -#include "../../cimg/CImg.h" #include "TextureDefinition.h" #include "../FileUtils.h" @@ -13,6 +9,8 @@ #include #include +#include "CImgu8.h" + DataChunkStream::DataChunkStream() : mCurrentBufferPos(0), mCurrentBuffer(0) {} @@ -474,40 +472,56 @@ unsigned PalleteDefinition::ColorCount() const { } TextureDefinition::TextureDefinition(const std::string& filename, G_IM_FMT fmt, G_IM_SIZ siz, TextureDefinitionEffect effects, std::shared_ptr pallete) : - mName(getBaseName(replaceExtension(filename, "")) + "_" + gFormatShortName[(int)fmt] + "_" + gSizeName[(int)siz]), - mFmt(fmt), - mSiz(siz), - mPallete(pallete), - mEffects(effects) { + TextureDefinition( + new CImgu8(filename), + getBaseName(replaceExtension(filename, "")) + "_" + gFormatShortName[(int)fmt] + "_" + gSizeName[(int)siz], + fmt, + siz, + pallete, + effects + ) { +} - cimg_library_suffixed::CImg imageData(filename.c_str()); +TextureDefinition::~TextureDefinition() { + delete mImg; + mImg = NULL; +} +TextureDefinition::TextureDefinition( + CImgu8* img, + const std::string& name, + G_IM_FMT fmt, + G_IM_SIZ siz, + std::shared_ptr pallete, + TextureDefinitionEffect effects +): mImg(std::move(img)), mName(name), mFmt(fmt), mSiz(siz), mWidth(img->mImg.width()), mHeight(img->mImg.height()), + mPallete(pallete), mEffects(effects) { if (HasEffect(TextureDefinitionEffect::TwoToneGrayscale)) { - applyTwoToneEffect(imageData, mTwoToneMax, mTwoToneMin); + applyTwoToneEffect(mImg->mImg, mTwoToneMax, mTwoToneMin); } if (HasEffect(TextureDefinitionEffect::NormalMap)) { - calculateNormalMap(imageData); + calculateNormalMap(mImg->mImg); } if (HasEffect(TextureDefinitionEffect::Invert)) { - invertImage(imageData); + invertImage(mImg->mImg); } if (HasEffect(TextureDefinitionEffect::SelectR) || HasEffect(TextureDefinitionEffect::SelectG) || HasEffect(TextureDefinitionEffect::SelectB)) { - selectChannel(imageData, mEffects); + selectChannel(mImg->mImg, mEffects); } - mWidth = imageData.width(); - mHeight = imageData.height(); + mWidth = mImg->mImg.width(); + mHeight = mImg->mImg.height(); DataChunkStream dataStream; for (int y = 0; y < mHeight; ++y) { for (int x = 0; x < mWidth; ++x) { - convertPixel(imageData, x, y, dataStream, fmt, siz, pallete); + convertPixel(mImg->mImg, x, y, dataStream, fmt, siz, pallete); } } @@ -520,8 +534,8 @@ TextureDefinition::TextureDefinition(const std::string& filename, G_IM_FMT fmt, mFmt = G_IM_FMT::G_IM_FMT_CI; mSiz = pallete->ColorCount() <= 16 ? G_IM_SIZ::G_IM_SIZ_4b : G_IM_SIZ::G_IM_SIZ_8b; } + } - bool isGrayscale(cimg_library_suffixed::CImg& input, int x, int y) { switch (input.spectrum()) { case 1: @@ -668,6 +682,10 @@ bool TextureDefinition::GetLineForTile(int& line) const { return bitLine % 64 == 0; } +const std::vector& TextureDefinition::GetData() const { + return mData; +} + const std::string& TextureDefinition::Name() const { return mName; } @@ -686,4 +704,26 @@ PixelRGBAu8 TextureDefinition::GetTwoToneMax() const { std::shared_ptr TextureDefinition::GetPallete() const { return mPallete; +} + +std::shared_ptr TextureDefinition::Crop(int x, int y, int w, int h) const { + return std::shared_ptr(new TextureDefinition( + new CImgu8(mImg->mImg.get_crop(x, y, x + w - 1, y + h - 1)), + mName, + mFmt, + mSiz, + mPallete, + mEffects + )); +} + +std::shared_ptr TextureDefinition::Resize(int w, int h) const { + return std::shared_ptr(new TextureDefinition( + new CImgu8(mImg->mImg.get_resize(w, h, -100, -100, 5)), + mName, + mFmt, + mSiz, + mPallete, + mEffects + )); } \ No newline at end of file diff --git a/skelatool64/src/materials/TextureDefinition.h b/skelatool64/src/materials/TextureDefinition.h index 208365e..74ca77e 100644 --- a/skelatool64/src/materials/TextureDefinition.h +++ b/skelatool64/src/materials/TextureDefinition.h @@ -3,12 +3,15 @@ #include #include +#include #include "TextureFormats.h" #include "../definitions/DataChunk.h" #include "../definitions/FileDefinition.h" +class CImgu8; + class DataChunkStream { public: DataChunkStream(); @@ -85,6 +88,7 @@ private: class TextureDefinition { public: TextureDefinition(const std::string& filename, G_IM_FMT fmt, G_IM_SIZ siz, TextureDefinitionEffect effects, std::shared_ptr pallete); + ~TextureDefinition(); static void DetermineIdealFormat(const std::string& filename, G_IM_FMT& fmt, G_IM_SIZ& siz); @@ -102,6 +106,8 @@ public: int DTX() const; int NBytes() const; + const std::vector& GetData() const; + const std::string& Name() const; bool HasEffect(TextureDefinitionEffect effect) const; @@ -110,7 +116,20 @@ public: PixelRGBAu8 GetTwoToneMax() const; std::shared_ptr GetPallete() const; + + std::shared_ptr Crop(int x, int y, int w, int h) const; + std::shared_ptr Resize(int w, int h) const; private: + TextureDefinition( + CImgu8* mImg, + const std::string& name, + G_IM_FMT fmt, + G_IM_SIZ siz, + std::shared_ptr pallete, + TextureDefinitionEffect effects + ); + + CImgu8* mImg; std::string mName; G_IM_FMT mFmt; G_IM_SIZ mSiz;