Finished reworking asset builder; Models are now cooked when built

This commit is contained in:
Grayson Riffe (Laptop) 2021-12-14 02:51:23 -06:00
parent cc0316ff80
commit 7a93befa14
20 changed files with 291 additions and 475 deletions

View File

@ -62,6 +62,7 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -79,6 +80,7 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard> <LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)src\include;$(ProjectDir)dep\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -91,13 +93,11 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="src\main.cpp" /> <ClCompile Include="src\main.cpp" />
<ClCompile Include="src\Models.cpp" /> <ClCompile Include="src\Models.cpp" />
<ClCompile Include="src\Textures.cpp" />
<ClCompile Include="src\Utility.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\Models.h" />
<ClInclude Include="src\include\Textures.h" />
<ClInclude Include="src\include\Utility.h" /> <ClInclude Include="src\include\Utility.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -18,9 +18,6 @@
<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"> <ClCompile Include="src\Models.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -32,9 +29,6 @@
<ClInclude Include="src\include\Utility.h"> <ClInclude Include="src\include\Utility.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\include\Textures.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Models.h"> <ClInclude Include="src\include\Models.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>

View File

@ -4,6 +4,7 @@
#include <sstream> #include <sstream>
#include <filesystem> #include <filesystem>
#include <map> #include <map>
#include <set>
void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) { void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
std::vector<char> obj(&OBJin[0], &OBJin[0] + OBJin.size()); std::vector<char> obj(&OBJin[0], &OBJin[0] + OBJin.size());
@ -156,8 +157,18 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
int matCount = 0; int matCount = 0;
std::string modelHeader; std::string modelHeader;
int numMats = (int)mats.size(); std::vector<std::string> textures = getNeededTextures(MTLin);
modelHeader.append((char*)&numMats, sizeof(numMats)); std::string textureHeader;
if (textures.empty())
textureHeader = "none\n";
else
for (const auto& curr : textures)
textureHeader.append(curr + (std::string)"\n");
modelHeader.append(textureHeader);
modelHeader.append("/ENDTEXTURES\n");
modelHeader.append(std::to_string(mats.size()) + (std::string)"\n");
for (auto& m : mats) { for (auto& m : mats) {
std::string curr = m.first; std::string curr = m.first;
@ -192,13 +203,25 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
TempMaterial& curr2 = *m.second; TempMaterial& curr2 = *m.second;
//Serialize this std::string textureIndices;
//curr2.diffuseColor.x, curr2.diffuseColor.y, curr2.diffuseColor.z, curr2.shininess if (!curr2.diffuseTextureName.empty())
textureIndices.append(std::to_string((std::find(textures.begin(), textures.end(), curr2.diffuseTextureName) - textures.begin()) + 1) + (std::string)" ");
else
textureIndices.append(std::to_string(0) + (std::string)" ");
if (!curr2.specularTextureName.empty())
textureIndices.append(std::to_string((std::find(textures.begin(), textures.end(), curr2.specularTextureName) - textures.begin()) + 1) + (std::string)" ");
else
textureIndices.append(std::to_string(0) + (std::string)" ");
if (!curr2.normalTextureName.empty())
textureIndices.append(std::to_string((std::find(textures.begin(), textures.end(), curr2.normalTextureName) - textures.begin()) + 1) + (std::string)" ");
else
textureIndices.append(std::to_string(0) + (std::string)" ");
modelHeader.append((char*)&curr2.diffuseColor.x, sizeof(curr2.diffuseColor.x)); modelHeader.append(textureIndices);
modelHeader.append((char*)&curr2.diffuseColor.y, sizeof(curr2.diffuseColor.y)); modelHeader.append(std::to_string(curr2.diffuseColor.x) + (std::string)" ");
modelHeader.append((char*)&curr2.diffuseColor.z, sizeof(curr2.diffuseColor.z)); modelHeader.append(std::to_string(curr2.diffuseColor.y) + (std::string)" ");
modelHeader.append((char*)&curr2.shininess, sizeof(curr2.shininess)); modelHeader.append(std::to_string(curr2.diffuseColor.z) + (std::string)" ");
modelHeader.append(std::to_string(curr2.shininess) + (std::string)"\n");
size_t offset = vboPositions.size() / 3; size_t offset = vboPositions.size() / 3;
vboPositions.insert(vboPositions.end(), curr2.outVB.begin(), curr2.outVB.end()); vboPositions.insert(vboPositions.end(), curr2.outVB.begin(), curr2.outVB.end());
@ -212,20 +235,23 @@ void cookModel(std::string& OBJin, std::string& MTLin, std::string& out) {
delete m.second; delete m.second;
matCount++; matCount++;
} }
modelHeader.append("/ENDMATERIALS\n");
size_t posSize = vboPositions.size() * sizeof(float); unsigned int posSize = (unsigned int)vboPositions.size() * sizeof(float);
size_t tcSize = vboTexCoords.size() * sizeof(float); unsigned int tcSize = (unsigned int)vboTexCoords.size() * sizeof(float);
size_t normSize = vboNormals.size() * sizeof(float); unsigned int normSize = (unsigned int)vboNormals.size() * sizeof(float);
size_t tanSize = vboTangents.size() * sizeof(float); unsigned int tanSize = (unsigned int)vboTangents.size() * sizeof(float);
size_t matIndicesSize = vboMaterialIndices.size() * sizeof(int); unsigned int matIndicesSize = (unsigned int)vboMaterialIndices.size() * sizeof(int);
size_t indicesSize = vboIndices.size() * sizeof(unsigned int); unsigned int indicesSize = (unsigned int)vboIndices.size() * sizeof(unsigned int);
modelHeader.append((char*)&posSize, sizeof(posSize)); modelHeader.append(std::to_string(posSize) + (std::string)" ");
modelHeader.append((char*)&tcSize, sizeof(tcSize)); modelHeader.append(std::to_string(tcSize) + (std::string)" ");
modelHeader.append((char*)&normSize, sizeof(normSize)); modelHeader.append(std::to_string(normSize) + (std::string)" ");
modelHeader.append((char*)&tanSize, sizeof(tanSize)); modelHeader.append(std::to_string(tanSize) + (std::string)" ");
modelHeader.append((char*)&matIndicesSize, sizeof(matIndicesSize)); modelHeader.append(std::to_string(matIndicesSize) + (std::string)" ");
modelHeader.append((char*)&indicesSize, sizeof(indicesSize)); modelHeader.append(std::to_string(vboIndices.size()) + (std::string)"\n");
modelHeader.append("/ENDHEADER\n");
out.append(modelHeader); out.append(modelHeader);
out.append((char*)vboPositions.data(), posSize); out.append((char*)vboPositions.data(), posSize);
@ -278,7 +304,8 @@ void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::v
} }
} }
void getNeededImages(std::string mtl, std::set<std::string>& set) { std::vector<std::string> getNeededTextures(std::string mtl) {
std::set<std::string> tex;
while (mtl.size()) { while (mtl.size()) {
size_t pos = mtl.find("map_"); size_t pos = mtl.find("map_");
if (pos == std::string::npos) if (pos == std::string::npos)
@ -292,6 +319,15 @@ void getNeededImages(std::string mtl, std::set<std::string>& set) {
size_t pos2 = temp.find_last_of("/\\"); size_t pos2 = temp.find_last_of("/\\");
if (pos2 != std::string::npos) if (pos2 != std::string::npos)
temp = temp.substr(pos2 + 1); temp = temp.substr(pos2 + 1);
set.insert(temp); tex.insert(temp);
} }
std::vector<std::string> out;
if (tex.empty())
return out;
else
for (const auto& curr : tex)
out.push_back(curr);
return out;
} }

View File

@ -1,18 +0,0 @@
#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

@ -56,8 +56,6 @@ void writePack(const std::string& filename, std::string& in) {
if (!out) if (!out)
Error("Pack \"" + filename + (std::string)"\" could not be written!"); Error("Pack \"" + filename + (std::string)"\" could not be written!");
in.insert(0, "NFASSETPACK");
Log("Encrypting..."); Log("Encrypting...");
for (unsigned int i = 0; i < in.size(); i++) for (unsigned int i = 0; i < in.size(); i++)
in[i] += 100; in[i] += 100;
@ -80,5 +78,8 @@ std::string getNewLine(std::stringstream& stringstream) {
if (out[out.size() - 1] == '\r') if (out[out.size() - 1] == '\r')
out.erase(out.size() - 1); out.erase(out.size() - 1);
if (out[0] == ' ')
out = out.substr(1);
return out; return out;
} }

View File

@ -1,6 +1,4 @@
#pragma once #pragma once
#include <string>
#include <set>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -30,4 +28,4 @@ struct TempMaterial {
void cookModel(std::string& in, std::string& MTLin, std::string& out); 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 parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl);
void getNeededImages(std::string mtl, std::set<std::string>& set); std::vector<std::string> getNeededTextures(std::string mtl);

View File

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

View File

@ -1,25 +1,29 @@
#include <iostream>
#include <thread> #include <thread>
#include <filesystem> #include <filesystem>
#include <set> #include <set>
#include <unordered_map>
#include <Windows.h> #include <Windows.h>
#include <compressapi.h> #include <compressapi.h>
#include "Utility.h" #include "Utility.h"
#include "Models.h" #include "Models.h"
#include "Textures.h"
[[noreturn]]
void printHelp() {
std::cout << "Nothin' Fancy Asset Builder\n\nThis tool creates .nfpack files for the NF engine to "
"load at runtime. A pack gets created for each directory in the working directory if there "
"are only compatible files inside. Subdirectories are not ignored.\n\nFor more information, "
"refer to the Nothin' Fancy manual";
std::exit(0);
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
Log("Starting up"); if (argc > 1 && ((std::string)argv[1] == "-h" || (std::string)argv[1] == "/?"))
printHelp();
if (argc > 1) Log("Starting up");
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(); initCompressor();
@ -35,7 +39,8 @@ int main(int argc, char* argv[]) {
std::string currPackFilename = currDir.path().filename().string().append(".nfpack"); std::string currPackFilename = currDir.path().filename().string().append(".nfpack");
Log("Building pack " + currPackFilename); Log("Building pack " + currPackFilename);
std::unordered_map<std::string, size_t> packFiles; std::vector<std::string> packFilenames;
std::vector<unsigned int> packFileSizes;
std::string currFileExtension; std::string currFileExtension;
std::string currFileIn; std::string currFileIn;
std::string currPackOut; std::string currPackOut;
@ -47,8 +52,8 @@ int main(int argc, char* argv[]) {
std::filesystem::path relative = std::filesystem::relative(curr, currDir); std::filesystem::path relative = std::filesystem::relative(curr, currDir);
std::string currFileName = relative.filename().string(); std::string currFileName = relative.filename().string();
for (auto& file : packFiles) for (auto& file : packFilenames)
if (currFileName == file.first) if (currFileName == file)
Error("Duplicate asset \"" + currFileName + (std::string)"\" in pack!"); Error("Duplicate asset \"" + currFileName + (std::string)"\" in pack!");
currFileExtension = relative.extension().string().substr(1); currFileExtension = relative.extension().string().substr(1);
@ -77,10 +82,11 @@ int main(int argc, char* argv[]) {
Log("Cooking model..."); Log("Cooking model...");
cookModel(currFileIn, mtl, currFileOut); cookModel(currFileIn, mtl, currFileOut);
} }
else if (currFileExtension == "png" || currFileExtension == "jpg") else
cookTexture(currFileIn, currFileOut); currFileOut = currFileIn;
packFiles[currFileName] = currFileOut.size(); packFilenames.push_back(currFileName);
packFileSizes.push_back((unsigned int)currFileOut.size());
currPackOut += currFileOut; currPackOut += currFileOut;
@ -94,19 +100,16 @@ int main(int argc, char* argv[]) {
else else
Log("Finished gathering files"); Log("Finished gathering files");
//Write pack header with asset names and sizes
std::string header; std::string header;
for (auto& currFile : packFiles) { header += std::to_string(fileCount) + (std::string)"\n";
header += currFile.first; for (unsigned int i = 0; i < packFilenames.size(); i++) {
header += ':'; header += packFilenames[i];
header.append((char*)&currFile.second, sizeof(size_t)); header += '\n';
header += ':'; header += std::to_string(packFileSizes[i]);
header += '\n';
} }
header.erase(header.size() - 1); header.append("/ENDHEADER");
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); currPackOut.insert(0, header);
writePack(currPackFilename, currPackOut); writePack(currPackFilename, currPackOut);

View File

@ -8,9 +8,9 @@ out vec4 color;
void main() { void main() {
vec3 tc; vec3 tc;
tc = vec3(-texCoord.x, texCoord.y, texCoord.z); tc = vec3(-texCoord.x, -texCoord.y, texCoord.z);
if (texCoord.y > 0.999999 || texCoord.y < -0.999999) { if (texCoord.y > 0.999999 || texCoord.y < -0.999999)
tc = vec3(texCoord.x, texCoord.y, texCoord.z); tc = vec3(texCoord.x, texCoord.y, texCoord.z);
}
color = texture(cm, tc); color = texture(cm, tc);
} }

View File

@ -51,34 +51,37 @@ namespace nf {
} }
void AssetPack::load(const char* packName) { void AssetPack::load(const char* packName) {
NFLog("Loading asset pack \"" + (std::string)packName + (std::string)"\"");
std::string path = "assets/" + (std::string)packName; std::string path = "assets/" + (std::string)packName;
std::string packContents = readFile(path, true); std::string packContents;
if (!readFile(path, packContents, true))
NFError("Could not find pack file \"" + (std::string)packName + (std::string)"\"!") ;
std::string packContentsOBJ = packContents; std::string packContentsOBJ = packContents;
std::unordered_map<std::string, ACubemap*> cubemaps; std::unordered_map<std::string, ACubemap*> cubemaps;
std::unordered_map<std::string, AButton*> buttons; std::unordered_map<std::string, AButton*> buttons;
unsigned int cubemapCount = 0; unsigned int cubemapFaceCount = 0;
unsigned int buttonCount = 0; unsigned int buttonTextureCount = 0;
while (packContents.size()) {
packContents = packContents.substr(9);
size_t endAssetNamePos = packContents.find_first_of('\n');
std::string assetName = packContents.substr(0, endAssetNamePos);
packContents = packContents.substr(endAssetNamePos + 1);
size_t extensionPos = assetName.find_first_of('.');
std::string extension = assetName.substr(extensionPos + 1);
std::string assetContents;
size_t nextAssetPos = packContents.find("#NFASSET ");
if (nextAssetPos != std::string::npos) {
assetContents = packContents.substr(0, nextAssetPos - 1);
packContents = packContents.substr(nextAssetPos);
}
else {
assetContents = packContents;
packContents = "";
}
unsigned int assetSize = (unsigned int)assetContents.size();
if (extension == "obj") unsigned int assetCount = std::stoi(packContents.substr(0, packContents.find_first_of("\n")));
unsigned int endHeader = (unsigned int)packContents.find("/ENDHEADER");
unsigned int headerLength = endHeader - ((unsigned int)packContents.find_first_of("\n") + 1);
std::stringstream header(packContents.substr(packContents.find_first_of("\n") + 1, headerLength));
unsigned int assetPos = endHeader + 10;
for (unsigned int i = 0; i < assetCount; i++) {
std::string assetName;
std::getline(header, assetName);
std::string temp;
std::getline(header, temp);
unsigned int assetSize = std::stoi(temp);
std::string extension = assetName.substr(assetName.find_last_of(".") + 1);
if (extension == "obj") {
assetPos += assetSize;
continue; continue;
}
if (extension == "png" || extension == "jpg") { if (extension == "png" || extension == "jpg") {
if (assetName.find("_cmfront") != std::string::npos || assetName.find("_cmback") != std::string::npos || assetName.find("_cmtop") != std::string::npos || assetName.find("_cmbottom") != std::string::npos || assetName.find("_cmleft") != std::string::npos || assetName.find("_cmright") != std::string::npos) { if (assetName.find("_cmfront") != std::string::npos || assetName.find("_cmback") != std::string::npos || assetName.find("_cmtop") != std::string::npos || assetName.find("_cmbottom") != std::string::npos || assetName.find("_cmleft") != std::string::npos || assetName.find("_cmright") != std::string::npos) {
std::string cmName = assetName.substr(0, assetName.find('_')); std::string cmName = assetName.substr(0, assetName.find('_'));
@ -91,40 +94,41 @@ namespace nf {
NFError("Duplicate cubemap images in pack \"" + (std::string)packName + (std::string)"\"!"); NFError("Duplicate cubemap images in pack \"" + (std::string)packName + (std::string)"\"!");
if (assetName.find("_cmfront") != std::string::npos) { if (assetName.find("_cmfront") != std::string::npos) {
curr->frontData = new char[assetSize]; curr->frontData = new char[assetSize];
std::memcpy(curr->frontData, &assetContents[0], assetSize); std::memcpy(curr->frontData, &packContents[assetPos], assetSize);
curr->frontSize = assetSize; curr->frontSize = assetSize;
} }
if (assetName.find("_cmback") != std::string::npos) { if (assetName.find("_cmback") != std::string::npos) {
curr->backData = new char[assetSize]; curr->backData = new char[assetSize];
std::memcpy(curr->backData, &assetContents[0], assetSize); std::memcpy(curr->backData, &packContents[assetPos], assetSize);
curr->backSize = assetSize; curr->backSize = assetSize;
} }
if (assetName.find("_cmtop") != std::string::npos) { if (assetName.find("_cmtop") != std::string::npos) {
curr->topData = new char[assetSize]; curr->topData = new char[assetSize];
std::memcpy(curr->topData, &assetContents[0], assetSize); std::memcpy(curr->topData, &packContents[assetPos], assetSize);
curr->topSize = assetSize; curr->topSize = assetSize;
} }
if (assetName.find("_cmbottom") != std::string::npos) { if (assetName.find("_cmbottom") != std::string::npos) {
curr->bottomData = new char[assetSize]; curr->bottomData = new char[assetSize];
std::memcpy(curr->bottomData, &assetContents[0], assetSize); std::memcpy(curr->bottomData, &packContents[assetPos], assetSize);
curr->bottomSize = assetSize; curr->bottomSize = assetSize;
} }
if (assetName.find("_cmleft") != std::string::npos) { if (assetName.find("_cmleft") != std::string::npos) {
curr->leftData = new char[assetSize]; curr->leftData = new char[assetSize];
std::memcpy(curr->leftData, &assetContents[0], assetSize); std::memcpy(curr->leftData, &packContents[assetPos], assetSize);
curr->leftSize = assetSize; curr->leftSize = assetSize;
} }
if (assetName.find("_cmright") != std::string::npos) { if (assetName.find("_cmright") != std::string::npos) {
curr->rightData = new char[assetSize]; curr->rightData = new char[assetSize];
std::memcpy(curr->rightData, &assetContents[0], assetSize); std::memcpy(curr->rightData, &packContents[assetPos], assetSize);
curr->rightSize = assetSize; curr->rightSize = assetSize;
} }
assetPos += assetSize;
curr->numImages++; curr->numImages++;
if (curr->numImages == 6) if (curr->numImages == 6)
m_assets[cmName + (std::string)".cm"] = curr; m_assets[cmName + (std::string)".cm"] = curr;
cubemapCount++; cubemapFaceCount++;
continue; continue;
} }
else if (assetName.find("_buttonidle") != std::string::npos || assetName.find("_buttonhover") != std::string::npos || assetName.find("_buttonpressed") != std::string::npos) { else if (assetName.find("_buttonidle") != std::string::npos || assetName.find("_buttonhover") != std::string::npos || assetName.find("_buttonpressed") != std::string::npos) {
@ -139,30 +143,32 @@ namespace nf {
NFError("Duplicate button images in pack \"" + (std::string)packName + (std::string)"\"!"); NFError("Duplicate button images in pack \"" + (std::string)packName + (std::string)"\"!");
if (assetName.find("_buttonidle") != std::string::npos) { if (assetName.find("_buttonidle") != std::string::npos) {
curr->idleTex.data = new char[assetSize]; curr->idleTex.data = new char[assetSize];
std::memcpy(curr->idleTex.data, &assetContents[0], assetSize); std::memcpy(curr->idleTex.data, &packContents[assetPos], assetSize);
curr->idleTex.size = assetSize; curr->idleTex.size = assetSize;
} }
if (assetName.find("_buttonhover") != std::string::npos) { if (assetName.find("_buttonhover") != std::string::npos) {
curr->hoverTex.data = new char[assetSize]; curr->hoverTex.data = new char[assetSize];
std::memcpy(curr->hoverTex.data, &assetContents[0], assetSize); std::memcpy(curr->hoverTex.data, &packContents[assetPos], assetSize);
curr->hoverTex.size = assetSize; curr->hoverTex.size = assetSize;
} }
if (assetName.find("_buttonpressed") != std::string::npos) { if (assetName.find("_buttonpressed") != std::string::npos) {
curr->pressedTex.data = new char[assetSize]; curr->pressedTex.data = new char[assetSize];
std::memcpy(curr->pressedTex.data, &assetContents[0], assetSize); std::memcpy(curr->pressedTex.data, &packContents[assetPos], assetSize);
curr->pressedTex.size = assetSize; curr->pressedTex.size = assetSize;
} }
assetPos += assetSize;
curr->numImages++; curr->numImages++;
if (curr->numImages == 3) if (curr->numImages == 3)
m_assets[buttonName + (std::string)".button"] = curr; m_assets[buttonName + (std::string)".button"] = curr;
buttonCount++; buttonTextureCount++;
continue; continue;
} }
ATexture* texture = new ATexture; ATexture* texture = new ATexture;
texture->data = new char[assetSize]; texture->data = new char[assetSize];
std::memcpy(texture->data, &assetContents[0], assetSize); std::memcpy(texture->data, &packContents[assetPos], assetSize);
assetPos += assetSize;
texture->size = assetSize; texture->size = assetSize;
if (packName == "base.nfpack") if (packName == "base.nfpack")
texture->isBaseAsset = true; texture->isBaseAsset = true;
@ -172,7 +178,8 @@ namespace nf {
if (extension == "shader") { if (extension == "shader") {
AShader* shader = new AShader; AShader* shader = new AShader;
shader->data = new char[assetSize + 1]; shader->data = new char[assetSize + 1];
std::memcpy(shader->data, &assetContents[0], assetSize); std::memcpy(shader->data, &packContents[assetPos], assetSize);
assetPos += assetSize;
shader->data[assetSize] = '\0'; shader->data[assetSize] = '\0';
m_assets[assetName] = shader; m_assets[assetName] = shader;
continue; continue;
@ -180,7 +187,8 @@ namespace nf {
if (extension == "ttf") { if (extension == "ttf") {
AFont* font = new AFont; AFont* font = new AFont;
font->data = new char[assetSize]; font->data = new char[assetSize];
std::memcpy(font->data, &assetContents[0], assetSize); std::memcpy(font->data, &packContents[assetPos], assetSize);
assetPos += assetSize;
font->size = assetSize; font->size = assetSize;
if (packName == "base.nfpack") if (packName == "base.nfpack")
font->isBaseAsset = true; font->isBaseAsset = true;
@ -190,7 +198,8 @@ namespace nf {
if (extension == "ogg" || extension == "wav") { if (extension == "ogg" || extension == "wav") {
ASound* sound = new ASound; ASound* sound = new ASound;
sound->data = new char[assetSize]; sound->data = new char[assetSize];
std::memcpy(sound->data, &assetContents[0], assetSize); std::memcpy(sound->data, &packContents[assetPos], assetSize);
assetPos += assetSize;
sound->size = assetSize; sound->size = assetSize;
if (packName == "base.nfpack") if (packName == "base.nfpack")
sound->isBaseAsset = true; sound->isBaseAsset = true;
@ -199,49 +208,50 @@ namespace nf {
} }
NFError("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!"); NFError("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!");
} }
if (cubemapCount % 6 != 0)
if (cubemapFaceCount % 6 != 0)
NFError("Could not find full cubemap in pack \"" + (std::string)packName + (std::string)"\"!"); NFError("Could not find full cubemap in pack \"" + (std::string)packName + (std::string)"\"!");
if (buttonCount % 3 != 0) if (buttonTextureCount % 3 != 0)
NFError("Could not find full button set in pack \"" + (std::string)packName + (std::string)"\"!"); NFError("Could not find full button set in pack \"" + (std::string)packName + (std::string)"\"!");
while (packContentsOBJ.size()) { //Model pass after ATextures are loaded
packContentsOBJ = packContentsOBJ.substr(9);
size_t endAssetNamePos = packContentsOBJ.find_first_of('\n'); assetPos = endHeader + 10;
std::string assetName = packContentsOBJ.substr(0, endAssetNamePos); std::stringstream header2(packContents.substr(packContents.find_first_of("\n") + 1, headerLength));
packContentsOBJ = packContentsOBJ.substr(endAssetNamePos + 1); for (unsigned int i = 0; i < assetCount; i++) {
size_t extensionPos = assetName.find_first_of('.'); std::string assetName;
std::string extension = assetName.substr(extensionPos + 1); std::getline(header2, assetName);
std::string assetContents; std::string temp;
size_t nextAssetPos = packContentsOBJ.find("#NFASSET "); std::getline(header2, temp);
if (nextAssetPos != std::string::npos) { unsigned int assetSize = std::stoi(temp);
assetContents = packContentsOBJ.substr(0, nextAssetPos - 1);
packContentsOBJ = packContentsOBJ.substr(nextAssetPos); std::string extension = assetName.substr(assetName.find_last_of(".") + 1);
}
else {
assetContents = packContentsOBJ;
packContentsOBJ = "";
}
if (extension == "obj") { if (extension == "obj") {
AModel* model = new AModel; AModel* model = new AModel;
std::string textures = assetContents.substr(0, assetContents.find("\n")); std::string textures = packContents.substr(assetPos, packContents.find("/ENDTEXTURES", assetPos) - assetPos - 1);
if (textures != "none") { if (textures != "none") {
std::stringstream ss(textures); std::stringstream ss(textures);
std::string curr; std::string curr;
while (ss >> curr) { while (std::getline(ss, curr))
model->neededTextures[curr] = (ATexture*)m_assets[curr]; model->neededTextures.push_back((ATexture*)m_assets[curr]);
} }
}
assetContents = assetContents.substr(assetContents.find("\n") + 1); unsigned int newStartPos = (unsigned int)packContents.find("/ENDTEXTURES", assetPos) + 13;
size_t assetSize = assetContents.size(); assetSize -= newStartPos - assetPos;
assetPos = newStartPos;
model->data = new char[assetSize]; model->data = new char[assetSize];
std::memcpy(model->data, &assetContents[0], assetSize); std::memcpy(model->data, &packContents[assetPos], assetSize);
assetPos += assetSize;
model->size = assetSize; model->size = assetSize;
if (packName == "base.nfpack") if (packName == "base.nfpack")
model->isBaseAsset = true; model->isBaseAsset = true;
m_assets[assetName] = model; m_assets[assetName] = model;
continue; continue;
} }
assetPos += assetSize;
} }
m_loaded = true; m_loaded = true;

View File

@ -41,17 +41,15 @@ namespace nf {
std::vector<CMFace> faces; std::vector<CMFace> faces;
int tempWidth, tempHeight, tempNChannels; int tempWidth, tempHeight, tempNChannels;
unsigned char* tempData; unsigned char* tempData;
stbi_set_flip_vertically_on_load(false); stbi_set_flip_vertically_on_load(true);
tempData = stbi_load_from_memory((unsigned char*)cm.leftData, cm.leftSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.leftData, cm.leftSize, &tempWidth, &tempHeight, &tempNChannels, 0);
faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels); faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels);
tempData = stbi_load_from_memory((unsigned char*)cm.rightData, cm.rightSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.rightData, cm.rightSize, &tempWidth, &tempHeight, &tempNChannels, 0);
faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels); faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels);
stbi_set_flip_vertically_on_load(true);
tempData = stbi_load_from_memory((unsigned char*)cm.topData, cm.topSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.topData, cm.topSize, &tempWidth, &tempHeight, &tempNChannels, 0);
faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels); faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels);
tempData = stbi_load_from_memory((unsigned char*)cm.bottomData, cm.bottomSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.bottomData, cm.bottomSize, &tempWidth, &tempHeight, &tempNChannels, 0);
faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels); faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels);
stbi_set_flip_vertically_on_load(false);
tempData = stbi_load_from_memory((unsigned char*)cm.backData, cm.backSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.backData, cm.backSize, &tempWidth, &tempHeight, &tempNChannels, 0);
faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels); faces.emplace_back(tempData, tempWidth, tempHeight, tempNChannels);
tempData = stbi_load_from_memory((unsigned char*)cm.frontData, cm.frontSize, &tempWidth, &tempHeight, &tempNChannels, 0); tempData = stbi_load_from_memory((unsigned char*)cm.frontData, cm.frontSize, &tempWidth, &tempHeight, &tempNChannels, 0);

View File

@ -171,11 +171,11 @@ namespace nf {
} }
} }
void PhysicsEngine::addConvexMesh(Model* model, std::vector<float>& vertices) { void PhysicsEngine::addConvexMesh(Model* model, const float* vertices, unsigned int buffSize) {
PxConvexMeshDesc desc; PxConvexMeshDesc desc;
desc.points.count = (unsigned int)vertices.size() / 3; desc.points.count = (unsigned int)buffSize / 12;
desc.points.stride = 3 * sizeof(float); desc.points.stride = 3 * sizeof(float);
desc.points.data = &vertices[0]; desc.points.data = vertices;
desc.flags = PxConvexFlag::eCOMPUTE_CONVEX; desc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
PxDefaultMemoryOutputStream buf; PxDefaultMemoryOutputStream buf;
@ -187,14 +187,14 @@ namespace nf {
m_convexMeshes[model] = mesh; m_convexMeshes[model] = mesh;
} }
void PhysicsEngine::addTriangleMesh(Model* model, std::vector<float>& vertices, std::vector<unsigned int>& indices) { void PhysicsEngine::addTriangleMesh(Model* model, const float* vertices, unsigned int vertBuffSize, const unsigned int* indices, unsigned int indicesCount) {
PxTriangleMeshDesc desc; PxTriangleMeshDesc desc;
desc.points.count = (unsigned int)vertices.size() / 3; desc.points.count = (unsigned int)vertBuffSize / 12;
desc.points.stride = sizeof(float) * 3; desc.points.stride = sizeof(float) * 3;
desc.points.data = &vertices[0]; desc.points.data = vertices;
desc.triangles.count = (unsigned int)indices.size() / 3; desc.triangles.count = (unsigned int)indicesCount / 3;
desc.triangles.stride = sizeof(unsigned int) * 3; desc.triangles.stride = sizeof(unsigned int) * 3;
desc.triangles.data = &indices[0]; desc.triangles.data = indices;
PxDefaultMemoryOutputStream buf; PxDefaultMemoryOutputStream buf;
if (!m_cooking->cookTriangleMesh(desc, buf)) if (!m_cooking->cookTriangleMesh(desc, buf))

View File

@ -14,293 +14,105 @@
namespace nf { namespace nf {
Model::Model(AModel* model, bool physicsConvex, bool physicsTriangle) : Model::Model(AModel* model, bool physicsConvex, bool physicsTriangle) :
m_base(model->isBaseAsset), m_base(model->isBaseAsset)
m_newMtl("newmtl"),
m_newLine("\n")
{ {
if (model->neededTextures.size() > 32) if (model->neededTextures.size() > 32)
NFError("Model exceedes 32 texture limit!"); NFError("Model exceedes 32 texture limit!");
std::vector<char> file(model->data, model->data + model->size);
size_t mtlPos = std::search(file.begin(), file.end(), m_newMtl, m_newMtl + std::strlen(m_newMtl)) - file.begin();
std::vector<char> mtl(&file[mtlPos], &file[0] + file.size());
std::unordered_map<std::string, TempMaterial*> mats; std::string modelData(model->data, model->data + model->size);
parseMaterials(mats, mtl); std::string mats = modelData.substr(0, modelData.find("/ENDMATERIALS") - 1);
std::vector<char> obj(&file[0], &file[mtlPos]); createMaterials(mats, model);
std::vector<float> vbRaw, tcRaw, vnRaw;
std::string usingMat;
bool tcPresent = false, vnPresent = false; unsigned int vboSizesStart = (unsigned int)modelData.find("/ENDMATERIALS") + 14;
size_t position = 0; std::string vboSizes = modelData.substr(vboSizesStart, modelData.find("/ENDHEADER") - vboSizesStart - 1);
while (true) {
size_t nextLine = std::search(obj.begin() + position, obj.end(), m_newLine, m_newLine + std::strlen(m_newLine)) - (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) { unsigned int currPos = (unsigned int)modelData.find("/ENDHEADER") + 11;
float x = 0.0f, y = 0.0f, z = 0.0f; unsigned int currSize = 0;
ss >> x >> y >> z; std::stringstream ss(vboSizes);
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)
NFError("No texture coordinates found in model!");
if (!vnPresent)
NFError("No normals found in model!");
unsigned int vertexIndex[3], uvIndex[3], vnIndex[3]; float* pos;
char temp; unsigned int posBuffSize;
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]; unsigned int* indices;
if (ss.rdbuf()->in_avail() > 1) unsigned int indicesCount;
NFError("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++) {
glm::vec3 pos1(mats[curr]->unindexedVB[i * 9], mats[curr]->unindexedVB[i * 9 + 1], mats[curr]->unindexedVB[i * 9 + 2]);
glm::vec2 uv1(mats[curr]->unindexedTC[i * 6], mats[curr]->unindexedTC[i * 6 + 1]);
glm::vec3 pos2(mats[curr]->unindexedVB[i * 9 + 3], mats[curr]->unindexedVB[i * 9 + 4], mats[curr]->unindexedVB[i * 9 + 5]);
glm::vec2 uv2(mats[curr]->unindexedTC[i * 6 + 2], mats[curr]->unindexedTC[i * 6 + 3]);
glm::vec3 pos3(mats[curr]->unindexedVB[i * 9 + 6], mats[curr]->unindexedVB[i * 9 + 7], mats[curr]->unindexedVB[i * 9 + 8]);
glm::vec2 uv3(mats[curr]->unindexedTC[i * 6 + 4], mats[curr]->unindexedTC[i * 6 + 5]);
glm::vec3 edge1 = pos2 - pos1;
glm::vec3 edge2 = pos3 - pos1;
glm::vec2 delta1 = uv2 - uv1;
glm::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;
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;
ATexture* diffA = nullptr;
Texture* diff = nullptr;
if (curr2.diffuseTextureName.size()) {
diffA = model->neededTextures[curr2.diffuseTextureName];
diff = new Texture(diffA);
}
ATexture* specA = nullptr;
Texture* spec = nullptr;
if (curr2.specularTextureName.size()) {
specA = model->neededTextures[curr2.specularTextureName];
spec = new Texture(specA, true);
}
ATexture* normA = nullptr;
Texture* norm = nullptr;
if (curr2.normalTextureName.size()) {
normA = model->neededTextures[curr2.normalTextureName];
norm = new Texture(normA, true);
}
m_materials.push_back(std::make_tuple(diff, spec, norm, curr2.diffuseColor.x, curr2.diffuseColor.y, curr2.diffuseColor.z, 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++;
}
if (m_materials.size() > 32)
NFError("Model exceedes 32 material limit!");
m_vao = new VertexArray; m_vao = new VertexArray;
m_vao->addBuffer(&vboPositions[0], vboPositions.size() * sizeof(float)); //Positions
ss >> currSize;
pos = (float*)&modelData[currPos];
posBuffSize = currSize;
m_vao->addBuffer(&modelData[currPos], currSize);
m_vao->pushFloat(3); m_vao->pushFloat(3);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_vao->addBuffer(&vboTexCoords[0], vboTexCoords.size() * sizeof(float)); currPos += currSize;
//Texture coordinates
ss >> currSize;
m_vao->addBuffer(&modelData[currPos], currSize);
m_vao->pushFloat(2); m_vao->pushFloat(2);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_vao->addBuffer(&vboNormals[0], vboNormals.size() * sizeof(float)); currPos += currSize;
//Normals
ss >> currSize;
m_vao->addBuffer(&modelData[currPos], currSize);
m_vao->pushFloat(3); m_vao->pushFloat(3);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_vao->addBuffer(&vboTangents[0], vboTangents.size() * sizeof(float)); currPos += currSize;
//Tangents
ss >> currSize;
m_vao->addBuffer(&modelData[currPos], currSize);
m_vao->pushFloat(3); m_vao->pushFloat(3);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_vao->addBuffer(&vboMaterialIndices[0], vboMaterialIndices.size() * sizeof(int)); currPos += currSize;
//Material indices
ss >> currSize;
m_vao->addBuffer(&modelData[currPos], currSize);
m_vao->pushInt(1); m_vao->pushInt(1);
m_vao->finishBufferLayout(); m_vao->finishBufferLayout();
m_ib = new IndexBuffer(&vboIndices[0], vboIndices.size()); currPos += currSize;
//Vertex indices
ss >> currSize;
indices = (unsigned int*)&modelData[currPos];
indicesCount = currSize;
m_ib = new IndexBuffer(&modelData[currPos], currSize);
if (physicsConvex) if (physicsConvex)
Application::getApp()->getPhysicsEngine()->addConvexMesh(this, vboPositions); Application::getApp()->getPhysicsEngine()->addConvexMesh(this, pos, posBuffSize);
else if(physicsTriangle) else if(physicsTriangle)
Application::getApp()->getPhysicsEngine()->addTriangleMesh(this, vboPositions, vboIndices); Application::getApp()->getPhysicsEngine()->addTriangleMesh(this, pos, posBuffSize, indices, indicesCount);
} }
void Model::parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl) { void Model::createMaterials(const std::string& mats, AModel* model) {
std::string currMat; std::stringstream ss(mats);
size_t position = 0; std::string temp;
while (true) { std::getline(ss, temp);
size_t nextLine = std::search(mtl.begin() + position, mtl.end(), m_newLine, m_newLine + std::strlen(m_newLine)) - (mtl.begin() + position); unsigned int matCount = std::stoi(temp);
if (position + nextLine >= mtl.size()) if (matCount > 32)
break; NFError("Model exceedes 32 material limit!");
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) { for (unsigned int i = 0; i < matCount; i++) {
std::string matName; Material curr;
ss >> matName;
currMat = matName; unsigned int texIndex;
mats[currMat] = new TempMaterial;
} ss >> texIndex;
else if (std::strcmp(&firstWord[0], "Kd") == 0) { if (texIndex != 0)
float r = 0.0f, g = 0.0f, b = 0.0f; curr.diffuse = new Texture(model->neededTextures[texIndex - 1]);
ss >> r >> g >> b; else
mats[currMat]->diffuseColor = Vec3(r, g, b); curr.diffuse = nullptr;
} ss >> texIndex;
else if (std::strcmp(&firstWord[0], "map_Kd") == 0) { if (texIndex != 0)
std::string texName; curr.specular = new Texture(model->neededTextures[texIndex - 1], true);
ss >> texName; else
mats[currMat]->diffuseTextureName = texName; curr.specular = nullptr;
} ss >> texIndex;
else if (std::strcmp(&firstWord[0], "map_Ks") == 0) { if (texIndex != 0)
std::string texName; curr.normal = new Texture(model->neededTextures[texIndex - 1], true);
ss >> texName; else
mats[currMat]->specularTextureName = texName; curr.normal = nullptr;
}
else if (std::strcmp(&firstWord[0], "map_Bump") == 0) { ss >> curr.diffuseColor.x >> curr.diffuseColor.y >> curr.diffuseColor.z >> curr.shininess;
std::string texName;
ss >> texName; m_materials.push_back(curr);
mats[currMat]->normalTextureName = texName;
}
else if (std::strcmp(&firstWord[0], "Ns") == 0) {
float s = 0.0f;
ss >> s;
mats[currMat]->shininess = s;
}
} }
} }
@ -320,7 +132,7 @@ namespace nf {
for (unsigned int i = 0; i < m_materials.size(); i++) { for (unsigned int i = 0; i < m_materials.size(); i++) {
std::string currMatSuffix = std::to_string(i) + (std::string)"]"; std::string currMatSuffix = std::to_string(i) + (std::string)"]";
Texture* diff; Texture* diff;
if ((diff = std::get<0>(m_materials[i])) != nullptr) { if ((diff = m_materials[i].diffuse) != nullptr) {
shader->setUniform(m_hasDiffString + currMatSuffix, true); shader->setUniform(m_hasDiffString + currMatSuffix, true);
diff->bind(texSlot); diff->bind(texSlot);
shader->setUniform(m_diffString + currMatSuffix, texSlot); shader->setUniform(m_diffString + currMatSuffix, texSlot);
@ -328,11 +140,11 @@ namespace nf {
} }
else { else {
shader->setUniform(m_hasDiffString + currMatSuffix, false); shader->setUniform(m_hasDiffString + currMatSuffix, false);
glm::vec3 color(std::get<3>(m_materials[i]), std::get<4>(m_materials[i]), std::get<5>(m_materials[i])); glm::vec3 color(m_materials[i].diffuseColor.x, m_materials[i].diffuseColor.y, m_materials[i].diffuseColor.z);
shader->setUniform(m_diffColorString + currMatSuffix, color); shader->setUniform(m_diffColorString + currMatSuffix, color);
} }
Texture* spec; Texture* spec;
if ((spec = std::get<1>(m_materials[i])) != nullptr) { if ((spec = m_materials[i].specular) != nullptr) {
shader->setUniform(m_hasSpecString + currMatSuffix, true); shader->setUniform(m_hasSpecString + currMatSuffix, true);
spec->bind(texSlot); spec->bind(texSlot);
shader->setUniform(m_specString + currMatSuffix, texSlot); shader->setUniform(m_specString + currMatSuffix, texSlot);
@ -341,7 +153,7 @@ namespace nf {
else else
shader->setUniform(m_hasSpecString + currMatSuffix, false); shader->setUniform(m_hasSpecString + currMatSuffix, false);
Texture* norm; Texture* norm;
if ((norm = std::get<2>(m_materials[i])) != nullptr) { if ((norm = m_materials[i].normal) != nullptr) {
shader->setUniform(m_hasNormString + currMatSuffix, true); shader->setUniform(m_hasNormString + currMatSuffix, true);
norm->bind(texSlot); norm->bind(texSlot);
shader->setUniform(m_normString + currMatSuffix, texSlot); shader->setUniform(m_normString + currMatSuffix, texSlot);
@ -349,7 +161,7 @@ namespace nf {
} }
else else
shader->setUniform(m_hasNormString + currMatSuffix, false); shader->setUniform(m_hasNormString + currMatSuffix, false);
shader->setUniform(m_specPowerString + currMatSuffix, std::get<6>(m_materials[i])); shader->setUniform(m_specPowerString + currMatSuffix, m_materials[i].shininess);
} }
} }
@ -360,11 +172,11 @@ namespace nf {
Model::~Model() { Model::~Model() {
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 = m_materials[i].diffuse) != nullptr)
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr); Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
if ((curr = std::get<1>(m_materials[i])) != nullptr) if ((curr = m_materials[i].specular) != nullptr)
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr); Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
if ((curr = std::get<2>(m_materials[i])) != nullptr) if ((curr = m_materials[i].normal) != nullptr)
Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr); Application::getApp()->getCurrentState()->m_texturesToDelete.insert(curr);
} }
} }

View File

@ -1,6 +1,8 @@
#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"
@ -12,14 +14,18 @@ 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, tex->data); 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);
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

@ -160,33 +160,30 @@ namespace nf {
out.close(); out.close();
} }
std::string readFile(const std::string& filename, bool compressed) { bool readFile(const std::string& filename, std::string& out, bool assetPack) {
if (!s_dHandle) if (!s_dHandle)
CreateDecompressor(COMPRESS_ALGORITHM_XPRESS_HUFF, NULL, &s_dHandle); CreateDecompressor(COMPRESS_ALGORITHM_XPRESS_HUFF, NULL, &s_dHandle);
std::ifstream in; std::ifstream in;
in.open(filename, std::ios::binary); in.open(filename, std::ios::binary);
if (!in) if (!in)
NFError("File \"" + (std::string)filename + (std::string)"\" could not be read!"); return false;
std::stringstream ss; std::stringstream ss;
ss << in.rdbuf(); ss << in.rdbuf();
std::string read(ss.str()); out = ss.str();
if (compressed) { if (assetPack) {
size_t decompSize; size_t decompSize;
Decompress(s_dHandle, &read[0], read.size(), NULL, 0, &decompSize); Decompress(s_dHandle, &out[0], out.size(), NULL, 0, &decompSize);
char* buff = new char[decompSize]; char* buff = new char[decompSize];
Decompress(s_dHandle, &read[0], read.size(), buff, decompSize, &decompSize); Decompress(s_dHandle, &out[0], out.size(), buff, decompSize, &decompSize);
read = std::string(buff, decompSize); out = std::string(buff, decompSize);
delete[] buff; delete[] buff;
}
if (read.size() > 4 && read.substr(0, 4) == "NFEF") { for (unsigned int i = 0; i < out.size(); i++)
read = read.substr(4); out[i] = out[i] - 100;
for (unsigned int i = 0; i < read.size(); i++)
read[i] = read[i] - 100;
} }
return read; return true;
} }
} }

View File

@ -23,7 +23,7 @@ namespace nf {
struct AModel : Asset { struct AModel : Asset {
Model* loadedModel = nullptr; Model* loadedModel = nullptr;
std::unordered_map<std::string, ATexture*> neededTextures; std::vector<ATexture*> neededTextures;
~AModel() override; ~AModel() override;
}; };

View File

@ -19,34 +19,18 @@ namespace nf {
~Model(); ~Model();
private: private:
struct TempMaterial { struct Material {
std::vector<float> outVB; Texture* diffuse;
std::vector<float> unindexedVB; Texture* specular;
std::vector<unsigned int> vbIndices; Texture* normal;
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; Vec3 diffuseColor;
std::string specularTextureName;
std::string normalTextureName;
float shininess = 1.0f; float shininess = 1.0f;
}; };
void parseMaterials(std::unordered_map<std::string, TempMaterial*>& mats, std::vector<char>& mtl); void createMaterials(const std::string& mats, AModel* model);
bool m_base; bool m_base;
std::vector<std::tuple<Texture*, Texture*, Texture*, float, float, float, float>> m_materials; std::vector<Material> m_materials;
const char* m_newMtl;
const char* m_newLine;
const std::string m_hasDiffString = "hasDiffuseTex["; const std::string m_hasDiffString = "hasDiffuseTex[";
const std::string m_diffString = "diffuseTexture["; const std::string m_diffString = "diffuseTexture[";
const std::string m_diffColorString = "diffuseColor["; const std::string m_diffColorString = "diffuseColor[";

View File

@ -21,8 +21,8 @@ namespace nf {
void setActorVelocity(Entity* ent, const Vec3& vel); void setActorVelocity(Entity* ent, const Vec3& vel);
void setActorMass(Entity* ent, float mass); void setActorMass(Entity* ent, float mass);
void update(float dt); void update(float dt);
void addConvexMesh(Model* model, std::vector<float>& vertices); void addConvexMesh(Model* model, const float* vertices, unsigned int buffSize);
void addTriangleMesh(Model* model, std::vector<float>& vertices, std::vector<unsigned int>& indices); void addTriangleMesh(Model* model, const float* vertices, unsigned int vertBuffSize, const unsigned int* indices, unsigned int indicesCount);
void addActor(Entity* entity); void addActor(Entity* entity);
void closeScene(); void closeScene();

View File

@ -428,13 +428,12 @@ std::exit(-1);}
/** /**
* @brief Reads a file's bytes into an std::string * @brief Reads a file's bytes into an std::string
* @param filename Path and name of file to be read, including extensions; Relative or absolute * @param filename Path and name of file to be read, including extensions; Relative or absolute
* @param compressed Internal use only as of now * @param out The output std::string to receive the file contents
* @return An std::string containing the specified file's bytes * @param assetPack Internal use only as of now
* @return If the file was successfully read or not
* *
* This function automatically detects whether or not the target file is encrypted * This function automatically detects whether or not the target file is encrypted
* and decrypts it if it is. * and decrypts it if it is.
*
* @todo If files aren't found, the engine errors. Change this.
*/ */
std::string readFile(const std::string& filename, bool compressed = false); bool readFile(const std::string& filename, std::string& out, bool assetPack = false);
} }