Merge pull request #136 from h4570/135-obj-get-texture-names-from-mtl-file-instead-of-material-name

Fix for obj loader and dynamic pipeline
This commit is contained in:
Sandro Sobczyński
2022-08-29 19:06:22 +02:00
committed by GitHub
30 changed files with 174 additions and 152 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ EnemyManager::EnemyManager(Engine* engine, const Heightmap& heightmap) {
auto data = loader.load(FileUtils::fromCwd("game/models/zombie/zombie.obj"), auto data = loader.load(FileUtils::fromCwd("game/models/zombie/zombie.obj"),
objOptions); objOptions);
data->normalsEnabled = false; data->loadNormals = false;
motherMesh = new DynamicMesh(data.get()); motherMesh = new DynamicMesh(data.get());
bodyTexture = textureRepo->add( bodyTexture = textureRepo->add(
+1 -1
View File
@@ -28,7 +28,7 @@ Weapon::Weapon(Engine* engine) {
auto* repo = &engine->renderer.core.texture.repository; auto* repo = &engine->renderer.core.texture.repository;
auto data = auto data =
loader.load(FileUtils::fromCwd("game/models/ak47/ak47.obj"), objOptions); loader.load(FileUtils::fromCwd("game/models/ak47/ak47.obj"), objOptions);
data->normalsEnabled = false; data->loadNormals = false;
mesh = new StaticMesh(data.get()); mesh = new StaticMesh(data.get());
mesh->translation.translateX(2.85F); mesh->translation.translateX(2.85F);
+1 -1
View File
@@ -25,7 +25,7 @@ Skybox::Skybox(TextureRepository* repo) {
auto data = loader.load(FileUtils::fromCwd("game/models/skybox/skybox.obj"), auto data = loader.load(FileUtils::fromCwd("game/models/skybox/skybox.obj"),
objOptions); objOptions);
data->normalsEnabled = false; data->loadNormals = false;
mesh = new StaticMesh(data.get()); mesh = new StaticMesh(data.get());
repo->addByMesh(mesh, FileUtils::fromCwd("game/models/skybox/"), "png"); repo->addByMesh(mesh, FileUtils::fromCwd("game/models/skybox/"), "png");
+1 -1
View File
@@ -29,7 +29,7 @@ Terrain::Terrain(TextureRepository* repo)
auto data = loader.load(FileUtils::fromCwd("game/models/terrain/terrain.obj"), auto data = loader.load(FileUtils::fromCwd("game/models/terrain/terrain.obj"),
objOptions); objOptions);
data->normalsEnabled = false; data->loadNormals = false;
mesh = new StaticMesh(data.get()); mesh = new StaticMesh(data.get());
repo->addByMesh(mesh, FileUtils::fromCwd("game/models/terrain/"), "png"); repo->addByMesh(mesh, FileUtils::fromCwd("game/models/terrain/"), "png");
+5
View File
@@ -32,6 +32,11 @@ class FileUtils {
static std::string fromCwd(const std::string& relativePath); static std::string fromCwd(const std::string& relativePath);
static std::string fromCwd(const char* relativePath); static std::string fromCwd(const char* relativePath);
static std::string getFilenameFromPath(const std::string& path);
static std::string getPathFromFilename(const std::string& path);
static std::string getFilenameWithoutExtension(const std::string& filename);
static std::string getExtensionOfFilename(const std::string& filename);
const char* getElfName() const { return elfName; }; const char* getElfName() const { return elfName; };
const char* getElfPath() const { return elfPath; }; const char* getElfPath() const { return elfPath; };
@@ -28,7 +28,7 @@ class MeshBuilderData {
std::vector<MeshBuilderMaterialData*> materials; std::vector<MeshBuilderMaterialData*> materials;
bool textureCoordsEnabled, normalsEnabled, lightMapEnabled; bool loadNormals, loadLightmap;
}; };
} // namespace Tyra } // namespace Tyra
@@ -13,6 +13,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <optional>
#include "./mesh_builder_material_frame_data.hpp" #include "./mesh_builder_material_frame_data.hpp"
#include "renderer/models/color.hpp" #include "renderer/models/color.hpp"
@@ -25,6 +26,7 @@ class MeshBuilderMaterialData {
std::vector<MeshBuilderMaterialFrameData*> frames; std::vector<MeshBuilderMaterialFrameData*> frames;
std::string name; std::string name;
std::optional<std::string> texturePath;
Color ambient; Color ambient;
}; };
@@ -10,7 +10,6 @@
#pragma once #pragma once
#include "../../loader.hpp"
#include "../builder/mesh_builder_data.hpp" #include "../builder/mesh_builder_data.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
@@ -23,7 +22,7 @@ struct MD2LoaderOptions {
}; };
/** Class responsible for loading & parsing Quake's II ".md2" 3D files */ /** Class responsible for loading & parsing Quake's II ".md2" 3D files */
class MD2Loader : public Loader { class MD2Loader {
public: public:
static std::unique_ptr<MeshBuilderData> load(const char* fullpath); static std::unique_ptr<MeshBuilderData> load(const char* fullpath);
static std::unique_ptr<MeshBuilderData> load(const char* fullpath, static std::unique_ptr<MeshBuilderData> load(const char* fullpath,
@@ -10,12 +10,12 @@
#pragma once #pragma once
#include "../../loader.hpp"
#include "../builder/mesh_builder_data.hpp" #include "../builder/mesh_builder_data.hpp"
#include <string> #include <string>
#include "renderer/models/color.hpp" #include "renderer/models/color.hpp"
#include "loaders/3d/obj_loader/tiny_obj_loader.hpp" #include "loaders/3d/obj_loader/tiny_obj_loader.hpp"
#include <memory.h> #include <memory.h>
#include <optional>
namespace Tyra { namespace Tyra {
@@ -36,7 +36,7 @@ struct MaterialVertexCount {
}; };
/** Class responsible for loading & parsing obj files */ /** Class responsible for loading & parsing obj files */
class ObjLoader : public Loader { class ObjLoader {
public: public:
static std::unique_ptr<MeshBuilderData> load(const char* fullpath); static std::unique_ptr<MeshBuilderData> load(const char* fullpath);
static std::unique_ptr<MeshBuilderData> load(const char* fullpath, static std::unique_ptr<MeshBuilderData> load(const char* fullpath,
-25
View File
@@ -1,25 +0,0 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#pragma once
#include <string>
namespace Tyra {
class Loader {
protected:
static std::string getFilenameFromPath(const std::string& path);
static std::string getPathFromFilename(const std::string& path);
static std::string getFilenameWithoutExtension(const std::string& filename);
static std::string getExtensionOfFilename(const std::string& filename);
};
} // namespace Tyra
@@ -10,13 +10,12 @@
#pragma once #pragma once
#include "loaders/loader.hpp"
#include "loaders/texture/builder/texture_builder_data.hpp" #include "loaders/texture/builder/texture_builder_data.hpp"
#include "renderer/core/texture/models/texture_bpp.hpp" #include "renderer/core/texture/models/texture_bpp.hpp"
#include <string> #include <string>
namespace Tyra { namespace Tyra {
class TextureLoader : public Loader { class TextureLoader {
public: public:
/** /**
* @brief Loads texture data from file. * @brief Loads texture data from file.
@@ -13,6 +13,7 @@
#include "debug/debug.hpp" #include "debug/debug.hpp"
#include "./mesh_material_frame.hpp" #include "./mesh_material_frame.hpp"
#include "loaders/3d/builder/mesh_builder_data.hpp" #include "loaders/3d/builder/mesh_builder_data.hpp"
#include <optional>
namespace Tyra { namespace Tyra {
@@ -23,11 +24,9 @@ class MeshMaterial {
~MeshMaterial(); ~MeshMaterial();
bool isMother, lightmapFlag; bool isMother, lightmapFlag;
u32 id; u32 id;
std::string name; std::string name;
std::optional<std::string> textureName;
Color ambient; Color ambient;
std::vector<MeshMaterialFrame*> frames; std::vector<MeshMaterialFrame*> frames;
@@ -44,8 +44,7 @@ class DynPipRenderer {
void uploadPrograms(); void uploadPrograms();
void setDoubleBuffer(); void setDoubleBuffer();
void addBufferDataToPacket(DynPipVU1Program* program, DynPipBag** bags, void addBufferDataToPacket(DynPipBag** bags, const u32& count);
const u32& count);
void sendPacket(); void sendPacket();
prim_t* prim; prim_t* prim;
@@ -59,7 +59,7 @@ class DynamicPipeline : public Renderer3DPipeline {
void setBuffer(DynPipBag* buffers, DynPipBag* buffer, u16* bufferIndex); void setBuffer(DynPipBag* buffers, DynPipBag* buffer, u16* bufferIndex);
void sendRestOfBuffers(DynPipBag* buffers, u16* bufferIndex); void sendRestOfBuffers(DynPipBag* buffers, const u16& bufferIndex);
void addVertices(const MeshMaterialFrame* materialFrameFrom, void addVertices(const MeshMaterialFrame* materialFrameFrom,
const MeshMaterialFrame* materialFrameTo, DynPipBag* bag, const MeshMaterialFrame* materialFrameTo, DynPipBag* bag,
+28
View File
@@ -64,4 +64,32 @@ std::string FileUtils::fromCwd(const char* file) {
auto cwd = getCwd(); auto cwd = getCwd();
return cwd + file; return cwd + file;
} }
std::string FileUtils::getFilenameFromPath(const std::string& path) {
std::string filename = path.substr(path.find_last_of("/\\") + 1);
if (filename.size() == path.size()) {
filename = path.substr(path.find_last_of(":\\") + 1);
}
return filename;
}
std::string FileUtils::getPathFromFilename(const std::string& path) {
std::string basepath = path.substr(0, path.find_last_of("/\\"));
if (basepath.size() == path.size()) {
basepath = path.substr(0, path.find_last_of(":\\"));
}
return basepath;
}
std::string FileUtils::getFilenameWithoutExtension(
const std::string& filename) {
auto lastindex = filename.find_last_of(".");
return filename.substr(0, lastindex);
}
std::string FileUtils::getExtensionOfFilename(const std::string& filename) {
auto lastindex = filename.find_last_of(".");
return filename.substr(lastindex + 1);
}
} // namespace Tyra } // namespace Tyra
@@ -14,9 +14,8 @@
namespace Tyra { namespace Tyra {
MeshBuilderData::MeshBuilderData() { MeshBuilderData::MeshBuilderData() {
textureCoordsEnabled = false; loadNormals = false;
normalsEnabled = false; loadLightmap = false;
lightMapEnabled = false;
} }
MeshBuilderData::~MeshBuilderData() { MeshBuilderData::~MeshBuilderData() {
@@ -13,7 +13,7 @@
#include <string> #include <string>
#include "debug/debug.hpp" #include "debug/debug.hpp"
#include "loaders/3d/md2_loader/anorms.hpp" #include "loaders/3d/md2_loader/anorms.hpp"
#include "loaders/loader.hpp" #include "file/file_utils.hpp"
namespace Tyra { namespace Tyra {
@@ -88,7 +88,7 @@ std::unique_ptr<MeshBuilderData> MD2Loader::load(const char* fullpath,
std::string path = fullpath; std::string path = fullpath;
TYRA_ASSERT(!path.empty(), "Provided path is empty!"); TYRA_ASSERT(!path.empty(), "Provided path is empty!");
auto filename = getFilenameFromPath(path); auto filename = FileUtils::getFilenameFromPath(path);
FILE* file = fopen(fullpath, "rb"); FILE* file = fopen(fullpath, "rb");
TYRA_ASSERT(file != nullptr, "Failed to load: ", filename); TYRA_ASSERT(file != nullptr, "Failed to load: ", filename);
@@ -122,12 +122,13 @@ std::unique_ptr<MeshBuilderData> MD2Loader::load(const char* fullpath,
auto result = std::make_unique<MeshBuilderData>(); auto result = std::make_unique<MeshBuilderData>();
auto* material = new MeshBuilderMaterialData(); auto* material = new MeshBuilderMaterialData();
material->name = getFilenameWithoutExtension(filename); material->name = FileUtils::getFilenameWithoutExtension(filename);
material->texturePath = material->name;
material->texturePath.value().append(".png");
result->materials.push_back(material); result->materials.push_back(material);
result->normalsEnabled = true; result->loadNormals = true;
result->textureCoordsEnabled = true; result->loadLightmap = false;
result->lightMapEnabled = false;
Vec4** tempVertices = new Vec4*[framesCount]; Vec4** tempVertices = new Vec4*[framesCount];
Vec4** tempNormals = new Vec4*[framesCount]; Vec4** tempNormals = new Vec4*[framesCount];
+34 -10
View File
@@ -10,13 +10,13 @@
#include <cstring> #include <cstring>
#include <stdio.h> #include <stdio.h>
#include <string>
#include <vector> #include <vector>
#include "math/vec2.hpp" #include "math/vec2.hpp"
#include "math/vec4.hpp" #include "math/vec4.hpp"
#include "renderer/models/color.hpp" #include "renderer/models/color.hpp"
#include "debug/debug.hpp" #include "debug/debug.hpp"
#include "loaders/3d/obj_loader/obj_loader.hpp" #include "loaders/3d/obj_loader/obj_loader.hpp"
#include "file/file_utils.hpp"
#define TINYOBJLOADER_USE_MAPBOX_EARCUT #define TINYOBJLOADER_USE_MAPBOX_EARCUT
#define TINYOBJLOADER_IMPLEMENTATION #define TINYOBJLOADER_IMPLEMENTATION
@@ -40,12 +40,12 @@ std::unique_ptr<MeshBuilderData> ObjLoader::load(
std::unique_ptr<MeshBuilderData> ObjLoader::load( std::unique_ptr<MeshBuilderData> ObjLoader::load(
const char* fullpath, const ObjLoaderOptions& options) { const char* fullpath, const ObjLoaderOptions& options) {
std::string path = fullpath; std::string path = fullpath;
std::string basePath = getPathFromFilename(path); std::string basePath = FileUtils::getPathFromFilename(path);
TYRA_ASSERT(!path.empty(), "Provided path is empty!"); TYRA_ASSERT(!path.empty(), "Provided path is empty!");
auto rawFilename = getFilenameWithoutExtension(path); auto rawFilename = FileUtils::getFilenameWithoutExtension(path);
auto extension = getExtensionOfFilename(path); auto extension = FileUtils::getExtensionOfFilename(path);
auto result = std::make_unique<MeshBuilderData>(); auto result = std::make_unique<MeshBuilderData>();
tinyobj::ObjReaderConfig readerConfig; tinyobj::ObjReaderConfig readerConfig;
@@ -131,9 +131,7 @@ void ObjLoader::addOutputMaterialsAndFrames(
const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::shape_t>& shapes,
const std::vector<tinyobj::material_t>& materials, const u16& framesCount, const std::vector<tinyobj::material_t>& materials, const u16& framesCount,
std::vector<MaterialVertexCount>& materialVertexCounts) { std::vector<MaterialVertexCount>& materialVertexCounts) {
if (attrib.texcoords.size()) output->textureCoordsEnabled = true; if (attrib.normals.size()) output->loadNormals = true;
if (attrib.normals.size()) output->normalsEnabled = true;
TYRA_ASSERT(materials.size() > 0, TYRA_ASSERT(materials.size() > 0,
"No material data found! Please add .mtl " "No material data found! Please add .mtl "
@@ -145,6 +143,10 @@ void ObjLoader::addOutputMaterialsAndFrames(
material->name = materials[i].name; material->name = materials[i].name;
if (!materials[i].diffuse_texname.empty()) {
material->texturePath = materials[i].diffuse_texname;
}
material->ambient.set(materials[i].diffuse[0] * 128.0F, material->ambient.set(materials[i].diffuse[0] * 128.0F,
materials[i].diffuse[1] * 128.0F, materials[i].diffuse[1] * 128.0F,
materials[i].diffuse[2] * 128.0F, 128.0F); materials[i].diffuse[2] * 128.0F, 128.0F);
@@ -157,10 +159,11 @@ void ObjLoader::addOutputMaterialsAndFrames(
frame->count = counter.count; frame->count = counter.count;
frame->vertices = new Vec4[counter.count]; frame->vertices = new Vec4[counter.count];
if (output->textureCoordsEnabled) if (material->texturePath.has_value()) {
frame->textureCoords = new Vec4[counter.count]; frame->textureCoords = new Vec4[counter.count];
}
if (output->normalsEnabled) frame->normals = new Vec4[counter.count]; if (output->loadNormals) frame->normals = new Vec4[counter.count];
material->frames.push_back(frame); material->frames.push_back(frame);
} }
@@ -186,6 +189,8 @@ void ObjLoader::importFrame(MeshBuilderData* output,
materialInsertControls.push_back(control); materialInsertControls.push_back(control);
} }
std::vector<u32> materialIdsWithTextureWarning;
// Loop over shapes // Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) { for (size_t s = 0; s < shapes.size(); s++) {
const auto& mesh = shapes[s].mesh; const auto& mesh = shapes[s].mesh;
@@ -197,7 +202,8 @@ void ObjLoader::importFrame(MeshBuilderData* output,
auto& materialInsertControl = materialInsertControls[materialId]; auto& materialInsertControl = materialInsertControls[materialId];
size_t vertCountPerFace = size_t(mesh.num_face_vertices[f]); size_t vertCountPerFace = size_t(mesh.num_face_vertices[f]);
auto* outFrame = output->materials[materialId]->frames[frameIndex]; auto* outMaterial = output->materials[materialId];
auto* outFrame = outMaterial->frames[frameIndex];
TYRA_ASSERT(count == 1 || vertCountPerFace == 3, TYRA_ASSERT(count == 1 || vertCountPerFace == 3,
"Please triangulate obj files if you are animating!", "Please triangulate obj files if you are animating!",
@@ -232,6 +238,7 @@ void ObjLoader::importFrame(MeshBuilderData* output,
// Check if `texcoord_index` is zero or positive. negative = // Check if `texcoord_index` is zero or positive. negative =
// notexcoord data // notexcoord data
if (idx.texcoord_index >= 0) { if (idx.texcoord_index >= 0) {
if (outMaterial->texturePath.has_value()) {
tinyobj::real_t tx = tinyobj::real_t tx =
attrib.texcoords[2 * size_t(idx.texcoord_index) + 0]; attrib.texcoords[2 * size_t(idx.texcoord_index) + 0];
tinyobj::real_t ty = tinyobj::real_t ty =
@@ -240,6 +247,23 @@ void ObjLoader::importFrame(MeshBuilderData* output,
auto finalY = invertY ? 1.0F - ty : ty; auto finalY = invertY ? 1.0F - ty : ty;
outFrame->textureCoords[materialInsertControl.inserted].set( outFrame->textureCoords[materialInsertControl.inserted].set(
tx, finalY, 1.0F, 0.0F); tx, finalY, 1.0F, 0.0F);
} else {
auto warningWasNotPrinted =
std::find(materialIdsWithTextureWarning.begin(),
materialIdsWithTextureWarning.end(),
materialId) == materialIdsWithTextureWarning.end();
if (frameIndex == 0 && warningWasNotPrinted) {
materialIdsWithTextureWarning.push_back(materialId);
TYRA_WARN(
"Material \"", outMaterial->name,
"\" has texture coordinates, but texture path was not found "
"in .mtl file! ",
"Please consider adding texture path to map_Kd field in .mtl "
"file!");
}
}
} }
materialInsertControl.inserted++; materialInsertControl.inserted++;
-42
View File
@@ -1,42 +0,0 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "loaders/loader.hpp"
namespace Tyra {
std::string Loader::getFilenameFromPath(const std::string& path) {
std::string filename = path.substr(path.find_last_of("/\\") + 1);
if (filename.size() == path.size()) {
filename = path.substr(path.find_last_of(":\\") + 1);
}
return filename;
}
std::string Loader::getPathFromFilename(const std::string& path) {
std::string basepath = path.substr(0, path.find_last_of("/\\"));
if (basepath.size() == path.size()) {
basepath = path.substr(0, path.find_last_of(":\\"));
}
return basepath;
}
std::string Loader::getFilenameWithoutExtension(const std::string& filename) {
auto lastindex = filename.find_last_of(".");
return filename.substr(0, lastindex);
}
std::string Loader::getExtensionOfFilename(const std::string& filename) {
auto lastindex = filename.find_last_of(".");
return filename.substr(lastindex + 1);
}
} // namespace Tyra
+2 -1
View File
@@ -16,6 +16,7 @@
#include <string> #include <string>
#include <draw_buffers.h> #include <draw_buffers.h>
#include "loaders/texture/png_loader.hpp" #include "loaders/texture/png_loader.hpp"
#include "file/file_utils.hpp"
namespace Tyra { namespace Tyra {
@@ -32,7 +33,7 @@ TextureBuilderData* PngLoader::load(const char* fullPath) {
std::string path = fullPath; std::string path = fullPath;
TYRA_ASSERT(!path.empty(), "Provided path is empty!"); TYRA_ASSERT(!path.empty(), "Provided path is empty!");
auto filename = getFilenameFromPath(path); auto filename = FileUtils::getFilenameFromPath(path);
FILE* file = fopen(fullPath, "rb"); FILE* file = fopen(fullPath, "rb");
TYRA_ASSERT(file != nullptr, "Failed to load ", fullPath); TYRA_ASSERT(file != nullptr, "Failed to load ", fullPath);
+18 -5
View File
@@ -14,6 +14,7 @@
#include <cstdlib> #include <cstdlib>
#include <iomanip> #include <iomanip>
#include "renderer/3d/mesh/mesh_material.hpp" #include "renderer/3d/mesh/mesh_material.hpp"
#include "file/file_utils.hpp"
namespace Tyra { namespace Tyra {
@@ -29,7 +30,7 @@ MeshMaterial::MeshMaterial(const MeshBuilderData& data,
id = rand() % 1000000; id = rand() % 1000000;
if (data.lightMapEnabled) { if (data.loadLightmap) {
lightmapFlag = true; lightmapFlag = true;
TYRA_ASSERT(material->frames[0]->colors != nullptr, TYRA_ASSERT(material->frames[0]->colors != nullptr,
"Colors faces are required"); "Colors faces are required");
@@ -38,8 +39,15 @@ MeshMaterial::MeshMaterial(const MeshBuilderData& data,
} }
ambient.set(material->ambient); ambient.set(material->ambient);
name = material->name; name = material->name;
if (material->texturePath.has_value()) {
auto textureFilename =
FileUtils::getFilenameFromPath(material->texturePath.value());
textureName = FileUtils::getFilenameWithoutExtension(textureFilename);
}
TYRA_ASSERT(name.length() > 0, "MeshMaterial name cannot be empty"); TYRA_ASSERT(name.length() > 0, "MeshMaterial name cannot be empty");
u32 lastVertexCount = 0; u32 lastVertexCount = 0;
@@ -71,7 +79,7 @@ MeshMaterial::MeshMaterial(const MeshMaterial& mesh) {
lightmapFlag = mesh.lightmapFlag; lightmapFlag = mesh.lightmapFlag;
name = mesh.name; name = mesh.name;
textureName = mesh.textureName;
ambient.set(128.0F, 128.0F, 128.0F, 128.0F); ambient.set(128.0F, 128.0F, 128.0F, 128.0F);
for (u32 i = 0; i < mesh.frames.size(); i++) { for (u32 i = 0; i < mesh.frames.size(); i++) {
@@ -112,9 +120,14 @@ std::string MeshMaterial::getPrint(const char* name) const {
res << std::endl; res << std::endl;
res << std::fixed << std::setprecision(2); res << std::fixed << std::setprecision(2);
res << "Id: " << id << ", " << std::endl; res << "Id: " << id << ", " << std::endl;
res << "Name: " << name << ", " << std::endl; res << "Name: " << this->name << ", " << std::endl;
if (textureName.has_value()) {
res << "Texture path: " << textureName.value() << ", " << std::endl;
}
res << "Frames count: " << frames.size() << ", " << std::endl; res << "Frames count: " << frames.size() << ", " << std::endl;
res << "Single color?: " << static_cast<u32>(lightmapFlag) << std::endl; res << "Lightmap?: " << static_cast<u32>(lightmapFlag) << std::endl;
res << ")"; res << ")";
return res.str(); return res.str();
@@ -36,11 +36,12 @@ MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data,
TYRA_ASSERT(frame->count > 0, "Vertex count must be greater than 0", TYRA_ASSERT(frame->count > 0, "Vertex count must be greater than 0",
"Material name: ", material->name); "Material name: ", material->name);
TYRA_ASSERT(frame->vertices != nullptr, "Vertex array can't be null"); TYRA_ASSERT(frame->vertices != nullptr, "Vertex array can't be null");
TYRA_ASSERT(!data.normalsEnabled || frame->normals != nullptr, TYRA_ASSERT(!data.loadNormals || frame->normals != nullptr,
"Normal array can't be null"); "Normal array can't be null");
TYRA_ASSERT(!data.textureCoordsEnabled || frame->textureCoords != nullptr, TYRA_ASSERT(
!material->texturePath.has_value() || frame->textureCoords != nullptr,
"Texture coordinate array can't be null"); "Texture coordinate array can't be null");
TYRA_ASSERT(!data.lightMapEnabled || frame->colors != nullptr, TYRA_ASSERT(!data.loadLightmap || frame->colors != nullptr,
"Color array can't be null"); "Color array can't be null");
bbox = new BBox(frame->vertices, frame->count); bbox = new BBox(frame->vertices, frame->count);
@@ -48,7 +49,7 @@ MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data,
count = frame->count; count = frame->count;
vertices = frame->vertices; vertices = frame->vertices;
if (data.normalsEnabled) { if (data.loadNormals) {
normals = frame->normals; normals = frame->normals;
} else { } else {
if (frame->normals != nullptr) delete[] frame->normals; if (frame->normals != nullptr) delete[] frame->normals;
@@ -56,7 +57,7 @@ MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data,
normals = nullptr; normals = nullptr;
} }
if (data.textureCoordsEnabled) { if (material->texturePath.has_value()) {
textureCoords = frame->textureCoords; textureCoords = frame->textureCoords;
} else { } else {
if (frame->textureCoords != nullptr) delete[] frame->textureCoords; if (frame->textureCoords != nullptr) delete[] frame->textureCoords;
@@ -64,7 +65,7 @@ MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data,
textureCoords = nullptr; textureCoords = nullptr;
} }
if (data.lightMapEnabled) { if (data.loadLightmap) {
colors = frame->colors; colors = frame->colors;
} else { } else {
if (frame->colors != nullptr) delete[] frame->colors; if (frame->colors != nullptr) delete[] frame->colors;
@@ -160,19 +160,19 @@ void DynPipRenderer::sendObjectData(
void DynPipRenderer::render(DynPipBag** bags, const u32& count) { void DynPipRenderer::render(DynPipBag** bags, const u32& count) {
if (count <= 0) return; if (count <= 0) return;
auto* program = programsRepo->getProgramByBag(bags[0]); addBufferDataToPacket(bags, count);
addBufferDataToPacket(program, bags, count);
sendPacket(); sendPacket();
} }
void DynPipRenderer::addBufferDataToPacket(DynPipVU1Program* program, void DynPipRenderer::addBufferDataToPacket(DynPipBag** bags, const u32& count) {
DynPipBag** bags, const u32& count) {
currentPacket = packets[context]; currentPacket = packets[context];
packet2_reset(currentPacket, false); packet2_reset(currentPacket, false);
for (u32 i = 0; i < count; i++) { for (u32 i = 0; i < count; i++) {
if (bags[i]->count <= 0) continue; if (bags[i]->count <= 0) continue;
auto* program = programsRepo->getProgramByBag(bags[i]);
program->addBufferDataToPacket(currentPacket, bags[i], prim); program->addBufferDataToPacket(currentPacket, bags[i], prim);
if (lastProgramName != program->getName()) { if (lastProgramName != program->getName()) {
@@ -35,6 +35,11 @@ void DynamicPipeline::onUse() {
buffers = new DynPipBag[buffersCount]; buffers = new DynPipBag[buffersCount];
for (u32 i = 0; i < buffersCount; i++) {
buffers[i].texture = nullptr;
buffers[i].lighting = nullptr;
}
auto packetSize = auto packetSize =
buffersCount * 5.1F; // 5.1 = packet2_get_qw_count / buffersCount buffersCount * 5.1F; // 5.1 = packet2_get_qw_count / buffersCount
@@ -96,11 +101,12 @@ void DynamicPipeline::render(const DynamicMesh* mesh,
for (u32 i = 0; i < mesh->materials.size(); i++) { for (u32 i = 0; i < mesh->materials.size(); i++) {
auto* material = mesh->materials[i]; auto* material = mesh->materials[i];
auto* frameFrom = material->frames[mesh->animation.getState().currentFrame]; auto* frameFrom = material->frames[mesh->animation.getState().currentFrame];
auto* frameTo = material->frames[mesh->animation.getState().nextFrame]; auto* frameTo = material->frames[mesh->animation.getState().nextFrame];
auto partSize = core.getMaxVertCountByParams( auto partSize = core.getMaxVertCountByParams(
options && options->lighting, material->frames[0]->textureCoords); options && options->lighting, material->textureName.has_value());
u32 partsCount = ceil(frameFrom->count / static_cast<float>(partSize)); u32 partsCount = ceil(frameFrom->count / static_cast<float>(partSize));
@@ -109,13 +115,17 @@ void DynamicPipeline::render(const DynamicMesh* mesh,
setBuffersColorBag(buffers, colorBag); setBuffersColorBag(buffers, colorBag);
u8 isPartInitialized = false; u8 isPartInitialized = false;
auto* texture = Texture* texture = nullptr;
if (material->textureName.has_value()) {
texture =
rendererCore->texture.repository.getByMeshMaterialId(material->id); rendererCore->texture.repository.getByMeshMaterialId(material->id);
TYRA_ASSERT(texture, "Texture for material: ", material->name, TYRA_ASSERT(texture, "Texture for material: ", material->name,
"Id: ", material->id, "Id: ", material->id,
"Was not found in texture repository! Did you forget to add " "Was not found in texture repository! Did you forget to add "
"texture or disable texture coords loading in mesh?"); "texture or disable texture coords loading in mesh?");
}
for (u32 k = 0; k < partsCount; k++) { for (u32 k = 0; k < partsCount; k++) {
auto& buffer = buffers[bufferIndex]; auto& buffer = buffers[bufferIndex];
@@ -127,6 +137,7 @@ void DynamicPipeline::render(const DynamicMesh* mesh,
u32 startIndex = k * partSize; u32 startIndex = k * partSize;
addVertices(frameFrom, frameTo, &buffer, startIndex); addVertices(frameFrom, frameTo, &buffer, startIndex);
buffer.texture = getTextureBag(texture, frameFrom, frameTo, startIndex); buffer.texture = getTextureBag(texture, frameFrom, frameTo, startIndex);
buffer.lighting = getLightingBag(frameFrom, frameTo, &model, options, buffer.lighting = getLightingBag(frameFrom, frameTo, &model, options,
dirLights, startIndex); dirLights, startIndex);
@@ -139,11 +150,13 @@ void DynamicPipeline::render(const DynamicMesh* mesh,
setBuffer(buffers, &buffer, &bufferIndex); setBuffer(buffers, &buffer, &bufferIndex);
} }
sendRestOfBuffers(buffers, bufferIndex);
bufferIndex = 0;
core.begin(infoBag);
delete colorBag; delete colorBag;
} }
sendRestOfBuffers(buffers, &bufferIndex);
if (dirLights) { if (dirLights) {
delete dirLights; delete dirLights;
} }
@@ -177,11 +190,12 @@ void DynamicPipeline::setBuffer(DynPipBag* buffers, DynPipBag* buffer,
*bufferIndex += 1; *bufferIndex += 1;
} }
void DynamicPipeline::sendRestOfBuffers(DynPipBag* buffers, u16* bufferIndex) { void DynamicPipeline::sendRestOfBuffers(DynPipBag* buffers,
auto isEndOf1stDBuffer = *bufferIndex <= halfBuffersCount - 1; const u16& bufferIndex) {
auto isEndOf1stDBuffer = bufferIndex <= halfBuffersCount - 1;
u32 offset = isEndOf1stDBuffer ? 0 : halfBuffersCount; u32 offset = isEndOf1stDBuffer ? 0 : halfBuffersCount;
u32 size = *bufferIndex - offset; u32 size = bufferIndex - offset;
if (size <= 0) return; if (size <= 0) return;
@@ -258,7 +272,7 @@ DynPipColorBag* DynamicPipeline::getColorBag(
DynPipTextureBag* DynamicPipeline::getTextureBag( DynPipTextureBag* DynamicPipeline::getTextureBag(
Texture* texture, const MeshMaterialFrame* materialFrameFrom, Texture* texture, const MeshMaterialFrame* materialFrameFrom,
const MeshMaterialFrame* materialFrameTo, const u32& startIndex) { const MeshMaterialFrame* materialFrameTo, const u32& startIndex) {
if (!materialFrameFrom->textureCoords) return nullptr; if (!materialFrameFrom->textureCoords || texture == nullptr) return nullptr;
auto* result = new DynPipTextureBag(); auto* result = new DynPipTextureBag();
@@ -65,6 +65,7 @@ void StaticPipeline::render(const StaticMesh* mesh,
!(options->frustumCulling != PipelineFrustumCulling_Precise && !(options->frustumCulling != PipelineFrustumCulling_Precise &&
infoBag->fullClipChecks == true), infoBag->fullClipChecks == true),
"Full clip checks are only supported with frustum culling == Precise!"); "Full clip checks are only supported with frustum culling == Precise!");
TYRA_ASSERT(options->transformationType == TyraMVP || TYRA_ASSERT(options->transformationType == TyraMVP ||
(!options->fullClipChecks && (!options->fullClipChecks &&
options->frustumCulling == PipelineFrustumCulling_None), options->frustumCulling == PipelineFrustumCulling_None),
@@ -146,7 +147,8 @@ StaPipColorBag* StaticPipeline::getColorBag(
StaPipTextureBag* StaticPipeline::getTextureBag( StaPipTextureBag* StaticPipeline::getTextureBag(
const MeshMaterial* material, const MeshMaterialFrame* materialFrame) { const MeshMaterial* material, const MeshMaterialFrame* materialFrame) {
if (!materialFrame->textureCoords) return nullptr; if (!materialFrame->textureCoords || !material->textureName.has_value())
return nullptr;
auto* result = new StaPipTextureBag(); auto* result = new StaPipTextureBag();
@@ -116,8 +116,12 @@ void TextureRepository::addByMesh(const Mesh* mesh, const char* directory,
if (dirFixed.back() != '/' && dirFixed.back() != ':') dirFixed += "/"; if (dirFixed.back() != '/' && dirFixed.back() != ':') dirFixed += "/";
for (u32 i = 0; i < mesh->materials.size(); i++) { for (u32 i = 0; i < mesh->materials.size(); i++) {
if (!mesh->materials[i]->textureName.has_value()) {
continue;
}
std::string fullPath = std::string fullPath =
dirFixed + mesh->materials[i]->name + "." + extension; dirFixed + mesh->materials[i]->textureName.value() + "." + extension;
auto* data = loader.load(fullPath.c_str()); auto* data = loader.load(fullPath.c_str());
Texture* texture = new Texture(data); Texture* texture = new Texture(data);
+4 -3
View File
@@ -51,7 +51,7 @@ void Tutorial04::loadMesh() {
/** /**
* Load mesh data * Load mesh data
* Texture names are the material names "usemtl <material name>" * Texture file names are loaded from .mtl file (map_Kd field).
*/ */
auto data = auto data =
ObjLoader::load(FileUtils::fromCwd("de_dust2/de_dust2.obj"), options); ObjLoader::load(FileUtils::fromCwd("de_dust2/de_dust2.obj"), options);
@@ -67,8 +67,9 @@ void Tutorial04::loadMesh() {
renderOptions.frustumCulling = Tyra::PipelineFrustumCulling_None; renderOptions.frustumCulling = Tyra::PipelineFrustumCulling_None;
/** /**
* Function which load all textures into texture repository, * Function which load all textures into texture repository.
* based on material names. * It will automatically extract filename from path (map_Kd) and add
* proper extension.
*/ */
engine->renderer.getTextureRepository().addByMesh( engine->renderer.getTextureRepository().addByMesh(
mesh.get(), FileUtils::fromCwd("de_dust2/"), "png"); mesh.get(), FileUtils::fromCwd("de_dust2/"), "png");
@@ -21,6 +21,8 @@ Tutorial05::~Tutorial05() {
} }
void Tutorial05::init() { void Tutorial05::init() {
engine->renderer.setClearScreenColor(Color(32.0F, 32.0F, 32.0F));
dynpip.setRenderer(&engine->renderer.core); dynpip.setRenderer(&engine->renderer.core);
cameraPosition = Vec4(0.0F, 0.0F, -10.0F); cameraPosition = Vec4(0.0F, 0.0F, -10.0F);
+3 -6
View File
@@ -76,12 +76,9 @@ void Tutorial07::loadMeshWithLightmap() {
auto data = ObjLoader::load(FileUtils::fromCwd("cup.obj"), options); auto data = ObjLoader::load(FileUtils::fromCwd("cup.obj"), options);
/** /**
* We don't want to load texture coordinates, * This model has no texture (it was exported without UV data),
* because this obj file has no texture. * but you can use lighting with textures as well.
*
* Anyways you can use texture as well.
*/ */
data->textureCoordsEnabled = false;
/** Lets add lightmap manually */ /** Lets add lightmap manually */
setLightmap(data.get()); setLightmap(data.get());
@@ -120,7 +117,7 @@ void Tutorial07::setDirectionalLightsOptions() {
void Tutorial07::setLightmap(MeshBuilderData* data) { void Tutorial07::setLightmap(MeshBuilderData* data) {
/** Information for mesh, that data has lightmap */ /** Information for mesh, that data has lightmap */
data->lightMapEnabled = true; data->loadLightmap = true;
/** This object file has only 1 material */ /** This object file has only 1 material */
auto* material = data->materials[0]; auto* material = data->materials[0];
@@ -92,7 +92,6 @@ void Tutorial08::loadCupMesh() {
options.scale = 3.0F; options.scale = 3.0F;
auto data = ObjLoader::load(FileUtils::fromCwd("cup/cup.obj"), options); auto data = ObjLoader::load(FileUtils::fromCwd("cup/cup.obj"), options);
data->textureCoordsEnabled = false;
cupMesh = std::make_unique<StaticMesh>(data.get()); cupMesh = std::make_unique<StaticMesh>(data.get());