diff --git a/modules/asset_baker/.clang-format b/modules/asset_baker/.clang-format new file mode 100644 index 0000000..a98b593 --- /dev/null +++ b/modules/asset_baker/.clang-format @@ -0,0 +1,151 @@ +--- +# Core +Language: Cpp +Standard: Cpp11 +ColumnLimit: '80' # No limit + +# Bin pack +BinPackArguments: 'false' +BinPackParameters: 'false' + +# Includes +SortIncludes: 'true' +IncludeBlocks: Regroup +IncludeCategories: + # Current Project + - Regex: '"' + Priority: 001 + + # Custom Project Categories... + + # Dependecies + - Regex: '' + Priority: 400 + + # Dependecies + - Regex: '<' + Priority: 500 + + + # Custom Deependencies Categories... + + # C++ includes + - Regex: '[^.h .hpp]>' + Priority: 998 + + # C includes + - Regex: '<[^/\n]+[.]h>' + Priority: 999 + +# Braces +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +# Indentation +UseTab: ForIndentation +TabWidth: '2' +IndentWidth: '2' +ContinuationIndentWidth: '2' +ConstructorInitializerIndentWidth: '2' +IndentCaseLabels: 'false' +IndentWrappedFunctionNames: 'true' +IndentPPDirectives: BeforeHash +NamespaceIndentation: None +AccessModifierOffset: '-2' + +# Space +SpaceAfterCStyleCast: 'false' +SpaceAfterLogicalNot: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'true' +SpaceBeforeCtorInitializerColon: 'false' +SpaceBeforeInheritanceColon: 'false' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' + +# Alignment +PointerAlignment: Left +DerivePointerAlignment: 'false' +AlignEscapedNewlines: Left +AlignAfterOpenBracket: BlockIndent +AlignConsecutiveDeclarations: 'false' +AlignConsecutiveAssignments: 'true' +AlignConsecutiveMacros: 'true' +AlignOperands: 'true' +AlignTrailingComments: 'true' + +# Single Line +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: 'false' +AllowShortLambdasOnASingleLine: Inline +AllowAllArgumentsOnNextLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortIfStatementsOnASingleLine: Never + +# Break +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'Yes' +BreakBeforeBinaryOperators: All +BreakBeforeTernaryOperators: 'false' +BreakInheritanceList: BeforeComma +BreakStringLiterals: 'false' + +# Penalties +PenaltyBreakAssignment: '99999' +PenaltyBreakBeforeFirstCallParameter: '0' +PenaltyBreakComment: '0' +PenaltyBreakFirstLessLess: '0' +PenaltyBreakString: '0' +PenaltyBreakTemplateDeclaration: '0' +PenaltyExcessCharacter: '999999999' +PenaltyReturnTypeOnItsOwnLine: '999999999' # Nope + +# Constructor Initializers +ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' +AllowAllConstructorInitializersOnNextLine: 'false' +BreakConstructorInitializers: BeforeComma + +# Comments +ReflowComments: 'true' +CommentPragmas: '^ TODO@:' +FixNamespaceComments: 'true' + +# Misc +Cpp11BracedListStyle: 'false' +SortUsingDeclarations: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +MaxEmptyLinesToKeep: '2' + + +ExperimentalAutoDetectBinPacking: false +AllowAllParametersOfDeclarationOnNextLine: false + + + diff --git a/modules/asset_baker/AssetBaker.cpp b/modules/asset_baker/AssetBaker.cpp new file mode 100644 index 0000000..d850d7c --- /dev/null +++ b/modules/asset_baker/AssetBaker.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#include + +#define ASSERT(x, ...) \ + if (!(x)) \ + { \ + log(__VA_ARGS__); \ + return -1; \ + } + + +template +void log(Args&&... args) +{ + (std::cout << ... << args); + std::cout << '\n'; +} + +bool convert_image( + const std::filesystem::path& input, + const std::filesystem::path& output +) +{ + int width, height, channels; + + stbi_uc* pixels = stbi_load( + input.string().c_str(), + &width, + &height, + &channels, + 4 + ); + + if (!pixels) + return false; + + Assets::TextureInfo texInfo { + .size = static_cast(width * height * 4), + .format = Assets::TextureFormat::RGBA8, + .pixel_size = { + static_cast(width), + static_cast(height), + 0ul, + }, + .original_file = input.string(), + }; + + Assets::AssetFile file = Assets::pack_texture(&texInfo, pixels); + + stbi_image_free(pixels); + + Assets::save_binary_file(output.string().c_str(), file); + + return true; +} + +int main(int argc, char* argv[]) +{ + std::ios_base::sync_with_stdio(false); + + ASSERT( + argc == 3, + "Argc MUST be 3, 1: execution-path(implicit), 2: input-directory, 3: output-directory" + ); + + for (auto& p : std::filesystem::directory_iterator(argv[1])) + { + if (p.path().extension() == ".png") + { + log("Found a texture: ", p); + + auto newp = p.path(); + newp.replace_extension(".asset_texture"); + convert_image(p.path(), newp); + } + else if (p.path().extension() == ".obj") + { + log("Found a mesh -> ", p, " (unsupported)"); + } + else + { + log("Unknown -> ", p); + } + } + + return 0; +} diff --git a/modules/asset_baker/CMakeLists.txt b/modules/asset_baker/CMakeLists.txt new file mode 100644 index 0000000..20a64bf --- /dev/null +++ b/modules/asset_baker/CMakeLists.txt @@ -0,0 +1,22 @@ +add_executable( + AssetBaker + + ${CMAKE_CURRENT_SOURCE_DIR}/AssetBaker.cpp +) + +set_target_properties( + AssetBaker PROPERTIES + CXX_STANDARD 20 +) + +target_include_directories( + AssetBaker + PRIVATE ${CMAKE_SOURCE_DIR}/AssetParser/ + PRIVATE ${CMAKE_SOURCE_DIR}/Vendor/stb/ +) + +target_link_libraries( + AssetBaker + PRIVATE ${CONAN_LIBS} + PRIVATE AssetParser +) diff --git a/modules/asset_parser/.clang-format b/modules/asset_parser/.clang-format new file mode 100644 index 0000000..090f268 --- /dev/null +++ b/modules/asset_parser/.clang-format @@ -0,0 +1,150 @@ +--- +# Core +Language: Cpp +Standard: Cpp11 +ColumnLimit: '80' # No limit + +# Bin pack +BinPackArguments: 'false' +BinPackParameters: 'false' + +# Includes +SortIncludes: 'true' +IncludeBlocks: Regroup +IncludeCategories: + # Current Project + - Regex: '"' + Priority: 001 + + # Custom Project Categories... + + # Dependecies + - Regex: '' + Priority: 400 + + # Dependecies + - Regex: '<' + Priority: 500 + + + # Custom Deependencies Categories... + + # C++ includes + - Regex: '[^.h .hpp]>' + Priority: 998 + + # C includes + - Regex: '<[^/\n]+[.]h>' + Priority: 999 + +# Braces +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +# Indentation +UseTab: ForIndentation +TabWidth: '2' +IndentWidth: '2' +ContinuationIndentWidth: '2' +ConstructorInitializerIndentWidth: '2' +IndentCaseLabels: 'false' +IndentWrappedFunctionNames: 'true' +IndentPPDirectives: BeforeHash +NamespaceIndentation: None +AccessModifierOffset: '-2' + +# Space +SpaceAfterCStyleCast: 'false' +SpaceAfterLogicalNot: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'true' +SpaceBeforeCtorInitializerColon: 'false' +SpaceBeforeInheritanceColon: 'false' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' + +# Alignment +PointerAlignment: Left +DerivePointerAlignment: 'false' +AlignEscapedNewlines: Left +AlignAfterOpenBracket: BlockIndent +AlignConsecutiveDeclarations: 'false' +AlignConsecutiveAssignments: 'true' +AlignConsecutiveMacros: 'true' +AlignOperands: 'true' +AlignTrailingComments: 'true' + +# Single Line +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: 'false' +AllowShortLambdasOnASingleLine: Inline +AllowAllArgumentsOnNextLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortIfStatementsOnASingleLine: Never + +# Break +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'Yes' +BreakBeforeBinaryOperators: All +BreakBeforeTernaryOperators: 'false' +BreakInheritanceList: BeforeComma +BreakStringLiterals: 'false' + +# Penalties +PenaltyBreakAssignment: '99999' +PenaltyBreakBeforeFirstCallParameter: '0' +PenaltyBreakComment: '0' +PenaltyBreakFirstLessLess: '0' +PenaltyBreakString: '0' +PenaltyBreakTemplateDeclaration: '0' +PenaltyExcessCharacter: '999999999' +PenaltyReturnTypeOnItsOwnLine: '999999999' # Nope + +# Constructor Initializers +ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' +AllowAllConstructorInitializersOnNextLine: 'false' +BreakConstructorInitializers: BeforeComma + +# Comments +ReflowComments: 'true' +CommentPragmas: '^ TODO@:' +FixNamespaceComments: 'true' + +# Misc +Cpp11BracedListStyle: 'false' +SortUsingDeclarations: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +MaxEmptyLinesToKeep: '2' + + +ExperimentalAutoDetectBinPacking: false +AllowAllParametersOfDeclarationOnNextLine: false + + diff --git a/modules/asset_parser/AssetParser.cpp b/modules/asset_parser/AssetParser.cpp new file mode 100644 index 0000000..2e6236e --- /dev/null +++ b/modules/asset_parser/AssetParser.cpp @@ -0,0 +1,57 @@ +#include "AssetParser.hpp" + +#include +#include +#include + +namespace Assets { + +bool save_binary_file(const char* path, const AssetFile& file) +{ + std::ofstream outstream(path, std::ios::binary | std::ios::out); + + outstream.write((const char*)&file.version, sizeof(uint32_t)); + outstream.write((const char*)&file.type, sizeof(AssetFile::Type)); + + uint32_t json_size = file.json.size(); + uint32_t blob_size = file.blob.size(); + outstream.write((const char*)&json_size, sizeof(uint32_t)); + outstream.write((const char*)&blob_size, sizeof(uint32_t)); + + outstream.write(file.json.c_str(), json_size); + outstream.write((const char*)file.blob.data(), blob_size); + + outstream.close(); + + outstream.close(); + + return true; +} + +bool load_binary_file(const char* path, AssetFile& out_file) +{ + std::ifstream instream(path, std::ios::binary); + instream.seekg(0ull); + + if (!instream.is_open()) + return false; + + instream.read((char*)&out_file.version, sizeof(uint32_t)); + instream.read((char*)&out_file.type, sizeof(AssetFile::Type)); + + uint32_t json_size; + uint32_t blob_size; + instream.read((char*)&json_size, sizeof(uint32_t)); + instream.read((char*)&blob_size, sizeof(uint32_t)); + + out_file.json.resize(json_size); + out_file.blob.resize(blob_size); + instream.read((char*)out_file.json.data(), json_size); + instream.read((char*)out_file.blob.data(), blob_size); + + instream.close(); + + return true; +} + +} // namespace Assets diff --git a/modules/asset_parser/AssetParser.hpp b/modules/asset_parser/AssetParser.hpp new file mode 100644 index 0000000..47d54c9 --- /dev/null +++ b/modules/asset_parser/AssetParser.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +namespace Assets { + +struct AssetFile +{ + uint32_t version; + + enum class Type : uint32_t + { + Texture, + Mesh, + Material, + } type; + + std::string json; + std::vector blob; +}; + +enum class CompressionMode : uint32_t +{ + None, + LZ4, + LZ4HC, +}; + +bool save_binary_file(const char* path, const AssetFile& in_file); +bool load_binary_file(const char* path, AssetFile& out_file); + +} // namespace Assets diff --git a/modules/asset_parser/CMakeLists.txt b/modules/asset_parser/CMakeLists.txt new file mode 100644 index 0000000..c51d1f9 --- /dev/null +++ b/modules/asset_parser/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(AssetParser + ${CMAKE_CURRENT_SOURCE_DIR}/AssetParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TextureAsset.cpp +) + +target_include_directories( + AssetParser + PRIVATE ${CMAKE_SOURCE_DIR}/Vendor/nlohmann/single_include + PRIVATE ${CMAKE_SOURCE_DIR}/Vendor/lz4/lib/ +) + +target_link_libraries( + AssetParser + PRIVATE lz4_static + PRIVATE nlohmann_json::nlohmann_json +) diff --git a/modules/asset_parser/TextureAsset.cpp b/modules/asset_parser/TextureAsset.cpp new file mode 100644 index 0000000..ddc4821 --- /dev/null +++ b/modules/asset_parser/TextureAsset.cpp @@ -0,0 +1,81 @@ +#include "TextureAsset.hpp" + +#include +#include + +namespace Assets { + +using namespace nlohmann; + +TextureInfo read_texture_info(AssetFile* file) +{ + json texture_meta_data = json::parse(file->json); + + return TextureInfo { + .size = texture_meta_data["bufferSize"], + .compression_mode = texture_meta_data["compression"], + .format = texture_meta_data["format"], + .pixel_size = { + texture_meta_data["width"], + texture_meta_data["height"], + 0, + }, + .original_file = texture_meta_data["originalFile"], + }; +} + +void unpack_texture( + TextureInfo* info, + const void* source_buffer, + size_t source_size, + void* destination +) +{ + if (info->compression_mode == CompressionMode::LZ4) + { + LZ4_decompress_safe( + (const char*)source_buffer, + (char*)destination, + source_size, + info->size + ); + } + else + { + memcpy(destination, source_buffer, source_size); + } +} + +AssetFile pack_texture(TextureInfo* info, void* pixel_data) +{ + json metadata; + metadata["format"] = info->format; + metadata["width"] = info->pixel_size[0]; + metadata["height"] = info->pixel_size[1]; + metadata["bufferSize"] = info->size; + metadata["originalFile"] = info->original_file; + metadata["compression"] = CompressionMode::LZ4; + + AssetFile file; + file.type = AssetFile::Type::Texture; + file.version = 1u; + + const int compress_staging = LZ4_compressBound(info->size); + file.blob.resize(compress_staging); + const int compression_size = LZ4_compress_default( + (const char*)pixel_data, + (char*)file.blob.data(), + info->size, + compress_staging + ); + file.blob.resize(compression_size); + + + metadata["compression"] = CompressionMode::LZ4; + + file.json = metadata.dump(); + + return file; +} + +} // namespace Assets diff --git a/modules/asset_parser/TextureAsset.hpp b/modules/asset_parser/TextureAsset.hpp new file mode 100644 index 0000000..df48476 --- /dev/null +++ b/modules/asset_parser/TextureAsset.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "AssetParser.hpp" + +namespace Assets { + +enum class TextureFormat +{ + None = 0, + RGBA8, +}; + +struct TextureInfo +{ + size_t size; + CompressionMode compression_mode; + TextureFormat format; + uint32_t pixel_size[3]; + std::string original_file; +}; + +TextureInfo read_texture_info(AssetFile* file); + +void unpack_texture( + TextureInfo* info, + const void* source_buffer, + size_t source_size, + void* destination +); + +AssetFile pack_texture(TextureInfo* info, void* pixel_data); + +} // namespace Assets