Merge pull request #103 from chrisliebert/master
Issue #74: Added basic diffuse texture support to examples/viewer
This commit is contained in:
6755
examples/viewer/stb_image.h
Normal file
6755
examples/viewer/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -26,12 +27,24 @@
|
|||||||
|
|
||||||
#include "trackball.h"
|
#include "trackball.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#include <mmsystem.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mmsystem.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -112,6 +125,7 @@ class timerutil {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
GLuint vb; // vertex buffer
|
GLuint vb; // vertex buffer
|
||||||
int numTriangles;
|
int numTriangles;
|
||||||
|
size_t material_id;
|
||||||
} DrawObject;
|
} DrawObject;
|
||||||
|
|
||||||
std::vector<DrawObject> gDrawObjects;
|
std::vector<DrawObject> gDrawObjects;
|
||||||
@@ -163,10 +177,11 @@ void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
|||||||
|
|
||||||
bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
||||||
std::vector<DrawObject>* drawObjects,
|
std::vector<DrawObject>* drawObjects,
|
||||||
|
std::vector<tinyobj::material_t>& materials,
|
||||||
|
std::map<std::string, GLuint>& textures,
|
||||||
const char* filename) {
|
const char* filename) {
|
||||||
tinyobj::attrib_t attrib;
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
std::vector<tinyobj::material_t> materials;
|
|
||||||
|
|
||||||
timerutil tm;
|
timerutil tm;
|
||||||
|
|
||||||
@@ -194,17 +209,82 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
printf("# of materials = %d\n", (int)materials.size());
|
printf("# of materials = %d\n", (int)materials.size());
|
||||||
printf("# of shapes = %d\n", (int)shapes.size());
|
printf("# of shapes = %d\n", (int)shapes.size());
|
||||||
|
|
||||||
|
// Load diffuse textures
|
||||||
|
{
|
||||||
|
for (size_t m = 0; m < materials.size(); m++) {
|
||||||
|
tinyobj::material_t* mp = &materials[m];
|
||||||
|
|
||||||
|
if (mp->diffuse_texname.length() > 0) {
|
||||||
|
// Only load the texture if it is not already loaded
|
||||||
|
if (textures.find(mp->diffuse_texname) == textures.end()) {
|
||||||
|
GLuint texture_id;
|
||||||
|
int w, h;
|
||||||
|
int comp;
|
||||||
|
unsigned char* image = stbi_load(mp->diffuse_texname.c_str(), &w, &h, &comp, STBI_default);
|
||||||
|
if (image == nullptr) {
|
||||||
|
std::cerr << "Unable to load texture: " << mp->diffuse_texname << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
glGenTextures(1, &texture_id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
if (comp == 3) {
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||||
|
}
|
||||||
|
else if (comp == 4) {
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
stbi_image_free(image);
|
||||||
|
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||||
|
|
||||||
{
|
{
|
||||||
for (size_t s = 0; s < shapes.size(); s++) {
|
for (size_t s = 0; s < shapes.size(); s++) {
|
||||||
|
size_t current_material_id = 0;
|
||||||
|
if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
|
||||||
|
// Base case
|
||||||
|
current_material_id = shapes[s].mesh.material_ids[s];
|
||||||
|
}
|
||||||
DrawObject o;
|
DrawObject o;
|
||||||
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
||||||
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
|
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
|
||||||
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
|
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
|
||||||
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
|
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
|
||||||
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
|
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
|
||||||
|
|
||||||
|
current_material_id = shapes[s].mesh.material_ids[f];
|
||||||
|
|
||||||
|
if (current_material_id >= materials.size()) {
|
||||||
|
std::cerr << "Invalid material index: " << current_material_id << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diffuse[3];
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
diffuse[i] = materials[current_material_id].diffuse[i];
|
||||||
|
}
|
||||||
|
float tc[3][2];
|
||||||
|
if (attrib.texcoords.size() > 0) {
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1);
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1);
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1);
|
||||||
|
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
|
||||||
|
tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
|
||||||
|
tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
|
||||||
|
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
|
||||||
|
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
|
||||||
|
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
|
||||||
|
} else {
|
||||||
|
std::cerr << "Texcoordinates are not defined" << std::endl;
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
float v[3][3];
|
float v[3][3];
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
@@ -227,7 +307,6 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
}
|
}
|
||||||
|
|
||||||
float n[3][3];
|
float n[3][3];
|
||||||
|
|
||||||
if (attrib.normals.size() > 0) {
|
if (attrib.normals.size() > 0) {
|
||||||
int f0 = idx0.normal_index;
|
int f0 = idx0.normal_index;
|
||||||
int f1 = idx1.normal_index;
|
int f1 = idx1.normal_index;
|
||||||
@@ -258,8 +337,14 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
vb.push_back(n[k][0]);
|
vb.push_back(n[k][0]);
|
||||||
vb.push_back(n[k][1]);
|
vb.push_back(n[k][1]);
|
||||||
vb.push_back(n[k][2]);
|
vb.push_back(n[k][2]);
|
||||||
// Use normal as color.
|
// Combine normal and diffuse to get color.
|
||||||
float c[3] = {n[k][0], n[k][1], n[k][2]};
|
float normal_factor = 0.2;
|
||||||
|
float diffuse_factor = 1 - normal_factor;
|
||||||
|
float c[3] = {
|
||||||
|
n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
|
||||||
|
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
|
||||||
|
n[k][2] * normal_factor + diffuse[2] * diffuse_factor
|
||||||
|
};
|
||||||
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||||
if (len2 > 0.0f) {
|
if (len2 > 0.0f) {
|
||||||
float len = sqrtf(len2);
|
float len = sqrtf(len2);
|
||||||
@@ -271,17 +356,21 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
vb.push_back(c[0] * 0.5 + 0.5);
|
vb.push_back(c[0] * 0.5 + 0.5);
|
||||||
vb.push_back(c[1] * 0.5 + 0.5);
|
vb.push_back(c[1] * 0.5 + 0.5);
|
||||||
vb.push_back(c[2] * 0.5 + 0.5);
|
vb.push_back(c[2] * 0.5 + 0.5);
|
||||||
|
|
||||||
|
vb.push_back(tc[k][0]);
|
||||||
|
vb.push_back(tc[k][1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.vb = 0;
|
o.vb = 0;
|
||||||
o.numTriangles = 0;
|
o.numTriangles = 0;
|
||||||
|
o.material_id = current_material_id;
|
||||||
if (vb.size() > 0) {
|
if (vb.size() > 0) {
|
||||||
glGenBuffers(1, &o.vb);
|
glGenBuffers(1, &o.vb);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||||
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
|
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
|
||||||
GL_STATIC_DRAW);
|
GL_STATIC_DRAW);
|
||||||
o.numTriangles = vb.size() / 9 / 3;
|
o.numTriangles = vb.size() / (3 + 3 + 3 + 2) * 3;
|
||||||
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
|
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
|
||||||
o.numTriangles);
|
o.numTriangles);
|
||||||
}
|
}
|
||||||
@@ -395,13 +484,13 @@ void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
|||||||
prevMouseY = mouse_y;
|
prevMouseY = mouse_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(const std::vector<DrawObject>& drawObjects) {
|
void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t>& materials, std::map<std::string, GLuint>& textures) {
|
||||||
glPolygonMode(GL_FRONT, GL_FILL);
|
glPolygonMode(GL_FRONT, GL_FILL);
|
||||||
glPolygonMode(GL_BACK, GL_FILL);
|
glPolygonMode(GL_BACK, GL_FILL);
|
||||||
|
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(1.0, 1.0);
|
glPolygonOffset(1.0, 1.0);
|
||||||
glColor3f(1.0f, 1.0f, 1.0f);
|
GLsizei stride = (3 + 3 + 3 + 2) * sizeof(float);
|
||||||
for (size_t i = 0; i < drawObjects.size(); i++) {
|
for (size_t i = 0; i < drawObjects.size(); i++) {
|
||||||
DrawObject o = drawObjects[i];
|
DrawObject o = drawObjects[i];
|
||||||
if (o.vb < 1) {
|
if (o.vb < 1) {
|
||||||
@@ -412,12 +501,20 @@ void Draw(const std::vector<DrawObject>& drawObjects) {
|
|||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
|
||||||
glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float) * 6));
|
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
||||||
|
if (diffuse_texname.length() > 0) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
||||||
|
}
|
||||||
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
|
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||||
|
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||||
CheckErrors("drawarrays");
|
CheckErrors("drawarrays");
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw wireframe
|
// draw wireframe
|
||||||
@@ -436,8 +533,11 @@ void Draw(const std::vector<DrawObject>& drawObjects) {
|
|||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
|
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||||
|
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||||
CheckErrors("drawarrays");
|
CheckErrors("drawarrays");
|
||||||
@@ -498,7 +598,9 @@ int main(int argc, char** argv) {
|
|||||||
reshapeFunc(window, width, height);
|
reshapeFunc(window, width, height);
|
||||||
|
|
||||||
float bmin[3], bmax[3];
|
float bmin[3], bmax[3];
|
||||||
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, argv[1])) {
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
std::map<std::string, GLuint> textures;
|
||||||
|
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,6 +618,7 @@ int main(int argc, char** argv) {
|
|||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
// camera & rotate
|
// camera & rotate
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
@@ -533,7 +636,7 @@ int main(int argc, char** argv) {
|
|||||||
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
|
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
|
||||||
-0.5 * (bmax[2] + bmin[2]));
|
-0.5 * (bmax[2] + bmin[2]));
|
||||||
|
|
||||||
Draw(gDrawObjects);
|
Draw(gDrawObjects, materials, textures);
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user