//// GLCanvas.h ///////////////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef GLCANVAS_H #define GLCANVAS_H #include //must come first before other gl type headers #include "wx/glcanvas.h" #ifdef __WXMAC__ #include "OpenGL/glu.h" #include "OpenGL/gl.h" #else #include #include #include #include "GL/glut.h" #endif #include "Object.h" ////////////////////////////////// class GLCanvas: public wxGLCanvas { public: GLCanvas(MainPanel *parent, wxWindowID id, wxSize size, int* attribList); ~GLCanvas(); //EVENTS void OnPaint(wxPaintEvent& event); void OnSize(wxSizeEvent& event); void OnEraseBackground(wxEraseEvent& event){}; //Do nothing, to avoid flashing. void IdleLoop(wxIdleEvent& event); void Render(); //PROCESSING void InitGL(GLfloat Width, GLfloat Height); void ReSizeGLScene(GLint Width, GLint Height); MainPanel *mainPanel; Object *object; DECLARE_EVENT_TABLE() }; #endif //GLCANVAS_H //// GLCanvas.cpp//////////////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////////////////////////////// #include "stdwx.h" #include "GLCanvas.h" /////////////////////////////////////// BEGIN_EVENT_TABLE(GLCanvas, wxGLCanvas) EVT_SIZE(GLCanvas::OnSize) EVT_PAINT(GLCanvas::OnPaint) EVT_ERASE_BACKGROUND(GLCanvas::OnEraseBackground) EVT_IDLE (GLCanvas::IdleLoop) END_EVENT_TABLE() GLCanvas::GLCanvas(MainPanel *parent, wxWindowID id, wxSize size, int* attributeList) : wxGLCanvas(parent, id, wxPoint(0,0), size, wxFULL_REPAINT_ON_RESIZE, wxT(""), attributeList, wxNullPalette) { SetExtraStyle(wxWS_EX_PROCESS_IDLE); //animate in the idle event SetCurrent(); mainPanel = parent; glewInit(); ///////////////////////////////////////////////// object = new Object("model.3ds"); ////////////////////////////////////////////////// InitGL(1,1); } GLCanvas::~GLCanvas() { delete object; } void GLCanvas::OnPaint(wxPaintEvent &event) { Render(); } void GLCanvas::OnSize(wxSizeEvent& event) { // this is also necessary to update the context on some platforms wxGLCanvas::OnSize(event); wxSize temp = event.GetSize(); ReSizeGLScene(temp.GetWidth(), temp.GetHeight()); this->SetSize(temp); } void GLCanvas::IdleLoop(wxIdleEvent &event) { event.Skip(true); //do not propagate this event Refresh(); } void GLCanvas::Render() { if(!IsShown()) return; SetCurrent(); wxPaintDC(this); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); object->Draw(); glFlush(); SwapBuffers(); } void GLCanvas::InitGL(GLfloat Width, GLfloat Height) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); // Enable lighting and set the position of the light glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); GLfloat pos[] = { 0.0, 4.0, 4.0 }; glLightfv(GL_LIGHT0, GL_POSITION, pos); // Generate Vertex Buffer Objects object->CreateVBO(); } void GLCanvas::ReSizeGLScene(GLint Width, GLint Height) { // Reset the viewport glViewport(0, 0, Width, Height); // Reset the projection and modelview matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); // 10 x 10 x 10 viewing volume glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //// Object.h ///////////////////////////////////////////////////////////////////////// // // /////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef OBJECT_H #define OBJECT_H #include "lib3ds/file.h" #include "lib3ds/mesh.h" class Object { public: Object(std:: string filename); virtual ~Object(); virtual void Draw() const; virtual void CreateVBO(); protected: void GetFaces(); unsigned int m_TotalFaces; Lib3dsFile * m_model; GLuint m_VertexVBO, m_NormalVBO, m_TexCoordVBO; }; #endif //OBJECT_H //// Object.cpp//////////////////////////////////////////////////////////////////////// // // /////////////////////////////////////////////////////////////////////////////////////// #include "stdwx.h" #include "Object.h" Object::Object(std:: string filename) { m_TotalFaces = 0; m_model = lib3ds_file_load(filename.c_str()); // If loading the model failed, we throw an exception if(!m_model) { throw strcat("Unable to load ", filename.c_str()); } } Object::~Object() { } void Object::GetFaces() { m_TotalFaces = 0; Lib3dsMesh * mesh; // Loop through every mesh. for(mesh = m_model->meshes;mesh != NULL;mesh = mesh->next) { // Add the number of faces this mesh has to the total number of faces. m_TotalFaces += mesh->faces; } } void Object::CreateVBO() { // Calculate the number of faces we have in total. GetFaces(); // Allocate memory for our vertices, normals and texture-coordinates. Lib3dsVector * vertices = new Lib3dsVector[m_TotalFaces * 3]; Lib3dsVector * normals = new Lib3dsVector[m_TotalFaces * 3]; Lib3dsVector * texCoords = new Lib3dsVector[m_TotalFaces * 2]; Lib3dsMesh * mesh; unsigned int FinishedFaces = 0; // Loop through all the meshes. for(mesh = m_model->meshes;mesh != NULL;mesh = mesh->next) { lib3ds_mesh_calculate_normals(mesh, &normals[FinishedFaces*3]); // Loop through every face. for(unsigned int cur_face = 0; cur_face < mesh->faces;cur_face++) { Lib3dsFace * face = &mesh->faceL[cur_face]; for(unsigned int i = 0;i < 3;i++) { // If there are texture-coordinates. if(mesh->texels) { memcpy(&texCoords[FinishedFaces*2 + i], mesh->texelL[face->points[ i ]], sizeof(Lib3dsTexel)); } memcpy(&vertices[FinishedFaces*3 + i], mesh->pointL[face->points[ i ]].pos, sizeof(Lib3dsVector)); } FinishedFaces++; } } // Generate a VBO and store it with our vertices. glGenBuffers(1, &m_VertexVBO); glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Lib3dsVector) * 3 * m_TotalFaces, vertices, GL_STATIC_DRAW); // Generate another VBO and store the normals in it. glGenBuffers(1, &m_NormalVBO); glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Lib3dsVector) * 3 * m_TotalFaces, normals, GL_STATIC_DRAW); // Generate a third VBO and store the texture coordinates in it. glGenBuffers(1, &m_TexCoordVBO); glBindBuffer(GL_ARRAY_BUFFER, m_TexCoordVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Lib3dsTexel) * 3 * m_TotalFaces, texCoords, GL_STATIC_DRAW); // Clean up our allocated memory because the data is now stored in the GPU. delete vertices; delete normals; delete texCoords; // We no longer need lib3ds. lib3ds_file_free(m_model); m_model = NULL; } void Object:: Draw() const { // Enable vertex, normal and texture-coordinate arrays. glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Bind the VBO with the normals. glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO); // The pointer for the normals is NULL which means that OpenGL will use the currently bound VBO. glNormalPointer(GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_TexCoordVBO); glTexCoordPointer(2, GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO); glVertexPointer(3, GL_FLOAT, 0, NULL); // Render the triangles. glDrawArrays(GL_TRIANGLES, 0, m_TotalFaces * 3); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); }