Started reworking the asset builder
This commit is contained in:
parent
ea1013c573
commit
cc0316ff80
@ -72,7 +72,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>cd assets
|
<Command>cd assets
|
||||||
"$(SolutionDir)NFPackCreator\bin\x64$(Configuration)\NFPackCreator.exe"
|
"$(SolutionDir)NFAssetBuilder\bin\x64$(Configuration)\NFAssetBuilder.exe"
|
||||||
if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q && goto end) else goto end
|
if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q && goto end) else goto end
|
||||||
:end
|
:end
|
||||||
mkdir "$(OutDir)assets"
|
mkdir "$(OutDir)assets"
|
||||||
@ -105,7 +105,7 @@ if exist "base.nfpack" (copy "base.nfpack" "$(OutDir)assets\")</Command>
|
|||||||
</Link>
|
</Link>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>cd assets
|
<Command>cd assets
|
||||||
"$(SolutionDir)NFPackCreator\bin\x64$(Configuration)\NFPackCreator.exe"
|
"$(SolutionDir)NFAssetBuilder\bin\x64$(Configuration)\NFAssetBuilder.exe"
|
||||||
if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q && goto end) else goto end
|
if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q && goto end) else goto end
|
||||||
:end
|
:end
|
||||||
mkdir "$(OutDir)assets"
|
mkdir "$(OutDir)assets"
|
||||||
|
@ -68,12 +68,12 @@ BEGIN
|
|||||||
BLOCK "040904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Grayson Riffe"
|
VALUE "CompanyName", "Grayson Riffe"
|
||||||
VALUE "FileDescription", "Nothin' Fancy Asset Pack Creator"
|
VALUE "FileDescription", "Nothin' Fancy Asset Builder"
|
||||||
VALUE "FileVersion", "1.0"
|
VALUE "FileVersion", "1.0"
|
||||||
VALUE "InternalName", "NFPackCreator.exe"
|
VALUE "InternalName", "NFAssetBuilder.exe"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2021 Grayson Riffe"
|
VALUE "LegalCopyright", "Copyright (C) 2021"
|
||||||
VALUE "OriginalFilename", "NFPackCreator.exe"
|
VALUE "OriginalFilename", "NFAssetBuilder.exe"
|
||||||
VALUE "ProductName", "Nothin' Fancy Asset Pack Creator"
|
VALUE "ProductName", "Nothin' Fancy Asset Builder"
|
||||||
VALUE "ProductVersion", "1.0"
|
VALUE "ProductVersion", "1.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
@ -16,6 +16,7 @@
|
|||||||
<ProjectGuid>{771b4aee-e2c6-4745-ac40-1ef57149612e}</ProjectGuid>
|
<ProjectGuid>{771b4aee-e2c6-4745-ac40-1ef57149612e}</ProjectGuid>
|
||||||
<RootNamespace>NFPackCreator</RootNamespace>
|
<RootNamespace>NFPackCreator</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>NFAssetBuilder</ProjectName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
@ -60,6 +61,7 @@
|
|||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -76,6 +78,7 @@
|
|||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -87,12 +90,18 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
|
<ClCompile Include="src\Models.cpp" />
|
||||||
|
<ClCompile Include="src\Textures.cpp" />
|
||||||
|
<ClCompile Include="src\Utility.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="src\include\Models.h" />
|
||||||
|
<ClInclude Include="src\include\Textures.h" />
|
||||||
|
<ClInclude Include="src\include\Utility.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="NFPackCreator.rc" />
|
<ResourceCompile Include="NFAssetBuilder.rc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
@ -18,14 +18,32 @@
|
|||||||
<ClCompile Include="src\main.cpp">
|
<ClCompile Include="src\main.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Textures.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Models.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Utility.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\include\Utility.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\include\Textures.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\include\Models.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="NFPackCreator.rc">
|
<ResourceCompile Include="NFAssetBuilder.rc">
|
||||||
<Filter>Resource Files</Filter>
|
<Filter>Resource Files</Filter>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
@ -10,6 +10,7 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||||
<LocalDebuggerCommandArguments>-h</LocalDebuggerCommandArguments>
|
<LocalDebuggerCommandArguments>
|
||||||
|
</LocalDebuggerCommandArguments>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,6 +1,6 @@
|
|||||||
//{{NO_DEPENDENCIES}}
|
//{{NO_DEPENDENCIES}}
|
||||||
// Microsoft Visual C++ generated include file.
|
// Microsoft Visual C++ generated include file.
|
||||||
// Used by NFPackCreator.rc
|
// Used by NFAssetBuilder.rc
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
297
NFAssetBuilder/src/Models.cpp
Normal file
297
NFAssetBuilder/src/Models.cpp
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
#include "Models.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
|
||||||
|
std::vector<char> obj(&OBJin[0], &OBJin[0] + OBJin.size());
|
||||||
|
std::vector<char> mtl(&MTLin[0], &MTLin[0] + MTLin.size());
|
||||||
|
|
||||||
|
std::unordered_map<std::string, TempMaterial*> mats;
|
||||||
|
parseMaterials(mats, mtl);
|
||||||
|
|
||||||
|
std::vector<float> vbRaw, tcRaw, vnRaw;
|
||||||
|
std::string usingMat;
|
||||||
|
|
||||||
|
bool tcPresent = false, vnPresent = false;
|
||||||
|
size_t position = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t nextLine = std::search(obj.begin() + position, obj.end(), "\n", "\n" + std::strlen("\n")) - (obj.begin() + position);
|
||||||
|
if (!nextLine)
|
||||||
|
break;
|
||||||
|
std::vector<char> line(&obj[position], &obj[position + nextLine]);
|
||||||
|
position += nextLine + 1;
|
||||||
|
std::stringstream ss(std::string(&line[0], line.size()));
|
||||||
|
std::string firstWord;
|
||||||
|
ss >> firstWord;
|
||||||
|
|
||||||
|
if (std::strcmp(&firstWord[0], "v") == 0) {
|
||||||
|
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||||
|
ss >> x >> y >> z;
|
||||||
|
vbRaw.push_back(x);
|
||||||
|
vbRaw.push_back(y);
|
||||||
|
vbRaw.push_back(z);
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "vt") == 0) {
|
||||||
|
tcPresent = true;
|
||||||
|
float u = 0.0f, v = 0.0f;
|
||||||
|
ss >> u >> v;
|
||||||
|
tcRaw.push_back(u);
|
||||||
|
tcRaw.push_back(v);
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "vn") == 0) {
|
||||||
|
vnPresent = true;
|
||||||
|
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||||
|
ss >> x >> y >> z;
|
||||||
|
vnRaw.push_back(x);
|
||||||
|
vnRaw.push_back(y);
|
||||||
|
vnRaw.push_back(z);
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "usemtl") == 0) {
|
||||||
|
std::string matName;
|
||||||
|
ss >> matName;
|
||||||
|
usingMat = matName;
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "f") == 0) {
|
||||||
|
if (!tcPresent)
|
||||||
|
Error("No texture coordinates found in model!");
|
||||||
|
if (!vnPresent)
|
||||||
|
Error("No normals found in model!");
|
||||||
|
|
||||||
|
unsigned int vertexIndex[3], uvIndex[3], vnIndex[3];
|
||||||
|
char temp;
|
||||||
|
ss >> vertexIndex[0] >> temp >> uvIndex[0] >> temp >> vnIndex[0] >> vertexIndex[1] >> temp >> uvIndex[1] >> temp >> vnIndex[1] >> vertexIndex[2] >> temp >> uvIndex[2] >> temp >> vnIndex[2];
|
||||||
|
if (ss.rdbuf()->in_avail() > 1)
|
||||||
|
Error("Model has non-triangle faces!");
|
||||||
|
mats[usingMat]->vbIndices.push_back(vertexIndex[0]);
|
||||||
|
mats[usingMat]->vbIndices.push_back(vertexIndex[1]);
|
||||||
|
mats[usingMat]->vbIndices.push_back(vertexIndex[2]);
|
||||||
|
mats[usingMat]->tcIndices.push_back(uvIndex[0]);
|
||||||
|
mats[usingMat]->tcIndices.push_back(uvIndex[1]);
|
||||||
|
mats[usingMat]->tcIndices.push_back(uvIndex[2]);
|
||||||
|
mats[usingMat]->vnIndices.push_back(vnIndex[0]);
|
||||||
|
mats[usingMat]->vnIndices.push_back(vnIndex[1]);
|
||||||
|
mats[usingMat]->vnIndices.push_back(vnIndex[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& m : mats) {
|
||||||
|
std::string curr = m.first;
|
||||||
|
for (unsigned int i = 0; i < mats[curr]->vbIndices.size(); i++) {
|
||||||
|
unsigned int vertexIndex = mats[curr]->vbIndices[i];
|
||||||
|
unsigned int uvIndex = mats[curr]->tcIndices[i];
|
||||||
|
unsigned int vnIndex = mats[curr]->vnIndices[i];
|
||||||
|
float vertexX = vbRaw[(vertexIndex - 1) * 3];
|
||||||
|
float vertexY = vbRaw[(vertexIndex - 1) * 3 + 1];
|
||||||
|
float vertexZ = vbRaw[(vertexIndex - 1) * 3 + 2];
|
||||||
|
float vertexU = tcRaw[(uvIndex - 1) * 2];
|
||||||
|
float vertexV = tcRaw[(uvIndex - 1) * 2 + 1];
|
||||||
|
float vnX = vnRaw[(vnIndex - 1) * 3];
|
||||||
|
float vnY = vnRaw[(vnIndex - 1) * 3 + 1];
|
||||||
|
float vnZ = vnRaw[(vnIndex - 1) * 3 + 2];
|
||||||
|
mats[curr]->unindexedVB.push_back(vertexX);
|
||||||
|
mats[curr]->unindexedVB.push_back(vertexY);
|
||||||
|
mats[curr]->unindexedVB.push_back(vertexZ);
|
||||||
|
mats[curr]->unindexedTC.push_back(vertexU);
|
||||||
|
mats[curr]->unindexedTC.push_back(vertexV);
|
||||||
|
mats[curr]->unindexedVN.push_back(vnX);
|
||||||
|
mats[curr]->unindexedVN.push_back(vnY);
|
||||||
|
mats[curr]->unindexedVN.push_back(vnZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i * 9 < mats[curr]->unindexedVB.size(); i++) {
|
||||||
|
Vec3 pos1(mats[curr]->unindexedVB[i * 9], mats[curr]->unindexedVB[i * 9 + 1], mats[curr]->unindexedVB[i * 9 + 2]);
|
||||||
|
Vec2 uv1(mats[curr]->unindexedTC[i * 6], mats[curr]->unindexedTC[i * 6 + 1]);
|
||||||
|
Vec3 pos2(mats[curr]->unindexedVB[i * 9 + 3], mats[curr]->unindexedVB[i * 9 + 4], mats[curr]->unindexedVB[i * 9 + 5]);
|
||||||
|
Vec2 uv2(mats[curr]->unindexedTC[i * 6 + 2], mats[curr]->unindexedTC[i * 6 + 3]);
|
||||||
|
Vec3 pos3(mats[curr]->unindexedVB[i * 9 + 6], mats[curr]->unindexedVB[i * 9 + 7], mats[curr]->unindexedVB[i * 9 + 8]);
|
||||||
|
Vec2 uv3(mats[curr]->unindexedTC[i * 6 + 4], mats[curr]->unindexedTC[i * 6 + 5]);
|
||||||
|
|
||||||
|
Vec3 edge1 = pos2 - pos1;
|
||||||
|
Vec3 edge2 = pos3 - pos1;
|
||||||
|
Vec2 delta1 = uv2 - uv1;
|
||||||
|
Vec2 delta2 = uv3 - uv1;
|
||||||
|
float f = 1.0f / (delta1.x * delta2.y - delta2.x * delta1.y);
|
||||||
|
float x = f * (delta2.y * edge1.x - delta1.y * edge2.x);
|
||||||
|
float y = f * (delta2.y * edge1.y - delta1.y * edge2.y);
|
||||||
|
float z = f * (delta2.y * edge1.z - delta1.y * edge2.z);
|
||||||
|
mats[curr]->unindexedTan.push_back(x);
|
||||||
|
mats[curr]->unindexedTan.push_back(y);
|
||||||
|
mats[curr]->unindexedTan.push_back(z);
|
||||||
|
mats[curr]->unindexedTan.push_back(x);
|
||||||
|
mats[curr]->unindexedTan.push_back(y);
|
||||||
|
mats[curr]->unindexedTan.push_back(z);
|
||||||
|
mats[curr]->unindexedTan.push_back(x);
|
||||||
|
mats[curr]->unindexedTan.push_back(y);
|
||||||
|
mats[curr]->unindexedTan.push_back(z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
|
||||||
|
float u;
|
||||||
|
float v;
|
||||||
|
|
||||||
|
float vnX;
|
||||||
|
float vnY;
|
||||||
|
float vnZ;
|
||||||
|
|
||||||
|
bool operator<(const Vertex other) const {
|
||||||
|
return std::memcmp((void*)this, (void*)&other, sizeof(Vertex)) > 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<float> vboPositions;
|
||||||
|
std::vector<float> vboTexCoords;
|
||||||
|
std::vector<float> vboNormals;
|
||||||
|
std::vector<float> vboTangents;
|
||||||
|
std::vector<int> vboMaterialIndices;
|
||||||
|
std::vector<unsigned int> vboIndices;
|
||||||
|
int matCount = 0;
|
||||||
|
|
||||||
|
std::string modelHeader;
|
||||||
|
int numMats = (int)mats.size();
|
||||||
|
modelHeader.append((char*)&numMats, sizeof(numMats));
|
||||||
|
|
||||||
|
for (auto& m : mats) {
|
||||||
|
std::string curr = m.first;
|
||||||
|
std::map<Vertex, unsigned int> vertexMap;
|
||||||
|
for (unsigned int i = 0; i * 3 < mats[curr]->unindexedVB.size(); i++) {
|
||||||
|
Vertex currVertex = { mats[curr]->unindexedVB[(i * 3)], mats[curr]->unindexedVB[(i * 3) + 1], mats[curr]->unindexedVB[(i * 3) + 2], mats[curr]->unindexedTC[(i * 2)], mats[curr]->unindexedTC[(i * 2) + 1], mats[curr]->unindexedVN[(i * 3)], mats[curr]->unindexedVN[(i * 3) + 1], mats[curr]->unindexedVN[(i * 3) + 2] };
|
||||||
|
bool found = false;
|
||||||
|
found = vertexMap.find(currVertex) != vertexMap.end();
|
||||||
|
if (found) {
|
||||||
|
unsigned int index = vertexMap[currVertex];
|
||||||
|
mats[curr]->outIB.push_back(index);
|
||||||
|
mats[curr]->ibCount++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mats[curr]->outVB.push_back(currVertex.x);
|
||||||
|
mats[curr]->outVB.push_back(currVertex.y);
|
||||||
|
mats[curr]->outVB.push_back(currVertex.z);
|
||||||
|
mats[curr]->outTC.push_back(currVertex.u);
|
||||||
|
mats[curr]->outTC.push_back(currVertex.v);
|
||||||
|
mats[curr]->outVN.push_back(currVertex.vnX);
|
||||||
|
mats[curr]->outVN.push_back(currVertex.vnY);
|
||||||
|
mats[curr]->outVN.push_back(currVertex.vnZ);
|
||||||
|
mats[curr]->outTan.push_back(mats[curr]->unindexedTan[(i * 3)]);
|
||||||
|
mats[curr]->outTan.push_back(mats[curr]->unindexedTan[(i * 3 + 1)]);
|
||||||
|
mats[curr]->outTan.push_back(mats[curr]->unindexedTan[(i * 3 + 2)]);
|
||||||
|
size_t index = (mats[curr]->outVB.size() / 3) - 1;
|
||||||
|
mats[curr]->outIB.push_back((unsigned int)index);
|
||||||
|
vertexMap[currVertex] = (unsigned int)index;
|
||||||
|
mats[curr]->ibCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TempMaterial& curr2 = *m.second;
|
||||||
|
|
||||||
|
//Serialize this
|
||||||
|
//curr2.diffuseColor.x, curr2.diffuseColor.y, curr2.diffuseColor.z, curr2.shininess
|
||||||
|
|
||||||
|
modelHeader.append((char*)&curr2.diffuseColor.x, sizeof(curr2.diffuseColor.x));
|
||||||
|
modelHeader.append((char*)&curr2.diffuseColor.y, sizeof(curr2.diffuseColor.y));
|
||||||
|
modelHeader.append((char*)&curr2.diffuseColor.z, sizeof(curr2.diffuseColor.z));
|
||||||
|
modelHeader.append((char*)&curr2.shininess, sizeof(curr2.shininess));
|
||||||
|
|
||||||
|
size_t offset = vboPositions.size() / 3;
|
||||||
|
vboPositions.insert(vboPositions.end(), curr2.outVB.begin(), curr2.outVB.end());
|
||||||
|
vboTexCoords.insert(vboTexCoords.end(), curr2.outTC.begin(), curr2.outTC.end());
|
||||||
|
vboNormals.insert(vboNormals.end(), curr2.outVN.begin(), curr2.outVN.end());
|
||||||
|
vboTangents.insert(vboTangents.end(), curr2.outTan.begin(), curr2.outTan.end());
|
||||||
|
vboMaterialIndices.insert(vboMaterialIndices.end(), curr2.outVB.size() / 3, matCount);
|
||||||
|
if (offset)
|
||||||
|
std::for_each(curr2.outIB.begin(), curr2.outIB.end(), [offset](unsigned int& out) { out += (unsigned int)offset; });
|
||||||
|
vboIndices.insert(vboIndices.end(), curr2.outIB.begin(), curr2.outIB.end());
|
||||||
|
delete m.second;
|
||||||
|
matCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t posSize = vboPositions.size() * sizeof(float);
|
||||||
|
size_t tcSize = vboTexCoords.size() * sizeof(float);
|
||||||
|
size_t normSize = vboNormals.size() * sizeof(float);
|
||||||
|
size_t tanSize = vboTangents.size() * sizeof(float);
|
||||||
|
size_t matIndicesSize = vboMaterialIndices.size() * sizeof(int);
|
||||||
|
size_t indicesSize = vboIndices.size() * sizeof(unsigned int);
|
||||||
|
|
||||||
|
modelHeader.append((char*)&posSize, sizeof(posSize));
|
||||||
|
modelHeader.append((char*)&tcSize, sizeof(tcSize));
|
||||||
|
modelHeader.append((char*)&normSize, sizeof(normSize));
|
||||||
|
modelHeader.append((char*)&tanSize, sizeof(tanSize));
|
||||||
|
modelHeader.append((char*)&matIndicesSize, sizeof(matIndicesSize));
|
||||||
|
modelHeader.append((char*)&indicesSize, sizeof(indicesSize));
|
||||||
|
|
||||||
|
out.append(modelHeader);
|
||||||
|
out.append((char*)vboPositions.data(), posSize);
|
||||||
|
out.append((char*)vboTexCoords.data(), tcSize);
|
||||||
|
out.append((char*)vboNormals.data(), normSize);
|
||||||
|
out.append((char*)vboTangents.data(), tanSize);
|
||||||
|
out.append((char*)vboMaterialIndices.data(), matIndicesSize);
|
||||||
|
out.append((char*)vboIndices.data(), indicesSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl) {
|
||||||
|
std::string currMat;
|
||||||
|
size_t position = 0;
|
||||||
|
while (true) {
|
||||||
|
size_t nextLine = std::search(mtl.begin() + position, mtl.end(), "\n", "\n" + std::strlen("\n")) - (mtl.begin() + position);
|
||||||
|
if (position + nextLine >= mtl.size())
|
||||||
|
break;
|
||||||
|
std::vector<char> line(&mtl[position], &mtl[position + nextLine]);
|
||||||
|
position += nextLine + 1;
|
||||||
|
std::stringstream ss(std::string(&line[0], line.size()));
|
||||||
|
std::string firstWord;
|
||||||
|
ss >> firstWord;
|
||||||
|
|
||||||
|
if (std::strcmp(&firstWord[0], "newmtl") == 0) {
|
||||||
|
ss >> currMat;
|
||||||
|
mats[currMat] = new TempMaterial;
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "Kd") == 0) {
|
||||||
|
float r = 0.0f, g = 0.0f, b = 0.0f;
|
||||||
|
ss >> r >> g >> b;
|
||||||
|
mats[currMat]->diffuseColor = Vec3(r, g, b);
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "map_Kd") == 0) {
|
||||||
|
std::string texName = getNewLine(ss);
|
||||||
|
mats[currMat]->diffuseTextureName = texName;
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "map_Ks") == 0) {
|
||||||
|
std::string texName = getNewLine(ss);
|
||||||
|
mats[currMat]->specularTextureName = texName;
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "map_Bump") == 0) {
|
||||||
|
std::string texName = getNewLine(ss);
|
||||||
|
mats[currMat]->normalTextureName = texName;
|
||||||
|
}
|
||||||
|
else if (std::strcmp(&firstWord[0], "Ns") == 0) {
|
||||||
|
float s = 0.0f;
|
||||||
|
ss >> s;
|
||||||
|
mats[currMat]->shininess = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getNeededImages(std::string mtl, std::set<std::string>& set) {
|
||||||
|
while (mtl.size()) {
|
||||||
|
size_t pos = mtl.find("map_");
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
break;
|
||||||
|
if (pos == mtl.find("map_Kd") || pos == mtl.find("map_Ks"))
|
||||||
|
mtl = mtl.substr(pos + 7);
|
||||||
|
else
|
||||||
|
mtl = mtl.substr(pos + 9);
|
||||||
|
std::stringstream ss(mtl);
|
||||||
|
std::string temp = getNewLine(ss);
|
||||||
|
size_t pos2 = temp.find_last_of("/\\");
|
||||||
|
if (pos2 != std::string::npos)
|
||||||
|
temp = temp.substr(pos2 + 1);
|
||||||
|
set.insert(temp);
|
||||||
|
}
|
||||||
|
}
|
18
NFAssetBuilder/src/Textures.cpp
Normal file
18
NFAssetBuilder/src/Textures.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "Textures.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
void cookTexture(const std::string& in, std::string& out) {
|
||||||
|
stbi_set_flip_vertically_on_load(true);
|
||||||
|
|
||||||
|
int x, y, channels;
|
||||||
|
unsigned char* texture = stbi_load_from_memory((unsigned char*)&in[0], (int)in.size(), &x, &y, &channels, 0);
|
||||||
|
|
||||||
|
out.append((char*)&x, sizeof(x));
|
||||||
|
out.append((char*)&y, sizeof(y));
|
||||||
|
out.append((char*)&channels, sizeof(channels));
|
||||||
|
out.append((char*)texture, x * y * channels);
|
||||||
|
|
||||||
|
stbi_image_free(texture);
|
||||||
|
}
|
84
NFAssetBuilder/src/Utility.cpp
Normal file
84
NFAssetBuilder/src/Utility.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "Utility.h"
|
||||||
|
|
||||||
|
#include<iostream>
|
||||||
|
#include<thread>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include<Windows.h>
|
||||||
|
#include <compressapi.h>
|
||||||
|
|
||||||
|
static COMPRESSOR_HANDLE cHandle;
|
||||||
|
|
||||||
|
void Log(const char* in) {
|
||||||
|
std::cout << "[NFAssetBuilder] Info: " << in << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(const std::string& in) {
|
||||||
|
Log(in.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void Error(const std::string& in) {
|
||||||
|
HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
SetConsoleTextAttribute(cmd, FOREGROUND_RED);
|
||||||
|
std::cout << "[NFAssetBuilder] Error: " + in + "\n";
|
||||||
|
SetConsoleTextAttribute(cmd, 7);
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||||
|
std::exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Success(const std::string& in) {
|
||||||
|
HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
SetConsoleTextAttribute(cmd, FOREGROUND_GREEN);
|
||||||
|
std::cout << "[NFAssetBuilder] Success: " + in + "\n";
|
||||||
|
SetConsoleTextAttribute(cmd, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initCompressor() {
|
||||||
|
CreateCompressor(COMPRESS_ALGORITHM_XPRESS_HUFF, NULL, &cHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string readFile(const std::string& filename) {
|
||||||
|
std::ifstream in;
|
||||||
|
in.open(filename, std::ios::binary);
|
||||||
|
if (!in)
|
||||||
|
Error("File \"" + (std::string)filename + (std::string)"\" could not be opened!");
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << in.rdbuf();
|
||||||
|
std::string read(ss.str());
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writePack(const std::string& filename, std::string& in) {
|
||||||
|
std::ofstream out;
|
||||||
|
out.open(filename, std::ios::binary);
|
||||||
|
if (!out)
|
||||||
|
Error("Pack \"" + filename + (std::string)"\" could not be written!");
|
||||||
|
|
||||||
|
in.insert(0, "NFASSETPACK");
|
||||||
|
|
||||||
|
Log("Encrypting...");
|
||||||
|
for (unsigned int i = 0; i < in.size(); i++)
|
||||||
|
in[i] += 100;
|
||||||
|
|
||||||
|
Log("Compressing...");
|
||||||
|
size_t compSize;
|
||||||
|
Compress(cHandle, &in[0], in.size(), NULL, 0, &compSize);
|
||||||
|
char* buff = new char[compSize];
|
||||||
|
Compress(cHandle, &in[0], in.size(), buff, compSize, &compSize);
|
||||||
|
|
||||||
|
out.write(buff, compSize);
|
||||||
|
delete[] buff;
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getNewLine(std::stringstream& stringstream) {
|
||||||
|
std::string out;
|
||||||
|
std::getline(stringstream, out);
|
||||||
|
|
||||||
|
if (out[out.size() - 1] == '\r')
|
||||||
|
out.erase(out.size() - 1);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
33
NFAssetBuilder/src/include/Models.h
Normal file
33
NFAssetBuilder/src/include/Models.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Utility.h"
|
||||||
|
|
||||||
|
struct TempMaterial {
|
||||||
|
std::vector<float> outVB;
|
||||||
|
std::vector<float> unindexedVB;
|
||||||
|
std::vector<unsigned int> vbIndices;
|
||||||
|
std::vector<float> outTC;
|
||||||
|
std::vector<float> unindexedTC;
|
||||||
|
std::vector<unsigned int> tcIndices;
|
||||||
|
std::vector<float> outVN;
|
||||||
|
std::vector<float> unindexedVN;
|
||||||
|
std::vector<unsigned int> vnIndices;
|
||||||
|
std::vector<float> unindexedTan;
|
||||||
|
std::vector<float> outTan;
|
||||||
|
std::vector<unsigned int> outIB;
|
||||||
|
unsigned int ibCount = 0;
|
||||||
|
|
||||||
|
std::string diffuseTextureName;
|
||||||
|
Vec3 diffuseColor;
|
||||||
|
std::string specularTextureName;
|
||||||
|
std::string normalTextureName;
|
||||||
|
float shininess = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
void cookModel(std::string& in, std::string& MTLin, std::string& out);
|
||||||
|
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl);
|
||||||
|
void getNeededImages(std::string mtl, std::set<std::string>& set);
|
4
NFAssetBuilder/src/include/Textures.h
Normal file
4
NFAssetBuilder/src/include/Textures.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void cookTexture(const std::string& in, std::string& out);
|
117
NFAssetBuilder/src/include/Utility.h
Normal file
117
NFAssetBuilder/src/include/Utility.h
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void Log(const char* in);
|
||||||
|
void Log(const std::string& in);
|
||||||
|
|
||||||
|
void Error(const std::string& in);
|
||||||
|
void Success(const std::string& in);
|
||||||
|
|
||||||
|
void initCompressor();
|
||||||
|
|
||||||
|
std::string readFile(const std::string& filename);
|
||||||
|
void writePack(const std::string& filename, std::string& in);
|
||||||
|
|
||||||
|
std::string getNewLine(std::stringstream& stringstream);
|
||||||
|
|
||||||
|
struct Vec2 {
|
||||||
|
Vec2() : x(0.0f), y(0.0f) {}
|
||||||
|
|
||||||
|
Vec2(float x1) : x(x1), y(x1) {}
|
||||||
|
|
||||||
|
Vec2(float x1, float y1) : x(x1), y(y1) {}
|
||||||
|
|
||||||
|
Vec2(double x1) : x((float)x1), y((float)x1) {}
|
||||||
|
|
||||||
|
Vec2(double x1, double y1) : x((float)x1), y((float)y1) {}
|
||||||
|
Vec2 operator+(const Vec2& rhs) const {
|
||||||
|
return Vec2(x + rhs.x, y + rhs.y);
|
||||||
|
}
|
||||||
|
Vec2 operator-(const Vec2& rhs) const {
|
||||||
|
return Vec2(x - rhs.x, y - rhs.y);
|
||||||
|
}
|
||||||
|
Vec2 operator*(const float scalar) const {
|
||||||
|
return Vec2(x * scalar, y * scalar);
|
||||||
|
}
|
||||||
|
Vec2 operator/(const Vec2& rhs) const {
|
||||||
|
return Vec2(x / rhs.x, y / rhs.y);
|
||||||
|
}
|
||||||
|
Vec2& operator+=(const Vec2& rhs) {
|
||||||
|
this->x += rhs.x;
|
||||||
|
this->y += rhs.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec2& operator-=(const Vec2& rhs) {
|
||||||
|
this->x -= rhs.x;
|
||||||
|
this->y -= rhs.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec2& operator*=(const Vec2& rhs) {
|
||||||
|
this->x *= rhs.x;
|
||||||
|
this->y *= rhs.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec2& operator/=(const Vec2& rhs) {
|
||||||
|
this->x /= rhs.x;
|
||||||
|
this->y /= rhs.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator==(const Vec2& rhs) {
|
||||||
|
return this->x == rhs.x && this->y == rhs.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vec3 {
|
||||||
|
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||||
|
|
||||||
|
Vec3(float x1) : x(x1), y(x1), z(x1) {}
|
||||||
|
|
||||||
|
Vec3(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
|
||||||
|
|
||||||
|
Vec3(double x1) : x((float)x1), y((float)x1), z((float)x1) {}
|
||||||
|
|
||||||
|
Vec3(double x1, double y1, double z1) : x((float)x1), y((float)y1), z((float)z1) {}
|
||||||
|
Vec3 operator+(const Vec3& rhs) const {
|
||||||
|
return Vec3(x + rhs.x, y + rhs.y, z + rhs.z);
|
||||||
|
}
|
||||||
|
Vec3 operator-(const Vec3& rhs) const {
|
||||||
|
return Vec3(x - rhs.x, y - rhs.y, z - rhs.z);
|
||||||
|
}
|
||||||
|
Vec3 operator*(const float scalar) const {
|
||||||
|
return Vec3(x * scalar, y * scalar, z * scalar);
|
||||||
|
}
|
||||||
|
Vec3 operator/(const Vec3& rhs) const {
|
||||||
|
return Vec3(x / rhs.x, y / rhs.y, z / rhs.z);
|
||||||
|
}
|
||||||
|
Vec3& operator+=(const Vec3& rhs) {
|
||||||
|
this->x += rhs.x;
|
||||||
|
this->y += rhs.y;
|
||||||
|
this->z += rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec3& operator-=(const Vec3& rhs) {
|
||||||
|
this->x -= rhs.x;
|
||||||
|
this->y -= rhs.y;
|
||||||
|
this->z -= rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec3& operator*=(const Vec3& rhs) {
|
||||||
|
this->x *= rhs.x;
|
||||||
|
this->y *= rhs.y;
|
||||||
|
this->z *= rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Vec3& operator/=(const Vec3& rhs) {
|
||||||
|
this->x /= rhs.x;
|
||||||
|
this->y /= rhs.y;
|
||||||
|
this->z /= rhs.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator==(const Vec3& rhs) {
|
||||||
|
return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
};
|
129
NFAssetBuilder/src/main.cpp
Normal file
129
NFAssetBuilder/src/main.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include <thread>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <compressapi.h>
|
||||||
|
|
||||||
|
#include "Utility.h"
|
||||||
|
#include "Models.h"
|
||||||
|
#include "Textures.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
Log("Starting up");
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
if ((std::string)argv[1] == "-h") {
|
||||||
|
Log("Nothin' Fancy Asset Builder\nThis tool creates .nfpack files for the NF engine to load "
|
||||||
|
"at runtime.\nA pack gets created for each directory in the working directory if there "
|
||||||
|
"are only compatible files inside.\nSubdirectories are not ignored.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
initCompressor();
|
||||||
|
|
||||||
|
std::set<std::string> extensions;
|
||||||
|
extensions.insert({ "shader", "obj", "png", "jpg", "ttf", "wav", "ogg" });
|
||||||
|
|
||||||
|
unsigned int dirCount = 0;
|
||||||
|
|
||||||
|
const std::filesystem::path workingDir = std::filesystem::current_path();
|
||||||
|
|
||||||
|
for (const auto& currDir : std::filesystem::directory_iterator(workingDir)) {
|
||||||
|
if (!currDir.is_directory()) continue;
|
||||||
|
std::string currPackFilename = currDir.path().filename().string().append(".nfpack");
|
||||||
|
Log("Building pack " + currPackFilename);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, size_t> packFiles;
|
||||||
|
std::string currFileExtension;
|
||||||
|
std::string currFileIn;
|
||||||
|
std::string currPackOut;
|
||||||
|
unsigned int fileCount = 0;
|
||||||
|
|
||||||
|
for (const auto& curr : std::filesystem::recursive_directory_iterator(currDir)) {
|
||||||
|
if (curr.is_directory()) continue;
|
||||||
|
|
||||||
|
std::filesystem::path relative = std::filesystem::relative(curr, currDir);
|
||||||
|
std::string currFileName = relative.filename().string();
|
||||||
|
|
||||||
|
for (auto& file : packFiles)
|
||||||
|
if (currFileName == file.first)
|
||||||
|
Error("Duplicate asset \"" + currFileName + (std::string)"\" in pack!");
|
||||||
|
|
||||||
|
currFileExtension = relative.extension().string().substr(1);
|
||||||
|
if (currFileExtension == "mtl")
|
||||||
|
continue;
|
||||||
|
if (extensions.find(currFileExtension) == extensions.end())
|
||||||
|
Error("File \"" + currFileName + (std::string)"\" is not of supported type!");
|
||||||
|
|
||||||
|
Log("Current file: " + currFileName);
|
||||||
|
|
||||||
|
currFileIn = readFile(curr.path().string());
|
||||||
|
std::string currFileOut;
|
||||||
|
|
||||||
|
if (currFileExtension == "obj") {
|
||||||
|
std::string mtlFileName = currFileName.substr(0, currFileName.find_last_of('.')) + (std::string)".mtl";
|
||||||
|
std::string mtl;
|
||||||
|
for (const auto& curr2 : std::filesystem::recursive_directory_iterator(currDir)) {
|
||||||
|
if (curr2.path().filename().string() == mtlFileName) {
|
||||||
|
Log("Found mtl file for " + currFileName);
|
||||||
|
mtl = readFile(curr2.path().string());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mtl.empty())
|
||||||
|
Error("No mtl file found for " + currFileName + (std::string)"!");
|
||||||
|
Log("Cooking model...");
|
||||||
|
cookModel(currFileIn, mtl, currFileOut);
|
||||||
|
}
|
||||||
|
else if (currFileExtension == "png" || currFileExtension == "jpg")
|
||||||
|
cookTexture(currFileIn, currFileOut);
|
||||||
|
|
||||||
|
packFiles[currFileName] = currFileOut.size();
|
||||||
|
|
||||||
|
currPackOut += currFileOut;
|
||||||
|
|
||||||
|
fileCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileCount) {
|
||||||
|
Log("No files found inside of \"" + currDir.path().filename().string() + (std::string)"\". No pack written.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log("Finished gathering files");
|
||||||
|
|
||||||
|
std::string header;
|
||||||
|
for (auto& currFile : packFiles) {
|
||||||
|
header += currFile.first;
|
||||||
|
header += ':';
|
||||||
|
header.append((char*)&currFile.second, sizeof(size_t));
|
||||||
|
header += ':';
|
||||||
|
}
|
||||||
|
header.erase(header.size() - 1);
|
||||||
|
header.append("/NFENDOFPACKHEADER");
|
||||||
|
int headerTableSize = (int)header.size();
|
||||||
|
header.insert(0, (char*)&headerTableSize, sizeof(headerTableSize));
|
||||||
|
header.insert(0, (char*)&fileCount, sizeof(fileCount));
|
||||||
|
|
||||||
|
currPackOut.insert(0, header);
|
||||||
|
|
||||||
|
writePack(currPackFilename, currPackOut);
|
||||||
|
|
||||||
|
Success("Wrote \"" + currPackFilename + (std::string)"\" containing " + std::to_string(fileCount) + (std::string)" files.");
|
||||||
|
|
||||||
|
dirCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirCount > 0)
|
||||||
|
Log("Wrote " + std::to_string(dirCount) + (std::string)" asset pack(s).");
|
||||||
|
else
|
||||||
|
Log("No directories found!");
|
||||||
|
|
||||||
|
Log("Done");
|
||||||
|
#ifdef _DEBUG
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,195 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <set>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <compressapi.h>
|
|
||||||
|
|
||||||
COMPRESSOR_HANDLE cHandle;
|
|
||||||
|
|
||||||
void Log(const std::string& in) {
|
|
||||||
std::cout << "[NFPackCreator] Info: " << in << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void Log(const char* in) {
|
|
||||||
std::cout << "[NFPackCreator] Info: " << in << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]]
|
|
||||||
void Error(const std::string& in) {
|
|
||||||
HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
SetConsoleTextAttribute(cmd, FOREGROUND_RED);
|
|
||||||
std::cout << "[NFPackCreator] Error: " + in + "\n";
|
|
||||||
SetConsoleTextAttribute(cmd, 7);
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
|
||||||
std::exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Success(const std::string& in) {
|
|
||||||
HANDLE cmd = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
SetConsoleTextAttribute(cmd, FOREGROUND_GREEN);
|
|
||||||
std::cout << "[NFPackCreator] Success: " + in + "\n";
|
|
||||||
SetConsoleTextAttribute(cmd, 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string readFile(const std::string& filename) {
|
|
||||||
std::ifstream in;
|
|
||||||
in.open(filename, std::ios::binary);
|
|
||||||
if (!in)
|
|
||||||
Error("File \"" + (std::string)filename + (std::string)"\" could not be read!");
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << in.rdbuf();
|
|
||||||
std::string read(ss.str());
|
|
||||||
if (read.size() > 4 && read.substr(0, 4) == "NFEF") {
|
|
||||||
read = read.substr(4);
|
|
||||||
for (unsigned int i = 0; i < read.size(); i++)
|
|
||||||
read[i] = read[i] - 100;
|
|
||||||
}
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeFile(const std::string& filename, const std::string& in, bool encrypted) {
|
|
||||||
std::ofstream out;
|
|
||||||
out.open(filename, std::ios::binary);
|
|
||||||
if (!out)
|
|
||||||
Error("File \"" + (std::string)filename + (std::string)"\" could not be written!");
|
|
||||||
std::string write(in);
|
|
||||||
if (encrypted) {
|
|
||||||
for (unsigned int i = 0; i < write.size(); i++) {
|
|
||||||
char temp = write[i] + 100;
|
|
||||||
write[i] = temp;
|
|
||||||
}
|
|
||||||
write.insert(0, "NFEF");
|
|
||||||
}
|
|
||||||
Log("Compressing...");
|
|
||||||
size_t compSize;
|
|
||||||
Compress(cHandle, &write[0], write.size(), NULL, 0, &compSize);
|
|
||||||
char* buff = new char[compSize];
|
|
||||||
Compress(cHandle, &write[0], write.size(), buff, compSize, &compSize);
|
|
||||||
|
|
||||||
out.write(buff, compSize);
|
|
||||||
delete[] buff;
|
|
||||||
out << write;
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void getNeededImages(std::string mtl, std::set<std::string>& set) {
|
|
||||||
while (mtl.size()) {
|
|
||||||
size_t pos = mtl.find("map_");
|
|
||||||
if (pos == std::string::npos)
|
|
||||||
break;
|
|
||||||
if (pos == mtl.find("map_Kd") || pos == mtl.find("map_Ks"))
|
|
||||||
mtl = mtl.substr(pos + 7);
|
|
||||||
else
|
|
||||||
mtl = mtl.substr(pos + 9);
|
|
||||||
std::stringstream ss(mtl);
|
|
||||||
std::string temp;
|
|
||||||
ss >> temp;
|
|
||||||
size_t pos2 = temp.find_last_of("/\\");
|
|
||||||
if (pos2 != std::string::npos)
|
|
||||||
temp = temp.substr(pos2 + 1);
|
|
||||||
set.insert(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
Log("Starting up");
|
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
if ((std::string)argv[1] == "-h") {
|
|
||||||
Log("Nothin' Fancy Asset Pack Creator\nThis tool creates .nfpack files for the NF engine to load at runtime.\nA pack gets created for each directory in the working directory if there are only compatible files inside.\nSubdirectories are not ignored.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateCompressor(COMPRESS_ALGORITHM_XPRESS_HUFF, NULL, &cHandle);
|
|
||||||
|
|
||||||
std::set<std::string> extensions;
|
|
||||||
extensions.insert({ "shader", "obj", "png", "jpg", "ttf", "wav", "ogg" });
|
|
||||||
|
|
||||||
unsigned int dirCount = 0;
|
|
||||||
const std::filesystem::path workingDir = std::filesystem::current_path();
|
|
||||||
for (const auto& currDir : std::filesystem::directory_iterator(std::filesystem::current_path())) {
|
|
||||||
if (!currDir.is_directory())
|
|
||||||
continue;
|
|
||||||
std::string filename = currDir.path().filename().string().append(".nfpack");
|
|
||||||
Log("Creating pack \"" + filename + (std::string)"\"");
|
|
||||||
std::vector<std::string> packFilenames;
|
|
||||||
std::string currFileExtension;
|
|
||||||
std::string currFileContents;
|
|
||||||
std::stringstream out;
|
|
||||||
unsigned int fileCount = 0;
|
|
||||||
for (const auto& curr : std::filesystem::recursive_directory_iterator(currDir)) {
|
|
||||||
if (curr.is_directory())
|
|
||||||
continue;
|
|
||||||
std::filesystem::path relative = std::filesystem::relative(curr, currDir);
|
|
||||||
currFileExtension = relative.extension().string().substr(1);
|
|
||||||
if (currFileExtension == "mtl")
|
|
||||||
continue;
|
|
||||||
if (extensions.find(currFileExtension) == extensions.end())
|
|
||||||
Error("File \"" + relative.string() + (std::string)"\" is not of supported type!");
|
|
||||||
Log("Current file: " + relative.string());
|
|
||||||
|
|
||||||
currFileContents = readFile(curr.path().string());
|
|
||||||
if (currFileExtension == "obj") {
|
|
||||||
std::filesystem::path mtlPath;
|
|
||||||
for (const auto& curr2 : std::filesystem::recursive_directory_iterator(curr.path().parent_path())) {
|
|
||||||
if (curr2.is_directory())
|
|
||||||
continue;
|
|
||||||
if (curr2.path().extension() != ".mtl")
|
|
||||||
continue;
|
|
||||||
std::string mtlFile = relative.filename().string().substr(0, relative.filename().string().size() - 4) + (std::string)".mtl";
|
|
||||||
if (curr2.path().filename().string() == mtlFile) {
|
|
||||||
mtlPath = curr2.path();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mtlPath.empty())
|
|
||||||
Error("No mtl file found for " + relative.filename().string() + (std::string)"!");
|
|
||||||
Log("Found mtl file for " + relative.filename().string());
|
|
||||||
std::set<std::string> neededImages;
|
|
||||||
std::string mtlContents = readFile(mtlPath.string());
|
|
||||||
getNeededImages(mtlContents, neededImages);
|
|
||||||
if (!neededImages.empty()) {
|
|
||||||
currFileContents.insert(0, "\n");
|
|
||||||
for (std::string curr : neededImages) {
|
|
||||||
currFileContents.insert(0, curr);
|
|
||||||
currFileContents.insert(0, " ");
|
|
||||||
}
|
|
||||||
currFileContents = currFileContents.substr(1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currFileContents.insert(0, "none\n");
|
|
||||||
}
|
|
||||||
currFileContents += '\n' + mtlContents;
|
|
||||||
}
|
|
||||||
for (std::string& currFilename : packFilenames)
|
|
||||||
if (relative.filename().string() == currFilename)
|
|
||||||
Error("Duplicate asset name \"" + relative.filename().string() + (std::string)"\" in pack!");
|
|
||||||
packFilenames.push_back(relative.filename().string());
|
|
||||||
if (out.rdbuf()->in_avail() != 0)
|
|
||||||
out << "\n";
|
|
||||||
out << "#NFASSET " + curr.path().filename().string();
|
|
||||||
out << "\n";
|
|
||||||
out << currFileContents;
|
|
||||||
fileCount++;
|
|
||||||
}
|
|
||||||
if (fileCount == 0) {
|
|
||||||
Log("No files found inside of \"" + currDir.path().filename().string() + (std::string)"\". No pack written.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
writeFile(filename, out.str(), true);
|
|
||||||
Success("Wrote \"" + filename + (std::string)"\" containing " + std::to_string(fileCount) + (std::string)" files.");
|
|
||||||
dirCount++;
|
|
||||||
}
|
|
||||||
if (dirCount > 0)
|
|
||||||
Log("Wrote " + std::to_string(dirCount) + (std::string)" asset pack(s).");
|
|
||||||
else
|
|
||||||
Log("No directories found!");
|
|
||||||
Log("Done");
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -81,7 +81,7 @@
|
|||||||
<PostBuildEvent />
|
<PostBuildEvent />
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>cd assets
|
<Command>cd assets
|
||||||
"$(SolutionDir)NFPackCreator\bin\x64$(Configuration)\NFPackCreator.exe"</Command>
|
"$(SolutionDir)NFAssetBuilder\bin\x64$(Configuration)\NFAssetBuilder.exe"</Command>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@ -116,7 +116,7 @@
|
|||||||
<PostBuildEvent />
|
<PostBuildEvent />
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
<Command>cd assets
|
<Command>cd assets
|
||||||
"$(SolutionDir)NFPackCreator\bin\x64$(Configuration)\NFPackCreator.exe"</Command>
|
"$(SolutionDir)NFAssetBuilder\bin\x64$(Configuration)\NFAssetBuilder.exe"</Command>
|
||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -184,6 +184,11 @@
|
|||||||
<None Include="res\defaultShader\fragment.shader" />
|
<None Include="res\defaultShader\fragment.shader" />
|
||||||
<None Include="res\defaultShader\vertex.shader" />
|
<None Include="res\defaultShader\vertex.shader" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\NFAssetBuilder\NFAssetBuilder.vcxproj">
|
||||||
|
<Project>{771b4aee-e2c6-4745-ac40-1ef57149612e}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
@ -361,11 +361,11 @@ namespace nf {
|
|||||||
for (unsigned int i = 0; i < m_materials.size(); i++) {
|
for (unsigned int i = 0; i < m_materials.size(); i++) {
|
||||||
Texture* curr;
|
Texture* curr;
|
||||||
if ((curr = std::get<0>(m_materials[i])) != nullptr)
|
if ((curr = std::get<0>(m_materials[i])) != nullptr)
|
||||||
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(std::get<0>(m_materials[i]));
|
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
|
||||||
if ((curr = std::get<1>(m_materials[i])) != nullptr)
|
if ((curr = std::get<1>(m_materials[i])) != nullptr)
|
||||||
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(std::get<1>(m_materials[i]));
|
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
|
||||||
if ((curr = std::get<2>(m_materials[i])) != nullptr)
|
if ((curr = std::get<2>(m_materials[i])) != nullptr)
|
||||||
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(std::get<2>(m_materials[i]));
|
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
#include "nf/Texture.h"
|
#include "nf/Texture.h"
|
||||||
|
|
||||||
#include "GL/glew.h"
|
#include "GL/glew.h"
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
#include "nf/Assets.h"
|
#include "nf/Assets.h"
|
||||||
#include "nf/Utility.h"
|
#include "nf/Utility.h"
|
||||||
@ -14,18 +12,14 @@ namespace nf {
|
|||||||
m_x(0),
|
m_x(0),
|
||||||
m_y(0)
|
m_y(0)
|
||||||
{
|
{
|
||||||
|
//Load dimensions and channels from cooked data
|
||||||
int nChannels;
|
int nChannels;
|
||||||
stbi_set_flip_vertically_on_load(true);
|
|
||||||
unsigned char* texture = stbi_load_from_memory((unsigned char*)tex->data, (unsigned int)tex->size, &m_x, &m_y, &nChannels, 0);
|
|
||||||
if (!texture)
|
|
||||||
NFError("Texture failed to load from memory!");
|
|
||||||
glGenTextures(1, &m_id);
|
glGenTextures(1, &m_id);
|
||||||
glBindTexture(GL_TEXTURE_2D, m_id);
|
glBindTexture(GL_TEXTURE_2D, m_id);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, linear ? GL_RGBA : GL_SRGB_ALPHA, m_x, m_y, 0, nChannels == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, texture);
|
glTexImage2D(GL_TEXTURE_2D, 0, linear ? GL_RGBA : GL_SRGB_ALPHA, m_x, m_y, 0, nChannels == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, tex->data);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
stbi_image_free(texture);
|
|
||||||
m_isBase = tex->isBaseAsset;
|
m_isBase = tex->isBaseAsset;
|
||||||
tex->alreadyLoaded = true;
|
tex->alreadyLoaded = true;
|
||||||
tex->loadedTexture = this;
|
tex->loadedTexture = this;
|
||||||
|
@ -10,7 +10,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "Game\Game.vcxproj",
|
|||||||
{771B4AEE-E2C6-4745-AC40-1EF57149612E} = {771B4AEE-E2C6-4745-AC40-1EF57149612E}
|
{771B4AEE-E2C6-4745-AC40-1EF57149612E} = {771B4AEE-E2C6-4745-AC40-1EF57149612E}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NFPackCreator", "NFPackCreator\NFPackCreator.vcxproj", "{771B4AEE-E2C6-4745-AC40-1EF57149612E}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NFAssetBuilder", "NFAssetBuilder\NFAssetBuilder.vcxproj", "{771B4AEE-E2C6-4745-AC40-1EF57149612E}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -336,7 +336,7 @@ After rendering, our world will have a background.
|
|||||||
@section customAssetsTut Adding Your Assets
|
@section customAssetsTut Adding Your Assets
|
||||||
|
|
||||||
NF's asset system builds your assets into NFPacks that the engine reads at runtime. The
|
NF's asset system builds your assets into NFPacks that the engine reads at runtime. The
|
||||||
external tool `NFPackCreator.exe` creates these for you. For a complete guide, please
|
external tool `NFAssetCreator.exe` creates these for you. For a complete guide, please
|
||||||
see @ref assets.
|
see @ref assets.
|
||||||
|
|
||||||
@section createUITut Creating a UI
|
@section createUITut Creating a UI
|
||||||
|
Reference in New Issue
Block a user