Created a crate model in glb and obj format to use in the tests, then finished the model test.

This commit is contained in:
Zed A. Shaw 2026-08-25 12:12:19 -04:00
parent c6a7c42a4e
commit 2431cf8c97
9 changed files with 125 additions and 51 deletions

View file

@ -209,7 +209,7 @@ Config setup() {
.shader={"shaders/14-vert.glsl", "shaders/14-frag.glsl"},
.lightShader={"shaders/14-vert.glsl", "shaders/14-lightsource.frag.glsl"},
.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.models[model_i].Draw(config.shader);
config.models[model_i].draw(config.shader);
}
void render(GLFWwindow* window, Config& config) {

View file

@ -2,21 +2,27 @@
#include "dbc.hpp"
#include <print>
unsigned int TextureFromFile(const std::string& path, const std::string& directory);
unsigned int TextureFromInternal(const aiScene *scene, size_t index);
unsigned int texture_from_file(const std::string& directory, const std::string& path);
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;
glGenTextures(1, &textureID);
GLenum format = GL_RGB;
if (nrComponents == 1) {
format = GL_RED;
} else if (nrComponents == 3) {
format = GL_RGB;
} else if (nrComponents == 4) {
format = GL_RGBA;
switch(nrComponents) {
case 1:
format = GL_RED;
break;
case 3:
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);
@ -31,7 +37,7 @@ unsigned int to_gl_texture(unsigned char *data, int width, int height, int nrCom
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];
unsigned int textureID = 0;
int width = 0;
@ -44,20 +50,20 @@ unsigned int TextureFromInternal(const aiScene *scene, size_t index) {
// compressed texture (PNG or JPG)
size_t dataSize = aiTex->mWidth;
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);
} else {
data = (unsigned char*)aiTex->pcData;
width = aiTex->mWidth;
height = aiTex->mHeight;
nrComponents = 4; // either BGRA8888 or RGBA8888
textureID = to_gl_texture(data, width, height, nrComponents);
textureID = image_to_texture(data, width, height, nrComponents);
}
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;
@ -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);
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);
return textureID;
}
void Model::Draw(Shader &shader) {
void Model::draw(Shader &shader) {
for(unsigned int i = 0; i < meshes.size(); i++) {
meshes[i].Draw(shader);
}
}
void Model::loadModel(const std::string& path) {
void Model::load_model() {
std::string path = directory + "/" + model_path;
Assimp::Importer importer;
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->mRootNode != nullptr, "Assimp loaded scene doesn't have a root node");
directory = path.substr(0, path.find_last_of('/'));
processNode(scene->mRootNode, scene);
process_node(scene, scene->mRootNode);
}
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++) {
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++) {
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<unsigned int> indices;
std::vector<Texture> textures;
@ -159,24 +165,22 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
// normal: texture_normalN
// 1. diffuse maps
loadMaterialTextures(textures, scene, material, aiTextureType_DIFFUSE, "texture_diffuse");
load_material_textures(scene, textures, material, aiTextureType_DIFFUSE, "texture_diffuse");
// 2. specular maps
loadMaterialTextures(textures, scene, material, aiTextureType_SPECULAR, "texture_specular");
load_material_textures(scene, textures, material, aiTextureType_SPECULAR, "texture_specular");
// 3. normal maps
loadMaterialTextures(textures, scene, material, aiTextureType_HEIGHT, "texture_normal");
load_material_textures(scene, textures, material, aiTextureType_HEIGHT, "texture_normal");
// 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);
}
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++) {
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(tx_str[0] == '*') {
// 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 get it from a file
tx_id = TextureFromFile(tx_str, directory);
tx_id = texture_from_file(directory, tx_str);
}
Texture texture{
.id = tx_id,
.type = typeName,
.path = tx_str,
};
textures.push_back(texture);
textures_loaded.try_emplace(tx_str, texture);
// dubious code here, but seems to be right
auto& result = textures.emplace_back(tx_id, typeName, tx_str);
textures_loaded.try_emplace(tx_str, result);
}
}
}

View file

@ -21,18 +21,21 @@
struct Model {
std::map<std::string, Texture> textures_loaded;
std::vector<Mesh> meshes;
std::string directory{"./"};
std::string directory;
std::string model_path;
bool gammaCorrection;
Model(const char *path) {
loadModel(path);
Model(const std::string& directory, const std::string& model_path) :
directory(directory), model_path(model_path)
{
load_model();
}
void Draw(Shader &shader);
void draw(Shader &shader);
void loadModel(const std::string& path);
void processNode(aiNode *node, const aiScene *scene);
Mesh processMesh(aiMesh *mesh, const aiScene *scene);
void load_model();
void process_node(const aiScene *scene, aiNode *node);
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);
};