📄 main.cpp
字号:
//***********************************************************************//
// //
// - "Talk to me like I'm a 3 year old!" Programming Lessons - //
// //
// $Author: DigiBen digiben@gametutorials.com //
// //
// $Program: 3DS Loader //
// //
// $Description: Demonstrates how to load a .3ds file format //
// //
// $Date: 10/6/01 - Modified 7/3/03 (TheTutor) //
// //
//***********************************************************************//
// This is a compiler directive that includes libraries (For Visual Studio)
// You can manually include the libraries in the "Project->settings" menu under
// the "Link" tab. You need these libraries to compile this program.
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")
#include "main.h" // This includes our header file
#include "3ds.h" // Include the 3DS header file.
bool g_bFullScreen = true; // Set full screen as default
HWND g_hWnd; // This is the handle for the window
RECT g_rRect; // This holds the window dimensions
HDC g_hDC; // General HDC - (handle to device context)
HGLRC g_hRC; // General OpenGL_DC - Our Rendering Context for OpenGL
HINSTANCE g_hInstance; // This holds the global hInstance for UnregisterClass() in DeInit()
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
// This tutorial will demonstrate how to load a .3DS file. This 3D file format
// is created from 3D Studio Max. It can be exported and important into many
// other programs. A great tool for converting 3D file formats is "3D Exploration".
// This is a shareware utility that can be found for download on the web.
// This 3DS loader only loads the texture names, object colors, the vertices, the faces, and the UV coordinates.
// The key frame information is ignored since we have a Key Frame Animation tutorial later.
// I didn't want to over complicate this tutorial, but just show the basics.
//
// In this tutorial, there is a picture of a face rotating around. It is a single object
// with a single texture. The .3ds loader does load multiple objects though.
// The controls are:
// Left Mouse Button - Changes the Render mode from normal to wireframe.
// Right Mouse Button - Turns lighting On/Off
// Left Arrow Key - Spins the model to the left
// Right Arrow Key - Spins the model to the right
// Escape - Quits
#define FILE_NAME "face.3ds" // This is the 3D file we will load.
UINT g_Texture[MAX_TEXTURES] = {0}; // This holds the texture info, referenced by an ID
CLoad3DS g_Load3ds; // This is 3DS class. This should go in a good model class.
t3DModel g_3DModel; // This holds the 3D Model info that we load in
int g_ViewMode = GL_TRIANGLES; // We want the default drawing mode to be normal
bool g_bLighting = true; // Turn lighting on initially
float g_RotateX = 0.0f; // This is the current value at which the model is rotated
float g_RotationSpeed = 0.8f; // This is the speed that our model rotates. (-speed rotates left)
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
///////////////////////////////// INIT GAME WINDOW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This function initializes the game window.
/////
///////////////////////////////// INIT GAME WINDOW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void Init(HWND hWnd)
{
g_hWnd = hWnd; // Assign the window handle to a global window handle
GetClientRect(g_hWnd, &g_rRect); // Assign the windows rectangle to a global RECT
InitializeOpenGL(g_rRect.right, g_rRect.bottom); // Init OpenGL with the global rect
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
// First we need to actually load the .3DS file. We just pass in an address to
// our t3DModel structure and the file name string we want to load ("face.3ds").
g_Load3ds.Import3DS(&g_3DModel, FILE_NAME); // Load our .3DS file into our model structure
// Depending on how many textures we found, load each one (Assuming .BMP)
// If you want to load other files than bitmaps, you will need to adjust CreateTexture().
// Below, we go through all of the materials and check if they have a texture map to load.
// Otherwise, the material just holds the color information and we don't need to load a texture.
// Go through all the materials
for(int i = 0; i < g_3DModel.numOfMaterials; i++)
{
// Check to see if there is a file name to load in this material
if(strlen(g_3DModel.pMaterials[i].strFile) > 0)
{
// Use the name of the texture file to load the bitmap, with a texture ID (i).
// We pass in our global texture array, the name of the texture, and an ID to reference it.
CreateTexture(g_Texture, g_3DModel.pMaterials[i].strFile, i);
}
// Set the texture ID for this material
g_3DModel.pMaterials[i].texureId = i;
}
// Here, we turn on a lighting and enable lighting. We don't need to
// set anything else for lighting because we will just take the defaults.
// We also want color, so we turn that on
glEnable(GL_LIGHT0); // Turn on a light with defaults set
glEnable(GL_LIGHTING); // Turn on lighting
glEnable(GL_COLOR_MATERIAL); // Allow color
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
}
///////////////////////////////// MAIN GAME LOOP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This function Handles the main game loop
/////
///////////////////////////////// MAIN GAME LOOP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
WPARAM MainLoop()
{
MSG msg;
while(1) // Do our infinate loop
{ // Check if there was a message
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT) // If the message wasnt to quit
break;
TranslateMessage(&msg); // Find out what the message does
DispatchMessage(&msg); // Execute the message
}
else // if there wasn't a message
{
RenderScene(); // Update the screen
}
}
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
// When we are done, we need to free all the model data
// We do this by walking through all the objects and freeing their information
// Go through all the objects in the scene
for(int i = 0; i < g_3DModel.numOfObjects; i++)
{
// Free the faces, normals, vertices, and texture coordinates.
delete [] g_3DModel.pObject[i].pFaces;
delete [] g_3DModel.pObject[i].pNormals;
delete [] g_3DModel.pObject[i].pVerts;
delete [] g_3DModel.pObject[i].pTexVerts;
}
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
DeInit(); // Clean up and free all allocated memory
return(msg.wParam); // Return from the program
}
///////////////////////////////// RENDER SCENE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This function renders the entire scene.
/////
///////////////////////////////// RENDER SCENE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The matrix
//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////
// Give OpenGL our position, then view, then up vector
gluLookAt( 0, 1.5f, 8, 0, 0.5f, 0, 0, 1, 0);
// We want the model to rotate around the axis so we give it a rotation
// value, then increase/decrease it. You can rotate right of left with the arrow keys.
glRotatef(g_RotateX, 0, 1.0f, 0); // Rotate the object around the Y-Axis
g_RotateX += g_RotationSpeed; // Increase the speed of rotation
// I am going to attempt to explain what is going on below up here as not to clutter the
// code below. We have a model that has a certain amount of objects and textures. We want
// to go through each object in the model, bind it's texture map to it, then render it.
// To render the current object, we go through all of it's faces (Polygons).
// What is a face you ask? A face is just (in this case) a triangle of the object.
// For instance, a cube has 12 faces because each side has 2 triangles.
// You might be thinking. Well, if there are 12 faces in a cube, that makes
// 36 vertices that we needed to read in for that object. Not really true. Because
// a lot of the vertices are the same, since they share sides, they only need to save
// 8 vertices, and ignore the duplicates. Then, you have an array of all the
// unique vertices in that object. No 2 vertices will be the same. This cuts down
// on memory. Then, another array is saved, which is the index numbers for each face,
// which index in to that array of vertices. That might sound silly, but it is better
// than saving tons of duplicate vertices. The same thing happens for UV coordinates.
// You don't save duplicate UV coordinates, you just save the unique ones, then an array
// that index's into them. This might be confusing, but most 3D files use this format.
// This loop below will stay the same for most file formats that you load, so all you need
// to change is the loading code. You don't need to change this loop (Except for animation).
// Since we know how many objects our model has, go through each of them.
for(int i = 0; i < g_3DModel.numOfObjects; i++)
{
// Make sure we have valid objects just in case. (size() is in the vector class)
if(g_3DModel.pObject.size() <= 0) break;
// Get the current object that we are displaying
t3DObject *pObject = &g_3DModel.pObject[i];
// Check to see if this object has a texture map, if so bind the texture to it.
if(pObject->bHasTexture) {
// Turn on texture mapping and turn off color
glEnable(GL_TEXTURE_2D);
// Reset the color to normal again
glColor3ub(255, 255, 255);
// Bind the texture map to the object by it's materialID
glBindTexture(GL_TEXTURE_2D, g_Texture[pObject->materialID]);
} else {
// Turn off texture mapping and turn on color
glDisable(GL_TEXTURE_2D);
// Reset the color to normal again
glColor3ub(255, 255, 255);
}
// This determines if we are in wireframe or normal mode
glBegin(g_ViewMode); // Begin drawing with our selected mode (triangles or lines)
// Go through all of the faces (polygons) of the object and draw them
for(int j = 0; j < pObject->numOfFaces; j++)
{
// Go through each corner of the triangle and draw it.
for(int whichVertex = 0; whichVertex < 3; whichVertex++)
{
// Get the index for each point of the face
int index = pObject->pFaces[j].vertIndex[whichVertex];
// Give OpenGL the normal for this vertex.
glNormal3f(pObject->pNormals[ index ].x, pObject->pNormals[ index ].y, pObject->pNormals[ index ].z);
// If the object has a texture associated with it, give it a texture coordinate.
if(pObject->bHasTexture) {
// Make sure there was a UVW map applied to the object or else it won't have tex coords.
if(pObject->pTexVerts) {
glTexCoord2f(pObject->pTexVerts[ index ].x, pObject->pTexVerts[ index ].y);
}
} else {
// Make sure there is a valid material/color assigned to this object.
// You should always at least assign a material color to an object,
// but just in case we want to check the size of the material list.
// if the size is at least one, and the material ID != -1,
// then we have a valid material.
if(g_3DModel.pMaterials.size() && pObject->materialID >= 0)
{
// Get and set the color that the object is, since it must not have a texture
BYTE *pColor = g_3DModel.pMaterials[pObject->materialID].color;
// Assign the current color to this model
glColor3ub(pColor[0], pColor[1], pColor[2]);
}
}
// Pass in the current vertex of the object (Corner of current face)
glVertex3f(pObject->pVerts[ index ].x, pObject->pVerts[ index ].y, pObject->pVerts[ index ].z);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -