Created a crate model in glb and obj format to use in the tests, then finished the model test.
This commit is contained in:
parent
c6a7c42a4e
commit
2431cf8c97
9 changed files with 125 additions and 51 deletions
BIN
14-refactor/assets/container2.png
Normal file
BIN
14-refactor/assets/container2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 457 KiB |
1
14-refactor/assets/crate.bbmodel
Normal file
1
14-refactor/assets/crate.bbmodel
Normal file
File diff suppressed because one or more lines are too long
BIN
14-refactor/assets/crate.glb
Normal file
BIN
14-refactor/assets/crate.glb
Normal file
Binary file not shown.
4
14-refactor/assets/crate.mtl
Normal file
4
14-refactor/assets/crate.mtl
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Made in Blockbench 5.1.6
|
||||||
|
newmtl m_cd2bce81-4f84-6efd-a971-2b9e91f19e2f
|
||||||
|
map_Kd container2.png
|
||||||
|
newmtl none
|
||||||
49
14-refactor/assets/crate.obj
Normal file
49
14-refactor/assets/crate.obj
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Made in Blockbench 5.1.6
|
||||||
|
mtllib crate.mtl
|
||||||
|
|
||||||
|
o cube
|
||||||
|
v 0.1875 0.4375 0.375
|
||||||
|
v 0.1875 0.4375 -0.0625
|
||||||
|
v 0.1875 0 0.375
|
||||||
|
v 0.1875 0 -0.0625
|
||||||
|
v -0.25 0.4375 -0.0625
|
||||||
|
v -0.25 0.4375 0.375
|
||||||
|
v -0.25 0 -0.0625
|
||||||
|
v -0.25 0 0.375
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 0 0
|
||||||
|
vn 0 0 -1
|
||||||
|
vn 1 0 0
|
||||||
|
vn 0 0 1
|
||||||
|
vn -1 0 0
|
||||||
|
vn 0 1 0
|
||||||
|
vn 0 -1 0
|
||||||
|
usemtl m_cd2bce81-4f84-6efd-a971-2b9e91f19e2f
|
||||||
|
f 4/4/1 7/3/1 5/2/1 2/1/1
|
||||||
|
f 3/8/2 4/7/2 2/6/2 1/5/2
|
||||||
|
f 8/12/3 3/11/3 1/10/3 6/9/3
|
||||||
|
f 7/16/4 8/15/4 6/14/4 5/13/4
|
||||||
|
f 6/20/5 1/19/5 2/18/5 5/17/5
|
||||||
|
f 7/24/6 4/23/6 3/22/6 8/21/6
|
||||||
|
|
@ -209,7 +209,7 @@ Config setup() {
|
||||||
.shader={"shaders/14-vert.glsl", "shaders/14-frag.glsl"},
|
.shader={"shaders/14-vert.glsl", "shaders/14-frag.glsl"},
|
||||||
.lightShader={"shaders/14-vert.glsl", "shaders/14-lightsource.frag.glsl"},
|
.lightShader={"shaders/14-vert.glsl", "shaders/14-lightsource.frag.glsl"},
|
||||||
.models={
|
.models={
|
||||||
{"assets/popcorn_model_a.glb"}
|
{"assets", "crate.obj"}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -226,7 +226,7 @@ void draw_popcorn(Config& config, size_t model_i, size_t model_pos, glm::mat4& p
|
||||||
|
|
||||||
config.shader.setMat4("model", model);
|
config.shader.setMat4("model", model);
|
||||||
|
|
||||||
config.models[model_i].Draw(config.shader);
|
config.models[model_i].draw(config.shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(GLFWwindow* window, Config& config) {
|
void render(GLFWwindow* window, Config& config) {
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,27 @@
|
||||||
#include "dbc.hpp"
|
#include "dbc.hpp"
|
||||||
#include <print>
|
#include <print>
|
||||||
|
|
||||||
unsigned int TextureFromFile(const std::string& path, const std::string& directory);
|
unsigned int texture_from_file(const std::string& directory, const std::string& path);
|
||||||
unsigned int TextureFromInternal(const aiScene *scene, size_t index);
|
unsigned int texture_from_internal(const aiScene *scene, size_t index);
|
||||||
|
|
||||||
unsigned int to_gl_texture(unsigned char *data, int width, int height, int nrComponents) {
|
unsigned int image_to_texture(unsigned char *data, int width, int height, int nrComponents) {
|
||||||
unsigned int textureID;
|
unsigned int textureID;
|
||||||
glGenTextures(1, &textureID);
|
glGenTextures(1, &textureID);
|
||||||
|
|
||||||
GLenum format = GL_RGB;
|
GLenum format = GL_RGB;
|
||||||
|
|
||||||
if (nrComponents == 1) {
|
switch(nrComponents) {
|
||||||
format = GL_RED;
|
case 1:
|
||||||
} else if (nrComponents == 3) {
|
format = GL_RED;
|
||||||
format = GL_RGB;
|
break;
|
||||||
} else if (nrComponents == 4) {
|
case 3:
|
||||||
format = GL_RGBA;
|
format = GL_RGB;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
format = GL_RGBA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dbc::sentinel($F("Impossible nrComponents={} when loading image", nrComponents));
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
@ -31,7 +37,7 @@ unsigned int to_gl_texture(unsigned char *data, int width, int height, int nrCom
|
||||||
return textureID;
|
return textureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TextureFromInternal(const aiScene *scene, size_t index) {
|
unsigned int texture_from_internal(const aiScene *scene, size_t index) {
|
||||||
const aiTexture *aiTex = scene->mTextures[index];
|
const aiTexture *aiTex = scene->mTextures[index];
|
||||||
unsigned int textureID = 0;
|
unsigned int textureID = 0;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
|
@ -44,20 +50,20 @@ unsigned int TextureFromInternal(const aiScene *scene, size_t index) {
|
||||||
// compressed texture (PNG or JPG)
|
// compressed texture (PNG or JPG)
|
||||||
size_t dataSize = aiTex->mWidth;
|
size_t dataSize = aiTex->mWidth;
|
||||||
data = stbi_load_from_memory(dataBytes, dataSize, &width, &height, &nrComponents, 0);
|
data = stbi_load_from_memory(dataBytes, dataSize, &width, &height, &nrComponents, 0);
|
||||||
textureID = to_gl_texture(data, width, height, nrComponents);
|
textureID = image_to_texture(data, width, height, nrComponents);
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
} else {
|
} else {
|
||||||
data = (unsigned char*)aiTex->pcData;
|
data = (unsigned char*)aiTex->pcData;
|
||||||
width = aiTex->mWidth;
|
width = aiTex->mWidth;
|
||||||
height = aiTex->mHeight;
|
height = aiTex->mHeight;
|
||||||
nrComponents = 4; // either BGRA8888 or RGBA8888
|
nrComponents = 4; // either BGRA8888 or RGBA8888
|
||||||
textureID = to_gl_texture(data, width, height, nrComponents);
|
textureID = image_to_texture(data, width, height, nrComponents);
|
||||||
}
|
}
|
||||||
|
|
||||||
return textureID;
|
return textureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TextureFromFile(const std::string& path, const std::string& directory)
|
unsigned int texture_from_file(const std::string& directory, const std::string& path)
|
||||||
{
|
{
|
||||||
std::string filename = directory + "/" + path;
|
std::string filename = directory + "/" + path;
|
||||||
|
|
||||||
|
|
@ -68,20 +74,22 @@ unsigned int TextureFromFile(const std::string& path, const std::string& directo
|
||||||
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
|
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
|
||||||
dbc::check(data != nullptr, $F("Failed to load texture {}", filename));
|
dbc::check(data != nullptr, $F("Failed to load texture {}", filename));
|
||||||
|
|
||||||
unsigned int textureID = to_gl_texture(data, width, height, nrComponents);
|
unsigned int textureID = image_to_texture(data, width, height, nrComponents);
|
||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
|
|
||||||
return textureID;
|
return textureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::Draw(Shader &shader) {
|
void Model::draw(Shader &shader) {
|
||||||
for(unsigned int i = 0; i < meshes.size(); i++) {
|
for(unsigned int i = 0; i < meshes.size(); i++) {
|
||||||
meshes[i].Draw(shader);
|
meshes[i].Draw(shader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::loadModel(const std::string& path) {
|
void Model::load_model() {
|
||||||
|
std::string path = directory + "/" + model_path;
|
||||||
|
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
const aiScene* scene = importer.ReadFile(path,
|
const aiScene* scene = importer.ReadFile(path,
|
||||||
|
|
@ -94,23 +102,21 @@ void Model::loadModel(const std::string& path) {
|
||||||
dbc::check(!(scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE), "Assimp says incomplete.");
|
dbc::check(!(scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE), "Assimp says incomplete.");
|
||||||
dbc::check(scene->mRootNode != nullptr, "Assimp loaded scene doesn't have a root node");
|
dbc::check(scene->mRootNode != nullptr, "Assimp loaded scene doesn't have a root node");
|
||||||
|
|
||||||
directory = path.substr(0, path.find_last_of('/'));
|
process_node(scene, scene->mRootNode);
|
||||||
|
|
||||||
processNode(scene->mRootNode, scene);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::processNode(aiNode *node, const aiScene *scene) {
|
void Model::process_node(const aiScene *scene, aiNode *node) {
|
||||||
for(unsigned int i = 0; i < node->mNumMeshes; i++) {
|
for(unsigned int i = 0; i < node->mNumMeshes; i++) {
|
||||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
meshes.push_back(processMesh(mesh, scene));
|
meshes.push_back(process_mesh(scene, mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned int i = 0; i < node->mNumChildren; i++) {
|
for(unsigned int i = 0; i < node->mNumChildren; i++) {
|
||||||
processNode(node->mChildren[i], scene);
|
process_node(scene, node->mChildren[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
|
Mesh Model::process_mesh(const aiScene *scene, aiMesh *mesh) {
|
||||||
std::vector<Vertex> vertices;
|
std::vector<Vertex> vertices;
|
||||||
std::vector<unsigned int> indices;
|
std::vector<unsigned int> indices;
|
||||||
std::vector<Texture> textures;
|
std::vector<Texture> textures;
|
||||||
|
|
@ -159,24 +165,22 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
|
||||||
// normal: texture_normalN
|
// normal: texture_normalN
|
||||||
|
|
||||||
// 1. diffuse maps
|
// 1. diffuse maps
|
||||||
loadMaterialTextures(textures, scene, material, aiTextureType_DIFFUSE, "texture_diffuse");
|
load_material_textures(scene, textures, material, aiTextureType_DIFFUSE, "texture_diffuse");
|
||||||
|
|
||||||
// 2. specular maps
|
// 2. specular maps
|
||||||
loadMaterialTextures(textures, scene, material, aiTextureType_SPECULAR, "texture_specular");
|
load_material_textures(scene, textures, material, aiTextureType_SPECULAR, "texture_specular");
|
||||||
|
|
||||||
// 3. normal maps
|
// 3. normal maps
|
||||||
loadMaterialTextures(textures, scene, material, aiTextureType_HEIGHT, "texture_normal");
|
load_material_textures(scene, textures, material, aiTextureType_HEIGHT, "texture_normal");
|
||||||
|
|
||||||
// 4. height maps
|
// 4. height maps
|
||||||
loadMaterialTextures(textures, scene, material, aiTextureType_AMBIENT, "texture_height");
|
load_material_textures(scene, textures, material, aiTextureType_AMBIENT, "texture_height");
|
||||||
|
|
||||||
return Mesh(vertices, indices, textures);
|
return Mesh(vertices, indices, textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::loadMaterialTextures(std::vector<Texture>& textures, const aiScene *scene, aiMaterial *mat, aiTextureType type, std::string typeName)
|
void Model::load_material_textures(const aiScene *scene, std::vector<Texture>& textures, aiMaterial *mat, aiTextureType type, std::string typeName)
|
||||||
{
|
{
|
||||||
fmt::println("TEXTURE COUNT: {}, {}, {}", (int)type, typeName, mat->GetTextureCount(type));
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
|
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
|
||||||
aiString str;
|
aiString str;
|
||||||
|
|
||||||
|
|
@ -192,20 +196,15 @@ void Model::loadMaterialTextures(std::vector<Texture>& textures, const aiScene *
|
||||||
// if it's a *# style path then it's internal
|
// if it's a *# style path then it's internal
|
||||||
if(tx_str[0] == '*') {
|
if(tx_str[0] == '*') {
|
||||||
// get the texture from the internal version
|
// get the texture from the internal version
|
||||||
tx_id = TextureFromInternal(scene, std::stoi(tx_str.substr(1)));
|
tx_id = texture_from_internal(scene, std::stoi(tx_str.substr(1)));
|
||||||
} else {
|
} else {
|
||||||
// else get it from a file
|
// else get it from a file
|
||||||
tx_id = TextureFromFile(tx_str, directory);
|
tx_id = texture_from_file(directory, tx_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture texture{
|
// dubious code here, but seems to be right
|
||||||
.id = tx_id,
|
auto& result = textures.emplace_back(tx_id, typeName, tx_str);
|
||||||
.type = typeName,
|
textures_loaded.try_emplace(tx_str, result);
|
||||||
.path = tx_str,
|
|
||||||
};
|
|
||||||
|
|
||||||
textures.push_back(texture);
|
|
||||||
textures_loaded.try_emplace(tx_str, texture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,21 @@
|
||||||
struct Model {
|
struct Model {
|
||||||
std::map<std::string, Texture> textures_loaded;
|
std::map<std::string, Texture> textures_loaded;
|
||||||
std::vector<Mesh> meshes;
|
std::vector<Mesh> meshes;
|
||||||
std::string directory{"./"};
|
std::string directory;
|
||||||
|
std::string model_path;
|
||||||
bool gammaCorrection;
|
bool gammaCorrection;
|
||||||
|
|
||||||
Model(const char *path) {
|
Model(const std::string& directory, const std::string& model_path) :
|
||||||
loadModel(path);
|
directory(directory), model_path(model_path)
|
||||||
|
{
|
||||||
|
load_model();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(Shader &shader);
|
void draw(Shader &shader);
|
||||||
|
|
||||||
void loadModel(const std::string& path);
|
void load_model();
|
||||||
void processNode(aiNode *node, const aiScene *scene);
|
void process_node(const aiScene *scene, aiNode *node);
|
||||||
Mesh processMesh(aiMesh *mesh, const aiScene *scene);
|
Mesh process_mesh(const aiScene *scene, aiMesh *mesh);
|
||||||
|
|
||||||
void loadMaterialTextures(std::vector<Texture>& textures, const aiScene *scene, aiMaterial *mat, aiTextureType type, std::string typeName);
|
void load_material_textures(const aiScene *scene, std::vector<Texture>& textures, aiMaterial *mat, aiTextureType type, std::string typeName);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,38 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fuc2/testing.hpp>
|
#include <fuc2/testing.hpp>
|
||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
|
#include "shader.hpp"
|
||||||
|
|
||||||
using namespace fuc2;
|
using namespace fuc2;
|
||||||
|
|
||||||
namespace model_tests {
|
namespace model_tests {
|
||||||
void test_load_textures() {
|
void test_load_textures() {
|
||||||
Model model{"assets/popcorn_model_a.glb"};
|
Shader shader{"shaders/14-vert.glsl", "shaders/14-frag.glsl"};
|
||||||
|
|
||||||
|
Model popcorn{"assets", "popcorn_model_a.glb"};
|
||||||
|
popcorn.draw(shader);
|
||||||
|
|
||||||
|
Model crate_glb{"assets", "crate.glb"};
|
||||||
|
crate_glb.draw(shader);
|
||||||
|
|
||||||
|
Model crate_obj{"assets", "crate.obj"};
|
||||||
|
crate_obj.draw(shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_failures() {
|
||||||
|
auto runner = [&]() {
|
||||||
|
Model bad_obj{"assets", "does_not_exist.obj"};
|
||||||
|
};
|
||||||
|
|
||||||
|
BLOWS_UP(runner, "should fail on missing file.");
|
||||||
|
}
|
||||||
|
|
||||||
fuc2::Set TESTS{
|
fuc2::Set TESTS{
|
||||||
.name="models",
|
.name="models",
|
||||||
.options={ .fail_fast=false },
|
.options={ .fail_fast=false },
|
||||||
.tests={
|
.tests={
|
||||||
TEST(test_load_textures),
|
TEST(test_load_textures),
|
||||||
|
TEST(test_failures),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue