Started reworking the asset builder

This commit is contained in:
grayson committed 2021-12-10 12:10:07 -06:00
1 parent ea1013c573
commit cc0316ff80
20 files changed
+735 -221

No files matched your search

+297
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);
}
}
+18
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);
}
+84
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;
}
+33
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);
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <string>
void cookTexture(const std::string& in, std::string& out);
+117
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
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;
}