Hey everyone!
I am trying to write a class that can import models using the assimp library and render them to OpenGL with a call to a function called Render().
I am trying to make the window creation process platform independent so I included the GLFW library, and when that didn’t work I tried the freeglut library which didn’t work either.
To compile this code you will need the following libraries/tools:
[ul]
[li] DevIL.
[/li][li] GLFW or freeglut for the glut tests.
[/li][li] Assimp
[/li][li] C++ compiler
[/li][li] A windows platform for the last (currently the only successful) test.
[/li][li] A 3D model supported by assimp, hopefully with some textures and additions.
[/li][/ul]
This is the class which I basically took the code from the assimp “SimpleTexturedOpenGL” sample, and organized it into a class.
The header file
[ol]
[li]Create a Mesh object.
[/li][li]Call the Init() function passing as parameter the name of the 3D model with its file format suffix.
[/li][li]Call Render() when rendering the OpenGL scene.
[/li][li]
[/li][/ol]
#ifndef MESH_H
#define MESH_H
#include <GL\freeglut.h> //Same as GLFW, but trying glut as an alternative
#include <GL\glut.h>
//#include <GL\glfw.h> //Use GLFW to open a window cross-platform and render with OpenGL
#include <assimp\Importer.hpp>
#include <assimp\postprocess.h>
#include <assimp\scene.h>
#include <IL\il.h>
#include <map>
#include <iostream>
class Mesh
{
public:
Mesh();
Mesh(std::string modelName);
~Mesh(void);
void Init(std::string modelName);
void Render(float scale);
void ApplyMaterial(const aiMaterial* mat);
int LoadGLTextures();
private:
void Color4f(const aiColor4D* color);
void Render(const aiNode* node, float scale);
bool configured;
const aiScene *scene;
std::map<std::string, GLuint*> textureIdMap;
GLuint* textureIds;
std::string basePath,
modelName;
Assimp::Importer modelImporter;
};
#endif
The class definition
#include "Mesh.h"
Mesh::Mesh()
{
}
Mesh::Mesh(std::string modelName)
{
Init(modelName);
}
Mesh::~Mesh(void)
{
}
void Mesh::Init(std::string modelName)
{
basePath = "models/3DS/tank/"; //<--- Base path to where the models are included.
this->modelName = modelName;
configured = false;
scene = modelImporter.ReadFile((basePath + modelName), aiProcessPreset_TargetRealtime_Quality);// If the import failed, report it
if( !scene)
{
std::cout << modelImporter.GetErrorString() << std::endl;
}
LoadGLTextures();
}
void Mesh::Render(float scale)
{
this->Render(scene->mRootNode, scale);
}
void Mesh::Render(const aiNode* node, float scale)
{
std::cout << "[Rendering]" << std::endl;
unsigned int i = 0,
t = 0,
n = 0;
aiMatrix4x4 aiM = node->mTransformation;
aiM.Scaling(aiVector3D(scale, scale, scale), aiM);
aiM.Transpose();
glPushMatrix();
glMultMatrixf((float*)&aiM);
for(; n < node->mNumMeshes; ++n)
{
const aiMesh* mesh = scene->mMeshes[node->mMeshes[n]];
ApplyMaterial(scene->mMaterials[mesh->mMaterialIndex]);
if(mesh->mNormals == NULL)
{
glDisable(GL_LIGHTING);
}
else
{
glEnable(GL_LIGHTING);
}
if(mesh->mColors[0] != NULL)
{
glEnable(GL_COLOR_MATERIAL);
}
else
{
glDisable(GL_COLOR_MATERIAL);
}
for(unsigned int t = 0; t < mesh->mNumFaces; ++t)
{
const 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;
case 4:
face_mode = GL_POLYGON;
break;
}
glBegin(face_mode);
for(unsigned int i = 0; i < face->mNumIndices; ++i)
{
int vertexIndex = face->mIndices[i];
if(mesh->mColors[0] != NULL)
{
Color4f(&mesh->mColors[0][vertexIndex]);
}
if(mesh->mNormals != NULL)
{
if(mesh->HasTextureCoords(0))
{
glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1 - mesh->mTextureCoords[0][vertexIndex].y);
}
glNormal3fv(&mesh->mNormals[vertexIndex].x);
}
glVertex3fv(&mesh->mVertices[vertexIndex].x);
}
glEnd();
}
}
// draw all children
for(unsigned int n = 0; n < node->mNumChildren; ++n)
{
this->Render(node->mChildren[n], scale);
}
glPopMatrix();
}
void Mesh::ApplyMaterial(const aiMaterial* mat)
{
float c[4];
GLenum fillMode;
unsigned int max = 0;
int ret1 = 0,
ret2 = 0,
twoSided = 0,
wireframe = 0,
texIndex = 0;
aiColor4D diffuse,
specular,
ambient,
emission;
float shininess = 0.0f,
strength = 0.0f;
aiString texPath;
if(AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath))
{
unsigned int texId = *textureIdMap[texPath.data];
glBindTexture(GL_TEXTURE_2D, texId);
}
c[0] = 0.8f;
c[1] = 0.8f;
c[2] = 0.8f;
c[3] = 1.0f;
if(AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
{
c[0] = diffuse.r;
c[1] = diffuse.g;
c[2] = diffuse.b;
c[3] = diffuse.a;
}
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);
c[0] = 0.0f;
c[1] = 0.0f;
c[2] = 0.0f;
c[3] = 1.0f;
if(AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_SPECULAR, &specular))
{
c[0] = specular.r;
c[1] = specular.g;
c[2] = specular.b;
c[3] = specular.a;
}
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
c[0] = 0.2f;
c[1] = 0.2f;
c[2] = 0.2f;
c[3] = 1.0f;
if(AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_AMBIENT, &ambient))
{
c[0] = ambient.r;
c[1] = ambient.g;
c[2] = ambient.b;
c[3] = ambient.a;
}
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);
c[0] = 0.0f;
c[1] = 0.0f;
c[2] = 0.0f;
c[3] = 1.0f;
if(AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_EMISSIVE, &emission))
{
c[0] = emission.r;
c[1] = emission.g;
c[2] = emission.b;
c[3] = emission.a;
}
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);
max = 1;
ret1 = aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS, &shininess, &max);
max = 1;
ret2 = aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS))
{
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
}
else
{
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
c[0] = 0.0f;
c[1] = 0.0f;
c[2] = 0.0f;
c[3] = 0.0f;
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
}
max = 1;
if(AI_SUCCESS == aiGetMaterialIntegerArray(mat, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
{
fillMode = wireframe ? GL_LINE : GL_FILL;
}
else
{
fillMode = GL_FILL;
}
glPolygonMode(GL_FRONT_AND_BACK, fillMode);
max = 1;
if((AI_SUCCESS == aiGetMaterialIntegerArray(mat, AI_MATKEY_TWOSIDED, &twoSided, &max)) && twoSided)
{
glEnable(GL_CULL_FACE);
}
else
{
glDisable(GL_CULL_FACE);
}
}
int Mesh::LoadGLTextures()
{
ILboolean success;
if(ilGetInteger(IL_VERSION_NUM) < IL_VERSION)
{
ILint test = ilGetInteger(IL_VERSION_NUM);
//wrong DevIL version
std::string error = "Wrong DevIL version";
char* cError = (char*) error.c_str();
//glfwCloseWindow();
return -1;
}
ilInit();
if(scene->HasTextures())
{
//glfwCloseWindow();
}
for(unsigned int i = 0; i < scene->mNumMaterials; ++i)
{
int texIndex = 0;
aiReturn texFound = AI_SUCCESS;
aiString path; //filename
while(texFound == AI_SUCCESS)
{
texFound = scene->mMaterials[i]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
textureIdMap[path.data] = NULL;
texIndex++;
}
}
int numTextures = textureIdMap.size();
ILuint* imageIds = NULL;
imageIds = new ILuint[numTextures];
/* generate DevIL Image IDs */
ilGenImages(numTextures, imageIds); /* Generation of numTextures image names */
/* create and fill array with GL texture ids */
textureIds = new GLuint[numTextures];
glGenTextures(numTextures, textureIds); /* Texture name generation */
/* define texture path */
//std::string texturepath = "../../../test/models/Obj/";
/* get iterator */
std::map<std::string, GLuint*>::iterator itr = textureIdMap.begin();
for (int i=0; i<numTextures; i++)
{
//save IL image ID
std::string filename = (*itr).first; // get filename
(*itr).second = &textureIds[i]; // save texture id for filename in map
itr++; // next texture
ilBindImage(imageIds[i]); /* Binding of DevIL image name */
std::string fileloc = basePath + filename; /* Loading of image */
success = ilLoadImage(fileloc.c_str());
if (success) /* If no error occured: */
{
success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); /* Convert every colour component into
unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA */
if (!success)
{
/* Error occured */
std::cout << "Couldn't convert image." << std::endl;
//glfwCloseWindow();
return -1;
}
//glGenTextures(numTextures, &textureIds[i]); /* Texture name generation */
glBindTexture(GL_TEXTURE_2D, textureIds[i]); /* Binding of texture name */
//redefine standard texture values
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* We will use linear
interpolation for magnification filter */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* We will use linear
interpolation for minifying filter */
glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH),
ilGetInteger(IL_IMAGE_HEIGHT), 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE,
ilGetData()); /* Texture specification */
}
else
{
/* Error occured */
std::cout << "Couldn't load image:" << fileloc << std::endl;
//MessageBox(NULL, ("Couldn't load Image: " + fileloc).c_str() , "ERROR", MB_OK | MB_ICONEXCLAMATION);
}
}
ilDeleteImages(numTextures, imageIds); /* Because we have already copied image data into texture data
we can release memory used by image. */
//Cleanup
delete [] imageIds;
imageIds = NULL;
//return success;
return true;
}
void Mesh::Color4f(const aiColor4D* color)
{
glColor4f(color->r, color->g, color->b, color->a);
}
The main.cpp code (GLUT)
#include "Mesh.h"
#include <assimp/DefaultLogger.hpp>
#include <stdlib.h>
void createAILogger()
{
//Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL;
Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE;
// Create a logger instance for Console Output
Assimp::DefaultLogger::create("",severity, aiDefaultLogStream_STDOUT);
// Create a logger instance for File Output (found in project folder or near .exe)
Assimp::DefaultLogger::create("assimp_log.txt",severity, aiDefaultLogStream_FILE);
// Now I am ready for logging my stuff
Assimp::DefaultLogger::get()->info("this is my info-call");
}
void logInfo(std::string logString)
{
//Will add message to File with "info" Tag
Assimp::DefaultLogger::get()->info(logString.c_str());
}
Mesh mesh;
GLfloat xrot;
GLfloat yrot;
GLfloat zrot;
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, 15.0f, 1.0f };
int InitGL() // All Setup For OpenGL goes here
{
mesh.Init("M1_Abrams.3DS");
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // Enables Smooth Shading
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculation
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0); // Uses default lighting parameters
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_NORMALIZE);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glEnable(GL_LIGHT1);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
return true; // Initialization Went OK
}
void DrawGLScene() //Here's where we do all the drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); // Reset MV Matrix
glTranslatef(0.0f, -10.0f, -40.0f); // Move 40 Units And Into The Screen
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glRotatef(zrot, 0.0f, 0.0f, 1.0f);
mesh.Render(0.5f);
glutSwapBuffers();
//xrot+=0.3f;
yrot+=0.2f;
//zrot+=0.4f;
}
void glutDisplayFunction()
{
DrawGLScene();
}
int main(int argc, char** argv)
{
bool done = false; // Bool Variable To Exit Loop
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_STENCIL | GLUT_RGBA);
glutInitWindowSize(800,600);
if(!glutCreateWindow("Testing"))
{
exit(EXIT_FAILURE);
}
glutIdleFunc(&glutDisplayFunction);
glutDisplayFunc(&glutDisplayFunction);
InitGL(); //Load mesh, call LoadGLTextures and set OpenGL values.
createAILogger();
logInfo("App fired!");
// load scene
logInfo("=============== Post Import ====================");
glutMainLoop();
return 0;
}
That code opens a window and it’s supposed to render the model, but does not render anything, although the model is getting imported and the Render function is being processed.
GLUT was after I tried GLFW.
The main.cpp code (GLFW)
#include "Mesh.h"
#include <assimp/DefaultLogger.hpp>
#include <stdlib.h>
void createAILogger()
{
//Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL;
Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE;
// Create a logger instance for Console Output
Assimp::DefaultLogger::create("",severity, aiDefaultLogStream_STDOUT);
// Create a logger instance for File Output (found in project folder or near .exe)
Assimp::DefaultLogger::create("assimp_log.txt",severity, aiDefaultLogStream_FILE);
// Now I am ready for logging my stuff
Assimp::DefaultLogger::get()->info("this is my info-call");
}
void logInfo(std::string logString)
{
//Will add message to File with "info" Tag
Assimp::DefaultLogger::get()->info(logString.c_str());
}
int main()
{
int running = GL_TRUE;
if(!glfwInit())
{
exit(EXIT_FAILURE);
}
if(!glfwOpenWindow(800, 600, 0, 0, 0, 8, 8, 0, GLFW_WINDOW))
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glEnable(GL_TEXTURE_2D);
glClearDepth(1.0f); // Depth Buffer Setup
glShadeModel(GL_SMOOTH); // Enables Smooth Shading
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculation
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0); // Uses default lighting parameters
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_NORMALIZE);
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, 15.0f, 1.0f };
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glEnable(GL_LIGHT1);
GLfloat xrot;
GLfloat yrot;
GLfloat zrot;
Mesh mesh;
mesh.Init("M1_Abrams.3DS"); // <--- Import and initialize the model
createAILogger();
logInfo("Post import.");
//glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 );
while(running)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(0.0f, -10.0f, -40.0f); // Move 40 Units And Into The Screen
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glRotatef(zrot, 0.0f, 0.0f, 1.0f);
mesh.Render(0.5f); // This is where the mesh tries to render to OpenGL.
yrot+=0.2f;
glfwSwapBuffers();
running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
}
glfwTerminate();
exit(EXIT_SUCCESS);
}
With this happens the same thing as with glut, the window opens but the model does not show on the screen.
I was pretty sure that code worked because it works in the assimp sample. Next thing I tried was rendering the window using the same code as the sample. I don’t like that because it’s Windows dependent code.
#include "Mesh.h"
#include <assimp/DefaultLogger.hpp>
#include <stdlib.h>
void createAILogger()
{
//Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL;
Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE;
// Create a logger instance for Console Output
Assimp::DefaultLogger::create("",severity, aiDefaultLogStream_STDOUT);
// Create a logger instance for File Output (found in project folder or near .exe)
Assimp::DefaultLogger::create("assimp_log.txt",severity, aiDefaultLogStream_FILE);
// Now I am ready for logging my stuff
Assimp::DefaultLogger::get()->info("this is my info-call");
}
void logInfo(std::string logString)
{
//Will add message to File with "info" Tag
Assimp::DefaultLogger::get()->info(logString.c_str());
}
Mesh mesh; // <---The Mesh class - Woo!
HGLRC hRC=NULL; // Permanent Rendering Context
HDC hDC=NULL; // Private GDI Device Context
HWND hWnd=NULL; // Holds Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
bool keys[256]; // Array used for Keyboard Routine;
bool active=TRUE; // Window Active Flag Set To TRUE by Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen By Default
GLfloat xrot;
GLfloat yrot;
GLfloat zrot;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
const char* windowTitle = "OpenGL Framework";
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, 15.0f, 1.0f };
void ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0, 0, width, height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
int InitGL() // All Setup For OpenGL goes here
{
mesh.LoadGLTextures(); // <-- I know this repeats itself, but the addition to the Init function calling LoadGLTextures was added after this test.
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // Enables Smooth Shading
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculation
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0); // Uses default lighting parameters
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_NORMALIZE);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glEnable(GL_LIGHT1);
//glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
return TRUE; // Initialization Went OK
}
int DrawGLScene() //Here's where we do all the drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset MV Matrix
glTranslatef(0.0f, -10.0f, -40.0f); // Move 40 Units And Into The Screen
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glRotatef(zrot, 0.0f, 0.0f, 1.0f);
mesh.Render(0.5f);
//xrot+=0.3f;
yrot+=0.2f;
//zrot+=0.4f;
return TRUE; // Ewwrissing okay
}
void KillGLWindow() // Properly Kill The Window
{
if (fullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL, 0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL, NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
hRC = NULL;
}
if (hDC && !ReleaseDC(hWnd, hDC)) // Are We able to Release The DC?
{
MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hDC=NULL;
}
if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window
{
MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hWnd = NULL;
}
if (!UnregisterClass("OpenGL", hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hInstance = NULL;
}
}
GLboolean abortGLInit(const char* abortMessage)
{
KillGLWindow(); // Reset Display
MessageBox(NULL, abortMessage, "ERROR", MB_OK|MB_ICONEXCLAMATION);
return FALSE; // quit and return False
}
BOOL CreateGLWindow(const char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat; // Hold the result after searching for a match
WNDCLASS wc; // Window Class Structure
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom = (long)height;
fullscreen = fullscreenflag;
hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Move, And Own DC For Window
wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc handles Messages
wc.cbClsExtra = 0; // No Extra Window Data
wc.cbWndExtra = 0; // No Extra Window Data
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the default arrow
wc.hbrBackground= NULL; // No Background required for OpenGL
wc.lpszMenuName = NULL; // No Menu
wc.lpszClassName= "OpenGL"; // Class Name
if (!RegisterClass(&wc))
{
MessageBox(NULL, "Failed to register the window class", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE; //exit and return false
}
if (fullscreen) // attempt fullscreen mode
{
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make Sure Memory's Cleared
dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size Of the devmode structure
dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
dmScreenSettings.dmBitsPerPel = bits; // bits per pixel
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode and Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
// If The Mode Fails, Offer Two Options. Quit Or Run In A Window.
if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By
Your Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen = FALSE; // Select Windowed Mode (Fullscreen = FALSE)
}
else
{
//Popup Messagebox: Closing
MessageBox(NULL, "Program will close now.", "ERROR", MB_OK|MB_ICONSTOP);
return FALSE; //exit, return false
}
}
}
if (fullscreen) // when mode really succeeded
{
dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
dwStyle=WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows style
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requestes Size
if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window
"OpenGL", // Class Name
title, // Window Title
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN | // Required Window Style
dwStyle, // Selected WIndow Style
0, 0, // Window Position
WindowRect.right-WindowRect.left, // Calc adjusted Window Width
WindowRect.bottom-WindowRect.top, // Calc adjustes Window Height
NULL, // No Parent Window
NULL, // No Menu
hInstance, // Instance
NULL ))) // Don't pass anything To WM_CREATE
{
abortGLInit("Window Creation Error.");
return FALSE;
KillGLWindow(); // Reset The Display
MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return False
}
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if (!(hDC=GetDC(hWnd))) // Did we get the Device Context?
{
abortGLInit("Can't Create A GL Device Context.");
return FALSE;
}
if (!(PixelFormat=ChoosePixelFormat(hDC, &pfd))) // Did We Find a matching pixel Format?
{
abortGLInit("Can't Find Suitable PixelFormat");
return FALSE;
}
if (!SetPixelFormat(hDC, PixelFormat, &pfd))
{
abortGLInit("Can't Set The PixelFormat");
return FALSE;
}
if (!(hRC=wglCreateContext(hDC)))
{
abortGLInit("Can't Create A GL Rendering Context.");
return FALSE;
}
if (!(wglMakeCurrent(hDC,hRC))) // Try to activate the rendering context
{
abortGLInit("Can't Activate The Rendering Context");
return FALSE;
}
//// *** everything okay ***
ShowWindow(hWnd, SW_SHOW); // Show The Window
SetForegroundWindow(hWnd); // Slightly Higher Prio
SetFocus(hWnd); // Sets Keyboard Focus To The Window
ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen
if (!InitGL())
{
abortGLInit("Initialization failed");
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window
UINT uMsg, // Message for this Window
WPARAM wParam, // additional message Info
LPARAM lParam) // additional message Info
{
switch (uMsg) // check for Window Messages
{
case WM_ACTIVATE: // Watch For Window Activate Message
{
if (!HIWORD(wParam)) // Check Minimization State
{
active=TRUE;
}
else
{
active=FALSE;
}
return 0; // return To The Message Loop
}
case WM_SYSCOMMAND: // Interrupt System Commands
{
switch (wParam)
{
case SC_SCREENSAVE: // Screensaver trying to start
case SC_MONITORPOWER: // Monitor tryig to enter powersafe
return 0;
}
break;
}
case WM_CLOSE: // close message received?
{
PostQuitMessage(0); // Send WM_QUIT quit message
return 0; // Jump Back
}
case WM_KEYDOWN: // Is a key pressed?
{
keys[wParam] = TRUE; // If so, Mark it as true
return 0;
}
case WM_KEYUP: // Has Key Been released?
{
keys[wParam] = FALSE; // If so, Mark It As FALSE
return 0;
}
case WM_SIZE: // Resize The OpenGL Window
{
ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord-Width, HiWord-Height
return 0;
}
}
// Pass All Unhandled Messaged To DefWindowProc
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain( HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nShowCmd ) // Window Show State
{
MSG msg; // Windows Message Structure
BOOL done=FALSE; // Bool Variable To Exit Loop
createAILogger();
logInfo("App fired!");
// load scene
mesh.Init("M1_Abrams.3DS");
logInfo("=============== Post Import ====================");
// Ask The User Which Screen Mode They Prefer
if (MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start Fullscreen?", MB_YESNO|MB_ICONEXCLAMATION)==IDNO)
{
fullscreen=FALSE; // Windowed Mode
}
// Create Our OpenGL Window (also calls GLinit und LoadGLTextures)
if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen))
{
return 0;
}
while(!done) // Game Loop
{
if (PeekMessage(&msg, NULL, 0,0, PM_REMOVE)) // Is There A Message Waiting
{
if (msg.message==WM_QUIT) // Have we received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else
{
// Draw The Scene. Watch For ESC Key And Quit Messaged From DrawGLScene()
if (active)
{
if (keys[VK_ESCAPE]) // Was ESC pressed?
{
done=TRUE; // ESC signalled A quit
}
else
{
DrawGLScene(); // Draw The Scene
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
}
}
if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If so make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen
//recreate Our OpenGL Window
if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen))
{
return 0; // Quit if Window Was Not Created
}
}
}
}
// Shutdown
KillGLWindow();
return (msg.wParam); // Exit The Program
}
For reasons that I do not yet understand this last main works like a charm. It renders the model and applies all textures/materials to it.
I have looked into several pages of the forum and other tutorials like lighthouse3D. But some of them use a different procedure than the samples use or they do not answer my questions.
Any insight/advice/suggestion is more than welcome. Thanks!