//// GLCanvas.h /////////////////////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GLCANVAS_H
#define GLCANVAS_H
#include <gl/glew.h> //must come first before other gl type headers
#include "wx/glcanvas.h"
#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#else
#include <windows.h>
#include <GL/glu.h>
#include <GL/gl.h>
#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);
}