Started reworking the asset builder

This commit is contained in:
Grayson Riffe (Laptop) 2021-12-10 12:10:07 -06:00
parent ea1013c573
commit cc0316ff80
20 changed files with 735 additions and 221 deletions

View File

@ -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 &amp;&amp; goto end) else goto end if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q &amp;&amp; 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 &amp;&amp; goto end) else goto end if exist "$(OutDir)assets" (rmdir "$(OutDir)assets" /S /Q &amp;&amp; goto end) else goto end
:end :end
mkdir "$(OutDir)assets" mkdir "$(OutDir)assets"

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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

View File

@ -0,0 +1,4 @@
#pragma once
#include <string>
void cookTexture(const std::string& in, std::string& out);

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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