1 // ----------------------------------------------------------------------------
2 // Another Assimp OpenGL sample including texturing.
3 // Note that it is very basic and will only read and apply the model's diffuse
4 // textures (by their material ids)
5 //
6 // Don't worry about the "Couldn't load Image: ...dwarf2.jpg" Message.
7 // It's caused by a bad texture reference in the model file (I guess)
8 //
9 // If you intend to _use_ this code sample in your app, do yourself a favour
10 // and replace immediate mode calls with VBOs ...
11 //
12 // Thanks to NeHe on whose OpenGL tutorials this one's based on! :)
13 // http://nehe.gamedev.net/
14 // ----------------------------------------------------------------------------
15 #include <windows.h>
16 #include <shellapi.h>
17 #include <stdio.h>
18 #include <GL/gl.h>
19 #include <GL/glu.h>
20
21 #ifdef _MSC_VER
22 #pragma warning(disable: 4100) // Disable warning 'unreferenced formal parameter'
23 #endif // _MSC_VER
24
25 #define STB_IMAGE_IMPLEMENTATION
26 #include "contrib/stb/stb_image.h"
27
28 #ifdef _MSC_VER
29 #pragma warning(default: 4100) // Enable warning 'unreferenced formal parameter'
30 #endif // _MSC_VER
31
32 #include <fstream>
33
34 //to map image filenames to textureIds
35 #include <string.h>
36 #include <map>
37
38 // assimp include files. These three are usually needed.
39 #include <assimp/Importer.hpp>
40 #include <assimp/postprocess.h>
41 #include <assimp/scene.h>
42 #include <assimp/DefaultLogger.hpp>
43 #include <assimp/LogStream.hpp>
44 #include "UTFConverter.h"
45
46 // The default hard-coded path. Can be overridden by supplying a path through the command line.
47 static std::string modelpath = "../../test/models/OBJ/spider.obj";
48
49 HGLRC hRC=nullptr; // Permanent Rendering Context
50 HDC hDC=nullptr; // Private GDI Device Context
51 HWND g_hWnd=nullptr; // Holds Window Handle
52 HINSTANCE g_hInstance=nullptr; // Holds The Instance Of The Application
53
54 bool keys[256]; // Array used for Keyboard Routine;
55 bool active=TRUE; // Window Active Flag Set To TRUE by Default
56 bool fullscreen=TRUE; // full-screen Flag Set To full-screen By Default
57
58 GLfloat xrot;
59 GLfloat yrot;
60 GLfloat zrot;
61
62
63 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
64 GLboolean abortGLInit(const char*);
65
66 const char* windowTitle = "OpenGL Framework";
67
68 GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };
69 GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
70 GLfloat LightPosition[]= { 0.0f, 0.0f, 15.0f, 1.0f };
71
72
73
74 // the global Assimp scene object
75 const aiScene* g_scene = nullptr;
76 GLuint scene_list = 0;
77 aiVector3D scene_min, scene_max, scene_center;
78
79 // images / texture
80 std::map<std::string, GLuint*> textureIdMap; // map image filenames to textureIds
81 GLuint* textureIds; // pointer to texture Array
82
83 // Create an instance of the Importer class
84 Assimp::Importer importer;
85
86 using namespace AssimpSamples::SharedCode;
87
createAILogger()88 void createAILogger()
89 {
90 // Change this line to normal if you not want to analyse the import process
91 //Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL;
92 Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE;
93
94 // Create a logger instance for Console Output
95 Assimp::DefaultLogger::create("",severity, aiDefaultLogStream_STDOUT);
96
97 // Create a logger instance for File Output (found in project folder or near .exe)
98 Assimp::DefaultLogger::create("assimp_log.txt",severity, aiDefaultLogStream_FILE);
99
100 // Now I am ready for logging my stuff
101 Assimp::DefaultLogger::get()->info("this is my info-call");
102 }
103
destroyAILogger()104 void destroyAILogger()
105 {
106 // Kill it after the work is done
107 Assimp::DefaultLogger::kill();
108 }
109
logInfo(std::string logString)110 void logInfo(std::string logString)
111 {
112 // Will add message to File with "info" Tag
113 Assimp::DefaultLogger::get()->info(logString.c_str());
114 }
115
logDebug(const char * logString)116 void logDebug(const char* logString)
117 {
118 // Will add message to File with "debug" Tag
119 Assimp::DefaultLogger::get()->debug(logString);
120 }
121
122
Import3DFromFile(const std::string & pFile)123 bool Import3DFromFile( const std::string& pFile)
124 {
125 // Check if file exists
126 std::ifstream fin(pFile.c_str());
127 if(!fin.fail())
128 {
129 fin.close();
130 }
131 else
132 {
133 MessageBox(nullptr, UTFConverter("Couldn't open file: " + pFile).c_wstr() , TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
134 logInfo( importer.GetErrorString());
135 return false;
136 }
137
138 g_scene = importer.ReadFile(pFile, aiProcessPreset_TargetRealtime_Quality);
139
140 // If the import failed, report it
141 if(!g_scene)
142 {
143 logInfo( importer.GetErrorString());
144 return false;
145 }
146
147 // Now we can access the file's contents.
148 logInfo("Import of scene " + pFile + " succeeded.");
149
150 // We're done. Everything will be cleaned up by the importer destructor
151 return true;
152 }
153
154 // Resize And Initialize The GL Window
ReSizeGLScene(GLsizei width,GLsizei height)155 void ReSizeGLScene(GLsizei width, GLsizei height)
156 {
157 // Prevent A Divide By Zero By
158 if (height==0)
159 {
160 // Making Height Equal One
161 height=1;
162 }
163
164 glViewport(0, 0, width, height); // Reset The Current Viewport
165
166 glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
167 glLoadIdentity(); // Reset The Projection Matrix
168
169 // Calculate The Aspect Ratio Of The Window
170 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
171
172 glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
173 glLoadIdentity(); // Reset The Modelview Matrix
174 }
175
176
getBasePath(const std::string & path)177 std::string getBasePath(const std::string& path)
178 {
179 size_t pos = path.find_last_of("\\/");
180 return (std::string::npos == pos) ? "" : path.substr(0, pos + 1);
181 }
182
freeTextureIds()183 void freeTextureIds()
184 {
185 textureIdMap.clear(); //no need to delete pointers in it manually here. (Pointers point to textureIds deleted in next step)
186
187 if (textureIds)
188 {
189 delete[] textureIds;
190 textureIds = nullptr;
191 }
192 }
193
LoadGLTextures(const aiScene * scene)194 int LoadGLTextures(const aiScene* scene)
195 {
196 freeTextureIds();
197
198 //ILboolean success;
199
200 /* Before calling ilInit() version should be checked. */
201 /*if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION)
202 {
203 /// wrong DevIL version ///
204 std::string err_msg = "Wrong DevIL version. Old devil.dll in system32/SysWow64?";
205 char* cErr_msg = (char *) err_msg.c_str();
206 abortGLInit(cErr_msg);
207 return -1;
208 }*/
209
210 //ilInit(); /* Initialization of DevIL */
211
212 if (scene->HasTextures()) return 1;
213 //abortGLInit("Support for meshes with embedded textures is not implemented");
214
215 /* getTexture Filenames and Numb of Textures */
216 for (unsigned int m=0; m<scene->mNumMaterials; m++)
217 {
218 int texIndex = 0;
219 aiReturn texFound = AI_SUCCESS;
220
221 aiString path; // filename
222
223 while (texFound == AI_SUCCESS)
224 {
225 texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
226 textureIdMap[path.data] = nullptr; //fill map with textures, pointers still NULL yet
227 texIndex++;
228 }
229 }
230
231 const size_t numTextures = textureIdMap.size();
232
233
234 /* array with DevIL image IDs */
235 //ILuint* imageIds = NULL;
236 // imageIds = new ILuint[numTextures];
237
238 /* generate DevIL Image IDs */
239 // ilGenImages(numTextures, imageIds); /* Generation of numTextures image names */
240
241 /* create and fill array with GL texture ids */
242 textureIds = new GLuint[numTextures];
243 glGenTextures(static_cast<GLsizei>(numTextures), textureIds); /* Texture name generation */
244
245 /* get iterator */
246 std::map<std::string, GLuint*>::iterator itr = textureIdMap.begin();
247
248 std::string basepath = getBasePath(modelpath);
249 for (size_t i=0; i<numTextures; i++)
250 {
251
252 //save IL image ID
253 std::string filename = (*itr).first; // get filename
254 (*itr).second = &textureIds[i]; // save texture id for filename in map
255 itr++; // next texture
256
257
258 //ilBindImage(imageIds[i]); /* Binding of DevIL image name */
259 std::string fileloc = basepath + filename; /* Loading of image */
260 //success = ilLoadImage(fileloc.c_str());
261 int x, y, n;
262 unsigned char *data = stbi_load(fileloc.c_str(), &x, &y, &n, STBI_rgb_alpha);
263
264 if (nullptr != data )
265 {
266 // Convert every colour component into unsigned byte.If your image contains
267 // alpha channel you can replace IL_RGB with IL_RGBA
268 //success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
269 /*if (!success)
270 {
271 abortGLInit("Couldn't convert image");
272 return -1;
273 }*/
274 // Binding of texture name
275 glBindTexture(GL_TEXTURE_2D, textureIds[i]);
276 // redefine standard texture values
277 // We will use linear interpolation for magnification filter
278 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
279 // We will use linear interpolation for minifying filter
280 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
281 // Texture specification
282 glTexImage2D(GL_TEXTURE_2D, 0, n, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);// Texture specification.
283
284 // we also want to be able to deal with odd texture dimensions
285 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
286 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
287 glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
288 glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
289 stbi_image_free(data);
290 }
291 else
292 {
293 /* Error occurred */
294 MessageBox(nullptr, UTFConverter("Couldn't load Image: " + fileloc).c_wstr(), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
295 }
296 }
297 // Because we have already copied image data into texture data we can release memory used by image.
298 // ilDeleteImages(numTextures, imageIds);
299
300 // Cleanup
301 //delete [] imageIds;
302 //imageIds = NULL;
303
304 return TRUE;
305 }
306
307 // All Setup For OpenGL goes here
InitGL()308 int InitGL()
309 {
310 if (!LoadGLTextures(g_scene))
311 {
312 return FALSE;
313 }
314
315
316 glEnable(GL_TEXTURE_2D);
317 glShadeModel(GL_SMOOTH); // Enables Smooth Shading
318 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
319 glClearDepth(1.0f); // Depth Buffer Setup
320 glEnable(GL_DEPTH_TEST); // Enables Depth Testing
321 glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
322 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculation
323
324
325 glEnable(GL_LIGHTING);
326 glEnable(GL_LIGHT0); // Uses default lighting parameters
327 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
328 glEnable(GL_NORMALIZE);
329
330 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
331 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
332 glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
333 glEnable(GL_LIGHT1);
334
335 return TRUE; // Initialization Went OK
336 }
337
338
339 // Can't send color down as a pointer to aiColor4D because AI colors are ABGR.
Color4f(const aiColor4D * color)340 void Color4f(const aiColor4D *color)
341 {
342 glColor4f(color->r, color->g, color->b, color->a);
343 }
344
set_float4(float f[4],float a,float b,float c,float d)345 void set_float4(float f[4], float a, float b, float c, float d)
346 {
347 f[0] = a;
348 f[1] = b;
349 f[2] = c;
350 f[3] = d;
351 }
352
color4_to_float4(const aiColor4D * c,float f[4])353 void color4_to_float4(const aiColor4D *c, float f[4])
354 {
355 f[0] = c->r;
356 f[1] = c->g;
357 f[2] = c->b;
358 f[3] = c->a;
359 }
360
apply_material(const aiMaterial * mtl)361 void apply_material(const aiMaterial *mtl)
362 {
363 float c[4];
364
365 GLenum fill_mode;
366 int ret1, ret2;
367 aiColor4D diffuse;
368 aiColor4D specular;
369 aiColor4D ambient;
370 aiColor4D emission;
371 ai_real shininess, strength;
372 int two_sided;
373 int wireframe;
374 unsigned int max; // changed: to unsigned
375
376 int texIndex = 0;
377 aiString texPath; //contains filename of texture
378
379 if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath))
380 {
381 //bind texture
382 unsigned int texId = *textureIdMap[texPath.data];
383 glBindTexture(GL_TEXTURE_2D, texId);
384 }
385
386 set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
387 if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
388 color4_to_float4(&diffuse, c);
389 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);
390
391 set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
392 if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
393 color4_to_float4(&specular, c);
394 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
395
396 set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
397 if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
398 color4_to_float4(&ambient, c);
399 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);
400
401 set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
402 if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission))
403 color4_to_float4(&emission, c);
404 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);
405
406 max = 1;
407 ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
408 max = 1;
409 ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
410 if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS))
411 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
412 else {
413 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
414 set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f);
415 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
416 }
417
418 max = 1;
419 if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
420 fill_mode = wireframe ? GL_LINE : GL_FILL;
421 else
422 fill_mode = GL_FILL;
423 glPolygonMode(GL_FRONT_AND_BACK, fill_mode);
424
425 max = 1;
426 if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
427 glEnable(GL_CULL_FACE);
428 else
429 glDisable(GL_CULL_FACE);
430 }
431
432
recursive_render(const struct aiScene * sc,const struct aiNode * nd,float scale)433 void recursive_render (const struct aiScene *sc, const struct aiNode* nd, float scale)
434 {
435 unsigned int i;
436 unsigned int n=0, t;
437 aiMatrix4x4 m = nd->mTransformation;
438
439 aiMatrix4x4 m2;
440 aiMatrix4x4::Scaling(aiVector3D(scale, scale, scale), m2);
441 m = m * m2;
442
443 // update transform
444 m.Transpose();
445 glPushMatrix();
446 glMultMatrixf((float*)&m);
447
448 // draw all meshes assigned to this node
449 for (; n < nd->mNumMeshes; ++n)
450 {
451 const struct aiMesh* mesh = sc->mMeshes[nd->mMeshes[n]];
452
453 apply_material(sc->mMaterials[mesh->mMaterialIndex]);
454
455
456 if(mesh->mNormals == nullptr)
457 {
458 glDisable(GL_LIGHTING);
459 }
460 else
461 {
462 glEnable(GL_LIGHTING);
463 }
464
465 if(mesh->mColors[0] != nullptr)
466 {
467 glEnable(GL_COLOR_MATERIAL);
468 }
469 else
470 {
471 glDisable(GL_COLOR_MATERIAL);
472 }
473
474 for (t = 0; t < mesh->mNumFaces; ++t) {
475 const struct aiFace* face = &mesh->mFaces[t];
476 GLenum face_mode;
477
478 switch(face->mNumIndices)
479 {
480 case 1: face_mode = GL_POINTS; break;
481 case 2: face_mode = GL_LINES; break;
482 case 3: face_mode = GL_TRIANGLES; break;
483 default: face_mode = GL_POLYGON; break;
484 }
485
486 glBegin(face_mode);
487
488 for(i = 0; i < face->mNumIndices; i++) // go through all vertices in face
489 {
490 int vertexIndex = face->mIndices[i]; // get group index for current index
491 if(mesh->mColors[0] != nullptr)
492 Color4f(&mesh->mColors[0][vertexIndex]);
493 if(mesh->mNormals != nullptr)
494
495 if(mesh->HasTextureCoords(0)) //HasTextureCoords(texture_coordinates_set)
496 {
497 glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1 - mesh->mTextureCoords[0][vertexIndex].y); //mTextureCoords[channel][vertex]
498 }
499
500 glNormal3fv(&mesh->mNormals[vertexIndex].x);
501 glVertex3fv(&mesh->mVertices[vertexIndex].x);
502 }
503 glEnd();
504 }
505 }
506
507 // draw all children
508 for (n = 0; n < nd->mNumChildren; ++n)
509 {
510 recursive_render(sc, nd->mChildren[n], scale);
511 }
512
513 glPopMatrix();
514 }
515
516
drawAiScene(const aiScene * scene)517 void drawAiScene(const aiScene* scene)
518 {
519 logInfo("drawing objects");
520
521 recursive_render(scene, scene->mRootNode, 0.5);
522
523 }
524
DrawGLScene()525 int DrawGLScene() //Here's where we do all the drawing
526 {
527 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
528 glLoadIdentity(); // Reset MV Matrix
529
530
531 glTranslatef(0.0f, -10.0f, -40.0f); // Move 40 Units And Into The Screen
532
533
534 glRotatef(xrot, 1.0f, 0.0f, 0.0f);
535 glRotatef(yrot, 0.0f, 1.0f, 0.0f);
536 glRotatef(zrot, 0.0f, 0.0f, 1.0f);
537
538 drawAiScene(g_scene);
539
540 //xrot+=0.3f;
541 yrot+=0.2f;
542 //zrot+=0.4f;
543
544 return TRUE; // okay
545 }
546
547
KillGLWindow()548 void KillGLWindow() // Properly Kill The Window
549 {
550 if (fullscreen) // Are We In Fullscreen Mode?
551 {
552 ChangeDisplaySettings(nullptr, 0); // If So Switch Back To The Desktop
553 ShowCursor(TRUE); // Show Mouse Pointer
554 }
555
556 if (hRC) // Do We Have A Rendering Context?
557 {
558 if (!wglMakeCurrent(nullptr, nullptr)) // Are We Able To Release The DC And RC Contexts?
559 {
560 MessageBox(nullptr, TEXT("Release Of DC And RC Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
561 }
562
563 if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
564 {
565 MessageBox(nullptr, TEXT("Release Rendering Context Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
566 }
567 hRC = nullptr;
568 }
569
570 if (hDC)
571 {
572 if (!ReleaseDC(g_hWnd, hDC)) // Are We able to Release The DC?
573 MessageBox(nullptr, TEXT("Release Device Context Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
574 hDC = nullptr;
575 }
576
577 if (g_hWnd)
578 {
579 if (!DestroyWindow(g_hWnd)) // Are We Able To Destroy The Window
580 MessageBox(nullptr, TEXT("Could Not Release hWnd."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
581 g_hWnd = nullptr;
582 }
583
584 if (g_hInstance)
585 {
586 if (!UnregisterClass(TEXT("OpenGL"), g_hInstance)) // Are We Able To Unregister Class
587 MessageBox(nullptr, TEXT("Could Not Unregister Class."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
588 g_hInstance = nullptr;
589 }
590 }
591
abortGLInit(const char * abortMessage)592 GLboolean abortGLInit(const char* abortMessage)
593 {
594 KillGLWindow(); // Reset Display
595 MessageBox(nullptr, UTFConverter(abortMessage).c_wstr(), TEXT("ERROR"), MB_OK|MB_ICONEXCLAMATION);
596 return FALSE; // quit and return False
597 }
598
CreateGLWindow(const char * title,int width,int height,int bits,bool fullscreenflag)599 BOOL CreateGLWindow(const char* title, int width, int height, int bits, bool fullscreenflag)
600 {
601 GLuint PixelFormat; // Hold the result after searching for a match
602 WNDCLASS wc; // Window Class Structure
603 DWORD dwExStyle; // Window Extended Style
604 DWORD dwStyle; // Window Style
605 RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values
606 WindowRect.left = (long)0;
607 WindowRect.right = (long)width;
608 WindowRect.top = (long)0;
609 WindowRect.bottom = (long)height;
610
611 fullscreen = fullscreenflag;
612
613 g_hInstance = GetModuleHandle(nullptr); // Grab An Instance For Our Window
614 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Move, And Own DC For Window
615 wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc handles Messages
616 wc.cbClsExtra = 0; // No Extra Window Data
617 wc.cbWndExtra = 0; // No Extra Window Data
618 wc.hInstance = g_hInstance;
619 wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO); // Load The Default Icon
620 wc.hCursor = LoadCursor(nullptr, IDC_ARROW); // Load the default arrow
621 wc.hbrBackground= nullptr; // No Background required for OpenGL
622 wc.lpszMenuName = nullptr; // No Menu
623 wc.lpszClassName= TEXT("OpenGL"); // Class Name
624
625 if (!RegisterClass(&wc))
626 {
627 MessageBox(nullptr, TEXT("Failed to register the window class"), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
628 return FALSE; //exit and return false
629 }
630
631 if (fullscreen) // attempt fullscreen mode
632 {
633 DEVMODE dmScreenSettings; // Device Mode
634 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make Sure Memory's Cleared
635 dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size Of the devmode structure
636 dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
637 dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
638 dmScreenSettings.dmBitsPerPel = bits; // bits per pixel
639 dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
640
641 // Try To Set Selected Mode and Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
642 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
643 {
644 // If The Mode Fails, Offer Two Options. Quit Or Run In A Window.
645 if (MessageBox(nullptr,TEXT("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),TEXT("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
646 {
647 fullscreen = FALSE; // Select Windowed Mode (Fullscreen = FALSE)
648 }
649 else
650 {
651 //Popup Messagebox: Closing
652 MessageBox(nullptr, TEXT("Program will close now."), TEXT("ERROR"), MB_OK|MB_ICONSTOP);
653 return FALSE; //exit, return false
654 }
655 }
656 }
657
658 if (fullscreen) // when mode really succeeded
659 {
660 dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
661 dwStyle=WS_POPUP;
662 ShowCursor(FALSE);
663 }
664 else
665 {
666 dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style
667 dwStyle=WS_OVERLAPPEDWINDOW; // Windows style
668 }
669
670 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
671
672 if (nullptr == (g_hWnd=CreateWindowEx(dwExStyle, // Extended Style For The Window
673 TEXT("OpenGL"), // Class Name
674 UTFConverter(title).c_wstr(), // Window Title
675 WS_CLIPSIBLINGS | // Required Window Style
676 WS_CLIPCHILDREN | // Required Window Style
677 dwStyle, // Selected WIndow Style
678 0, 0, // Window Position
679 WindowRect.right-WindowRect.left, // Calc adjusted Window Width
680 WindowRect.bottom-WindowRect.top, // Calc adjustes Window Height
681 nullptr, // No Parent Window
682 nullptr, // No Menu
683 g_hInstance, // Instance
684 nullptr ))) // Don't pass anything To WM_CREATE
685 {
686 abortGLInit("Window Creation Error.");
687 return FALSE;
688 }
689
690 static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
691 {
692 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
693 1, // Version Number
694 PFD_DRAW_TO_WINDOW | // Format Must Support Window
695 PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
696 PFD_DOUBLEBUFFER, // Must Support Double Buffering
697 PFD_TYPE_RGBA, // Request An RGBA Format
698 BYTE(bits), // Select Our Color Depth
699 0, 0, 0, 0, 0, 0, // Color Bits Ignored
700 0, // No Alpha Buffer
701 0, // Shift Bit Ignored
702 0, // No Accumulation Buffer
703 0, 0, 0, 0, // Accumulation Bits Ignored
704 16, // 16Bit Z-Buffer (Depth Buffer)
705 0, // No Stencil Buffer
706 0, // No Auxiliary Buffer
707 PFD_MAIN_PLANE, // Main Drawing Layer
708 0, // Reserved
709 0, 0, 0 // Layer Masks Ignored
710 };
711
712 if (nullptr == (hDC=GetDC(g_hWnd))) // Did we get the Device Context?
713 {
714 abortGLInit("Can't Create A GL Device Context.");
715 return FALSE;
716 }
717
718 if (0 == (PixelFormat=ChoosePixelFormat(hDC, &pfd))) // Did We Find a matching pixel Format?
719 {
720 abortGLInit("Can't Find Suitable PixelFormat");
721 return FALSE;
722 }
723
724 if (!SetPixelFormat(hDC, PixelFormat, &pfd))
725 {
726 abortGLInit("Can't Set The PixelFormat");
727 return FALSE;
728 }
729
730 if (nullptr == (hRC=wglCreateContext(hDC)))
731 {
732 abortGLInit("Can't Create A GL Rendering Context.");
733 return FALSE;
734 }
735
736 if (!(wglMakeCurrent(hDC,hRC))) // Try to activate the rendering context
737 {
738 abortGLInit("Can't Activate The Rendering Context");
739 return FALSE;
740 }
741
742 //// *** everything okay ***
743
744 ShowWindow(g_hWnd, SW_SHOW); // Show The Window
745 SetForegroundWindow(g_hWnd); // Slightly Higher Prio
746 SetFocus(g_hWnd); // Sets Keyboard Focus To The Window
747 ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen
748
749 if (!InitGL())
750 {
751 abortGLInit("Initialization failed");
752 return FALSE;
753 }
754
755 return TRUE;
756 }
757
cleanup()758 void cleanup()
759 {
760 freeTextureIds();
761
762 destroyAILogger();
763
764 if (g_hWnd)
765 KillGLWindow();
766 }
767
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)768 LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window
769 UINT uMsg, // Message for this Window
770 WPARAM wParam, // additional message Info
771 LPARAM lParam) // additional message Info
772 {
773 switch (uMsg) // check for Window Messages
774 {
775 case WM_ACTIVATE: // Watch For Window Activate Message
776 {
777 if (!HIWORD(wParam)) // Check Minimization State
778 {
779 active=TRUE;
780 }
781 else
782 {
783 active=FALSE;
784 }
785
786 return 0; // return To The Message Loop
787 }
788
789 case WM_SYSCOMMAND: // Interrupt System Commands
790 {
791 switch (wParam)
792 {
793 case SC_SCREENSAVE: // Screen-saver trying to start
794 case SC_MONITORPOWER: // Monitor trying to enter power-safe
795 return 0;
796 }
797 break;
798 }
799
800 case WM_CLOSE: // close message received?
801 {
802 PostQuitMessage(0); // Send WM_QUIT quit message
803 return 0; // Jump Back
804 }
805
806 case WM_KEYDOWN: // Is a key pressed?
807 {
808 keys[wParam] = TRUE; // If so, Mark it as true
809 return 0;
810 }
811
812 case WM_KEYUP: // Has Key Been released?
813 {
814 keys[wParam] = FALSE; // If so, Mark It As FALSE
815 return 0;
816 }
817
818 case WM_SIZE: // Resize The OpenGL Window
819 {
820 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord-Width, HiWord-Height
821 return 0;
822 }
823 }
824
825 // Pass All unhandled Messaged To DefWindowProc
826 return DefWindowProc(hWnd, uMsg, wParam, lParam);
827 }
828
WinMain(HINSTANCE,HINSTANCE,LPSTR,int)829 int WINAPI WinMain( HINSTANCE /*hInstance*/, // The instance
830 HINSTANCE /*hPrevInstance*/, // Previous instance
831 LPSTR /*lpCmdLine*/, // Command Line Parameters
832 int /*nShowCmd*/ ) // Window Show State
833 {
834 MSG msg = {};
835 BOOL done=FALSE;
836
837 createAILogger();
838 logInfo("App fired!");
839
840 // Check the command line for an override file path.
841 int argc;
842 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
843 if (argv != nullptr && argc > 1)
844 {
845 std::wstring modelpathW(argv[1]);
846 modelpath = UTFConverter(modelpathW).str();
847 }
848
849 if (!Import3DFromFile(modelpath))
850 {
851 cleanup();
852 return 0;
853 }
854
855 logInfo("=============== Post Import ====================");
856
857 if (MessageBox(nullptr, TEXT("Would You Like To Run In Fullscreen Mode?"), TEXT("Start Fullscreen?"), MB_YESNO|MB_ICONEXCLAMATION)==IDNO)
858 {
859 fullscreen=FALSE;
860 }
861
862 if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen))
863 {
864 cleanup();
865 return 0;
866 }
867
868 while(!done) // Game Loop
869 {
870 if (PeekMessage(&msg, nullptr, 0,0, PM_REMOVE))
871 {
872 if (msg.message==WM_QUIT)
873 {
874 done=TRUE;
875 }
876 else
877 {
878 TranslateMessage(&msg);
879 DispatchMessage(&msg);
880 }
881 }
882 else
883 {
884 // Draw The Scene. Watch For ESC Key And Quit Messaged From DrawGLScene()
885 if (active)
886 {
887 if (keys[VK_ESCAPE])
888 {
889 done=TRUE;
890 }
891 else
892 {
893 DrawGLScene();
894 SwapBuffers(hDC);
895 }
896 }
897
898 if (keys[VK_F1])
899 {
900 keys[VK_F1]=FALSE;
901 KillGLWindow();
902 fullscreen=!fullscreen;
903 if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen))
904 {
905 cleanup();
906 return 0;
907 }
908 }
909 }
910 }
911
912 // *** cleanup ***
913 cleanup();
914 return static_cast<int>(msg.wParam);
915 }
916