Source

dbsdev / sources / tools / mesh_importer / renderer.cpp

Full commit
// ----------------------------------------------------------------------------
// Simple sample to prove that Assimp is easy to use with OpenGL.
// It takes a file name as command line parameter, loads it using standard
// settings and displays it.
//
// ----------------------------------------------------------------------------

#include <iostream>

#include <cstdio>
#include <cstdlib>

// Bring in OpenGL 
#include "glfw_utils.h"

// assimp include files. These three are usually needed.
#include <assimp/config.h>
#include <assimp/cimport.h>
#include <assimp/cexport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#include "GLTimer.h"

#include "renderer.h"

// the global Assimp scene object
extern const struct aiScene* scene;

// timer
GLTimer timer;
// current rotation angle
static float angle = 0.f;


// ----------------------------------------------------------------------------
void color4_to_float4(const aiColor4D *c, float f[4])
{
	f[0] = c->r;
	f[1] = c->g;
	f[2] = c->b;
	f[3] = c->a;
}

// ----------------------------------------------------------------------------
void set_float4(float f[4], float a, float b, float c, float d)
{
	f[0] = a;
	f[1] = b;
	f[2] = c;
	f[3] = d;
}

// ----------------------------------------------------------------------------
void apply_material(const struct aiMaterial *mtl)
{
	float c[4];

	GLenum fill_mode;
	int ret1, ret2;
	aiColor4D diffuse;
	aiColor4D specular;
	aiColor4D ambient;
	aiColor4D emission;
	float shininess, strength;
	int two_sided;
	int wireframe;
	unsigned int max;

	set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
	if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
		color4_to_float4(&diffuse, c);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);

	set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
	if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
		color4_to_float4(&specular, c);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);

	set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
	if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
		color4_to_float4(&ambient, c);
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);

	set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
	if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission))
		color4_to_float4(&emission, c);
	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);

	max = 1;
	ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
	if(ret1 == AI_SUCCESS) {
    	max = 1;
    	ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
		if(ret2 == AI_SUCCESS)
			glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
        else
        	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
    }
	else {
		glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
		set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
	}

	max = 1;
	if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
		fill_mode = wireframe ? GL_LINE : GL_FILL;
	else
		fill_mode = GL_FILL;
	glPolygonMode(GL_FRONT_AND_BACK, fill_mode);

	max = 1;
	if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
		glDisable(GL_CULL_FACE);
	else 
		glEnable(GL_CULL_FACE);
}

// ----------------------------------------------------------------------------
void recursive_render (const struct aiScene *sc, const struct aiNode* nd)
{
	unsigned int i;
	unsigned int n = 0, t;
	aiMatrix4x4 m = nd->mTransformation;

	// update transform
	aiTransposeMatrix4(&m);
	glPushMatrix();
	glMultMatrixf((float*)&m);

	// draw all meshes assigned to this node
	for (; n < nd->mNumMeshes; ++n) {
		const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];

		apply_material(sc->mMaterials[mesh->mMaterialIndex]);

		// if(mesh->mNormals == NULL) {
		// 	glDisable(GL_LIGHTING);
		// } else {
			glEnable(GL_LIGHTING);
		// }

		for (t = 0; t < mesh->mNumFaces; ++t) {
			const struct aiFace* face = &mesh->mFaces[t];
			GLenum face_mode;

			switch(face->mNumIndices) {
				case 1: face_mode = GL_POINTS; break;
				case 2: face_mode = GL_LINES; break;
				case 3: face_mode = GL_TRIANGLES; break;
				default: face_mode = GL_POLYGON; break;
			}

			glBegin(face_mode);

			for(i = 0; i < face->mNumIndices; i++) {
				int index = face->mIndices[i];
				if(mesh->mColors[0] != NULL)
					glColor4fv((GLfloat*)&mesh->mColors[0][index]);
				if(mesh->mNormals != NULL) 
					glNormal3fv(&mesh->mNormals[index].x);
				glVertex3fv(&mesh->mVertices[index].x);
			}

			glEnd();
		}

	}

	// draw all children
	for (n = 0; n < nd->mNumChildren; ++n) 
	{
		recursive_render(sc, nd->mChildren[n]);
	}

	glPopMatrix();
}


void drawSimpleGrid(float xmin, float xmax, unsigned int nx,
					float ymin, float ymax, unsigned int ny,
                    float zmin, float zmax, unsigned int nz)
{
    glPushAttrib(GL_LIGHTING_BIT);
    glDisable(GL_LIGHTING);

    float dx = (xmax-xmin)/nx;
    float dy = (ymax-ymin)/ny;
    float dz = (zmax-zmin)/nz;
    // XZ plane
    for (unsigned int i=0; i<=nx; i++)
    {
        float xval=xmin+i*dx;
        if (fabs(xval)<1e-6) continue;
        glBegin(GL_LINES);
            glColor3f(0.5f,0.0f,0.0f);
            glVertex3f(xval,0.0f,zmin);
            glVertex3f(xval,0.0f,zmax);
        glEnd();
    }
    for (unsigned int j=0; j<=nz; j++)
    {
        float zval=zmin+j*dz;
        if (fabs(zval)<1e-6) continue;
        glBegin(GL_LINES);
            glColor3f(0.5f,0.0f,0.0f);
            glVertex3f(xmin,0.0f,zval);
            glVertex3f(xmax,0.0f,zval);
        glEnd();        
    }
    // XY plane
    for (unsigned int i=0; i<=nx; i++)
    {
        float xval=xmin+i*dx;
        glBegin(GL_LINES);
            glColor3f(0.0f,0.5f,0.0f);
            glVertex3f(xval,ymin,0.0f);
            glVertex3f(xval,ymax,0.0f);
        glEnd();
    }
    for (unsigned int j=0; j<=ny; j++)
    {
        float yval=ymin+j*dy;
        if (fabs(yval)<1e-6) continue;
        glBegin(GL_LINES);
            glColor3f(0.0f,0.5f,0.0f);
            glVertex3f(xmin,yval,0.0f);
            glVertex3f(xmax,yval,0.0f);
        glEnd();        
    }
    // YZ plane
    for (unsigned int i=0; i<=nx; i++)
    {
        float yval=ymin+i*dy;
        if (fabs(yval)<1e-6) continue;
        glBegin(GL_LINES);
            glColor3f(0.0f,0.0f,0.5f);
            glVertex3f(0.0f,yval,zmin);
            glVertex3f(0.0f,yval,zmax);
        glEnd();
    }
    for (unsigned int j=0; j<=nz; j++)
    {
        float zval=zmin+j*dz;
        if (fabs(zval)<1e-6) continue;
        glBegin(GL_LINES);
            glColor3f(0.0f,0.0f,0.5f);
            glVertex3f(0.0f,ymin,zval);
            glVertex3f(0.0f,ymax,zval);
        glEnd();        
    }

    // bold axes
    glLineWidth(3.0f);
    glBegin(GL_LINES);
    	glColor3f(1.0f,0.0f,0.0f);
        glVertex3f(xmin,0.0f,0.0f);
        glVertex3f(xmax,0.0f,0.0f);
        glColor3f(0.0f,1.0f,0.0f);
        glVertex3f(0.0f,ymin,0.0f);
        glVertex3f(0.0f,ymax,0.0f);
        glColor3f(0.0f,0.0f,1.0f);
        glVertex3f(0.0f,0.0f,zmin);
        glVertex3f(0.0f,0.0f,zmax);
    glEnd();
    glLineWidth(1.0f);

    glPopAttrib();	// lighting
}    

// ----------------------------------------------------------------------------
void drawGraphics(void)
{
	float tmp;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.f,2.f,10.f,0.f,0.f,0.0f,0.f,1.f,0.f);

	// rotate it around the y axis
	glRotatef(timer.getElapsedTime()*10.0,0.f,1.f,0.f);

	drawSimpleGrid(-10.0,10.0,20,
				   -10.0,10.0,20,
				   -10.0,10.0,20);
	if (scene)
    	recursive_render(scene, scene->mRootNode);
}


// ----------------------------------------------------------------------------
bool initRenderer( void )
{
	if (!glfw_Init(900,600))
	{
		printf("Error initializing Renderer.\n");
		return false;
	}
	return true;
}


// ----------------------------------------------------------------------------
void startRenderer( void *params )
{
	if (!initRenderer())
	{
		printf("Error initializing Renderer.\n");
		return;
	}

	glClearColor(0.1f,0.1f,0.1f,1.f);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);    // Uses default lighting parameters

	glEnable(GL_DEPTH_TEST);

	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
	glEnable(GL_NORMALIZE);

	glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);

	timer.start();

	bool running = true;
    while( running ) 
    {
        // OpenGL rendering goes here...
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        // draw graphics
        drawGraphics();

        // Swap front and back rendering buffers
        glfwSwapBuffers();
        // Check if ESC key was pressed or window was closed
        running = !glfwGetKey( GLFW_KEY_ESC ) && glfwGetWindowParam( GLFW_OPENED );
    }

	return;
}