3D C/C++ tutorials -> OpenGL 2.1 -> Loading, picking and moving objects
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
opengl_tutorials_win32_framework.h
...
class CObject
{
public:
bool Movable, CullFace;
GLenum FrontFace;
int TrianglesCount;
GLuint VBO[3];
CTexture Texture;
vec2 *TexCoords;
vec3 *Normals, *Vertices, Color, Min, Max, Position;
public:
CObject();
~CObject();
void CreateSphere(float Radius, int Resolution = 16, bool InvertNormals = false);
void Destroy();
void InitVertexBuffers();
bool Load(char *Directory, char *ObjFileName);
void Rotate(float Angle, const vec3 &Axis);
void Scale(float ScaleFactor);
void Translate(const vec3 &Translation);
protected:
void AllocateMemory();
void GetMinMax();
bool ParseMtl(char *Directory, char *MtlFileName);
bool ReadSource(char *Directory, char *FileName, char **Source, long &Length);
void SetDefaults();
};
...
class COpenGLRenderer
{
protected:
int Width, Height;
mat4x4 Model, View, Projection, ProjectionBiasInverse;
CShaderProgram Shader;
int ObjectsCount, LightObjectID;
CObject *Objects;
int SelectedObject;
float PlaneD;
vec3 SelectedPoint, PlaneNormal;
public:
bool ShowAxisGrid, WireFrame, Texturing;
public:
COpenGLRenderer();
~COpenGLRenderer();
bool Init();
void Render(float FrameTime);
void Resize(int Width, int Height);
void Destroy();
void MoveSelectedObject(int x, int y);
void SelectObject(int x, int y);
};
...
opengl_tutorials_win32_framework.cpp
...
CObject::CObject()
{
SetDefaults();
}
CObject::~CObject()
{
}
void CObject::CreateSphere(float Radius, int Resolution, bool InvertNormals)
{
if(Resolution < 16) Resolution = 16;
if(Resolution % 4) Resolution += 4 - Resolution % 4;
TrianglesCount = Resolution * (Resolution / 4 - 1) * 4 + Resolution * 2;
AllocateMemory();
float angle = (float)M_PI * 2.0f / Resolution;
vec3 a, b, c, d;
vec2 tca, tcb, tcc, tcd;
int i = 0;
float r = (float)Resolution, r4 = (float)Resolution / 2.0f;
for(int y = 0; y < Resolution / 4; y++)
{
for(int xz = 0; xz < Resolution; xz++)
{
if(y < Resolution / 4 - 1)
{
a = vec3(- sin(angle * (xz + 0)) * cos(angle * (y + 0)), sin(angle * (y + 0)), - cos(angle * (xz + 0)) * cos(angle * (y + 0)));
b = vec3(- sin(angle * (xz + 1)) * cos(angle * (y + 0)), sin(angle * (y + 0)), - cos(angle * (xz + 1)) * cos(angle * (y + 0)));
c = vec3(- sin(angle * (xz + 1)) * cos(angle * (y + 1)), sin(angle * (y + 1)), - cos(angle * (xz + 1)) * cos(angle * (y + 1)));
d = vec3(- sin(angle * (xz + 0)) * cos(angle * (y + 1)), sin(angle * (y + 1)), - cos(angle * (xz + 0)) * cos(angle * (y + 1)));
tca = TexCoords[i] = vec2((xz + 0) / r, 0.5f + (y + 0) / r4);
tcb = TexCoords[i] = vec2((xz + 1) / r, 0.5f + (y + 0) / r4);
tcc = TexCoords[i] = vec2((xz + 1) / r, 0.5f + (y + 1) / r4);
tcd = TexCoords[i] = vec2((xz + 0) / r, 0.5f + (y + 1) / r4);
TexCoords[i] = tca; Normals[i] = a; Vertices[i++] = a * Radius;
TexCoords[i] = tcb; Normals[i] = b; Vertices[i++] = b * Radius;
TexCoords[i] = tcc; Normals[i] = c; Vertices[i++] = c * Radius;
TexCoords[i] = tcc; Normals[i] = c; Vertices[i++] = c * Radius;
TexCoords[i] = tcd; Normals[i] = d; Vertices[i++] = d * Radius;
TexCoords[i] = tca; Normals[i] = a; Vertices[i++] = a * Radius;
a.y = -a.y;
b.y = -b.y;
c.y = -c.y;
d.y = -d.y;
tca.y = 1.0f - tca.y;
tcb.y = 1.0f - tcb.y;
tcc.y = 1.0f - tcc.y;
tcd.y = 1.0f - tcd.y;
TexCoords[i] = tcd; Normals[i] = d; Vertices[i++] = d * Radius;
TexCoords[i] = tcc; Normals[i] = c; Vertices[i++] = c * Radius;
TexCoords[i] = tcb; Normals[i] = b; Vertices[i++] = b * Radius;
TexCoords[i] = tcb; Normals[i] = b; Vertices[i++] = b * Radius;
TexCoords[i] = tca; Normals[i] = a; Vertices[i++] = a * Radius;
TexCoords[i] = tcd; Normals[i] = d; Vertices[i++] = d * Radius;
}
else
{
a = vec3(- sin(angle * (xz + 0)) * cos(angle * (y + 0)), sin(angle * (y + 0)), - cos(angle * (xz + 0)) * cos(angle * (y + 0)));
b = vec3(- sin(angle * (xz + 1)) * cos(angle * (y + 0)), sin(angle * (y + 0)), - cos(angle * (xz + 1)) * cos(angle * (y + 0)));
c = vec3(0.0f, 1.0f, 0.0f);
tca = TexCoords[i] = vec2((xz + 0) / r, 0.5f + (y + 0) / r4);
tcb = TexCoords[i] = vec2((xz + 1) / r, 0.5f + (y + 0) / r4);
tcc = TexCoords[i] = vec2((xz + 0.5f) / r, 1.0f);
TexCoords[i] = tca; Normals[i] = a; Vertices[i++] = a * Radius;
TexCoords[i] = tcb; Normals[i] = b; Vertices[i++] = b * Radius;
TexCoords[i] = tcc; Normals[i] = c; Vertices[i++] = c * Radius;
a.y = -a.y;
b.y = -b.y;
c.y = -c.y;
tca.y = 1.0f - tca.y;
tcb.y = 1.0f - tcb.y;
tcc.y = 1.0f - tcc.y;
TexCoords[i] = tca; Normals[i] = a; Vertices[i++] = a * Radius;
TexCoords[i] = tcc; Normals[i] = c; Vertices[i++] = c * Radius;
TexCoords[i] = tcb; Normals[i] = b; Vertices[i++] = b * Radius;
}
}
}
if(InvertNormals)
{
for(int i = 0; i < TrianglesCount * 3; i++)
{
Normals[i] = -Normals[i];
}
}
Min = vec3(-Radius, -Radius, -Radius);
Max = vec3(Radius, Radius, Radius);
}
void CObject::Destroy()
{
if(gl_version >= 15)
{
glDeleteBuffers(3, VBO);
}
Texture.Delete();
delete [] TexCoords;
delete [] Normals;
delete [] Vertices;
SetDefaults();
}
void CObject::InitVertexBuffers()
{
if(gl_version >= 15)
{
glDeleteBuffers(3, VBO);
glGenBuffers(3, VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, TrianglesCount * 3 * 2 * 4, TexCoords, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, TrianglesCount * 3 * 3 * 4, Normals, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferData(GL_ARRAY_BUFFER, TrianglesCount * 3 * 3 * 4, Vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
bool CObject::Load(char *Directory, char *ObjFileName)
{
char *ObjSource;
long ObjLength;
if(!ReadSource(Directory, ObjFileName, &ObjSource, ObjLength)) return false;
char *Line, *End = ObjSource + ObjLength;
float x, y, z;
int texcoordscount = 0, normalscount = 0, verticescount = 0;
int i1, i2, i3, i4, i5, i6, i7, i8, i9;
int v = 0, n = 0, t = 0, T = 0;
Line = ObjSource;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(Line[0] == 'm' && Line[1] == 't' && Line[2] == 'l' && Line[3] == 'l' && Line[4] == 'i' && Line[5] == 'b' && (Line[6] == ' ' || Line[6] == '\t'))
{
char *MtlFileName = Line + 6;
while(MtlFileName < End && (*MtlFileName == ' ' || *MtlFileName == '\t')) MtlFileName++;
if(!ParseMtl(Directory, MtlFileName))
{
delete [] ObjSource;
return false;
}
}
else if(sscanf(Line, "vt %f %f", &x, &y) == 2)
{
texcoordscount++;
}
else if(sscanf(Line, "vn %f %f %f", &x, &y, &z) == 3)
{
normalscount++;
}
else if(sscanf(Line, "v %f %f %f", &x, &y, &z) == 3)
{
verticescount++;
}
else if(sscanf(Line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d//%d %d//%d %d//%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d/%d %d/%d %d/%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
TrianglesCount++;
}
else if(sscanf(Line, "f %d %d %d", &i1, &i2, &i3) == 3)
{
TrianglesCount++;
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
vec2 *texcoords = NULL;
vec3 *normals = NULL;
vec3 *vertices = NULL;
if(texcoordscount > 0) texcoords = new vec2[texcoordscount];
if(normalscount > 0) normals = new vec3[normalscount];
if(verticescount > 0) vertices = new vec3[verticescount];
AllocateMemory();
Line = ObjSource;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(sscanf(Line, "vt %f %f", &x, &y) == 2)
{
texcoords[t++] = vec2(x, y);
}
else if(sscanf(Line, "vn %f %f %f", &x, &y, &z) == 3)
{
normals[n++] = vec3(x, y ,z);
}
else if(sscanf(Line, "v %f %f %f", &x, &y, &z) == 3)
{
vertices[v++] = vec3(x, y ,z);
}
else if(sscanf(Line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9) == 9)
{
TexCoords[T] = texcoords[i2 - 1];
Normals[T] = normals[i3 - 1];
Vertices[T++] = vertices[i1 - 1];
TexCoords[T] = texcoords[i5 - 1];
Normals[T] = normals[i6 - 1];
Vertices[T++] = vertices[i4 - 1];
TexCoords[T] = texcoords[i8 - 1];
Normals[T] = normals[i9 - 1];
Vertices[T++] = vertices[i7 - 1];
}
else if(sscanf(Line, "f %d//%d %d//%d %d//%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
Normals[T] = normals[i2 - 1];
Vertices[T++] = vertices[i1 - 1];
Normals[T] = normals[i4 - 1];
Vertices[T++] = vertices[i3 - 1];
Normals[T] = normals[i6 - 1];
Vertices[T++] = vertices[i5 - 1];
}
else if(sscanf(Line, "f %d/%d %d/%d %d/%d", &i1, &i2, &i3, &i4, &i5, &i6) == 6)
{
if(texcoords != NULL && i1 - 1 < texcoordscount) TexCoords[T] = texcoords[i1 - 1];
if(texcoords != NULL && i2 - 1 < texcoordscount) TexCoords[T] = texcoords[i2 - 1];
if(normals != NULL && i1 - 1 < normalscount) Normals[T] = normals[i1 - 1];
if(normals != NULL && i2 - 1 < normalscount) Normals[T] = normals[i2 - 1];
Vertices[T++] = vertices[i1 - 1];
if(texcoords != NULL && i3 - 1 < texcoordscount) TexCoords[T] = texcoords[i3 - 1];
if(texcoords != NULL && i4 - 1 < texcoordscount) TexCoords[T] = texcoords[i4 - 1];
if(normals != NULL && i3 - 1 < normalscount) Normals[T] = normals[i3 - 1];
if(normals != NULL && i4 - 1 < normalscount) Normals[T] = normals[i4 - 1];
Vertices[T++] = vertices[i3 - 1];
if(texcoords != NULL && i5 - 1 < texcoordscount) TexCoords[T] = texcoords[i5 - 1];
if(texcoords != NULL && i6 - 1 < texcoordscount) TexCoords[T] = texcoords[i6 - 1];
if(normals != NULL && i5 - 1 < normalscount) Normals[T] = normals[i5 - 1];
if(normals != NULL && i6 - 1 < normalscount) Normals[T] = normals[i6 - 1];
Vertices[T++] = vertices[i5 - 1];
}
else if(sscanf(Line, "f %d %d %d", &i1, &i2, &i3) == 3)
{
if(texcoords != NULL && i1 - 1 < texcoordscount) TexCoords[T] = texcoords[i1 - 1];
if(normals != NULL && i1 - 1 < normalscount) Normals[T] = normals[i1 - 1];
Vertices[T++] = vertices[i1 - 1];
if(texcoords != NULL && i2 - 1 < texcoordscount) TexCoords[T] = texcoords[i2 - 1];
if(normals != NULL && i2 - 1 < normalscount) Normals[T] = normals[i2 - 1];
Vertices[T++] = vertices[i2 - 1];
if(texcoords != NULL && i3 - 1 < texcoordscount) TexCoords[T] = texcoords[i3 - 1];
if(normals != NULL && i3 - 1 < normalscount) Normals[T] = normals[i3 - 1];
Vertices[T++] = vertices[i3 - 1];
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
delete [] texcoords;
delete [] normals;
delete [] vertices;
delete [] ObjSource;
if(normalscount == 0)
{
for(int i = 0; i < TrianglesCount * 3; i += 3)
{
vec3 a = Vertices[i + 1] - Vertices[i];
vec3 b = Vertices[i + 2] - Vertices[i];
vec3 normal = normalize(cross(a, b));
Normals[i + 0] = normal;
Normals[i + 1] = normal;
Normals[i + 2] = normal;
}
}
GetMinMax();
return true;
}
void CObject::Rotate(float Angle, const vec3 &Axis)
{
mat4x4 Rotation = RotationMatrix(Angle, Axis);
for(int i = 0; i < TrianglesCount * 3; i++)
{
Normals[i] = Rotation * Normals[i];
Vertices[i] = Rotation * Vertices[i];
}
GetMinMax();
}
void CObject::Scale(float ScaleFactor)
{
for(int i = 0; i < TrianglesCount * 3; i++)
{
Vertices[i] *= ScaleFactor;
}
Min *= ScaleFactor;
Max *= ScaleFactor;
}
void CObject::Translate(const vec3 &Translation)
{
for(int i = 0; i < TrianglesCount * 3; i++)
{
Vertices[i] += Translation;
}
Min += Translation;
Max += Translation;
}
void CObject::AllocateMemory()
{
delete [] TexCoords;
delete [] Normals;
delete [] Vertices;
TexCoords = new vec2[TrianglesCount * 3];
Normals = new vec3[TrianglesCount * 3];
Vertices = new vec3[TrianglesCount * 3];
}
void CObject::GetMinMax()
{
for(int i = 0; i < TrianglesCount * 3; i++)
{
if(i == 0)
{
Min = Max = Vertices[i];
}
else
{
if(Min.x > Vertices[i].x) Min.x = Vertices[i].x;
if(Min.y > Vertices[i].y) Min.y = Vertices[i].y;
if(Min.z > Vertices[i].z) Min.z = Vertices[i].z;
if(Max.x < Vertices[i].x) Max.x = Vertices[i].x;
if(Max.y < Vertices[i].y) Max.y = Vertices[i].y;
if(Max.z < Vertices[i].z) Max.z = Vertices[i].z;
}
}
}
bool CObject::ParseMtl(char *Directory, char *MtlFileName)
{
char *MtlSource;
long MtlLength;
if(!ReadSource(Directory, MtlFileName, &MtlSource, MtlLength)) return false;
char *Line = MtlSource, *End = MtlSource + MtlLength;
bool Error = false;
while(Line < End)
{
while(Line < End && (*Line == ' ' || *Line == '\t')) Line++;
if(Line[0] == 'm' && Line[1] == 'a' && Line[2] == 'p' && Line[3] == '_' && Line[4] == 'K' && Line[5] == 'a' && (Line[6] == ' ' || Line[6] == '\t'))
{
char *Texture2DFileName = Line + 6;
while(Texture2DFileName < End && (*Texture2DFileName == ' ' || *Texture2DFileName == '\t')) Texture2DFileName++;
Error |= !Texture.LoadTexture2D(CString(Directory) + Texture2DFileName);
}
while(Line < End && *Line != 0) Line++;
while(Line < End && *Line == 0) Line++;
}
delete [] MtlSource;
return !Error;
}
bool CObject::ReadSource(char *Directory, char *FileName, char **Source, long &Length)
{
CString PathFileName = ModuleDirectory + Directory + FileName;
FILE *File;
if(fopen_s(&File, PathFileName, "rb") != 0)
{
ErrorLog.Append("Error loading file " + PathFileName + "!\r\n");
return false;
}
fseek(File, 0, SEEK_END);
Length = ftell(File);
fseek(File, 0, SEEK_SET);
*Source = new char[Length + 1];
fread(*Source, 1, Length, File);
(*Source)[Length] = 0;
fclose(File);
for(long i = 0; i < Length; i++)
{
if((*Source)[i] == '\r' || (*Source)[i] == '\n') (*Source)[i] = 0;
}
return true;
}
void CObject::SetDefaults()
{
Movable = true;
CullFace = true;
FrontFace = GL_CCW;
TrianglesCount = 0;
for(int i = 0; i < 3; i++)
{
VBO[i] = 0;
}
TexCoords = NULL;
Normals = NULL;
Vertices = NULL;
Color = vec3(1.0f, 1.0f, 1.0f);
Position = vec3(0.0f, 0.0f, 0.0f);
}
...
COpenGLRenderer::COpenGLRenderer()
{
ShowAxisGrid = true;
WireFrame = false;
Texturing = true;
SelectedObject = -1;
Camera.SetViewMatrixPointer(&View);
}
COpenGLRenderer::~COpenGLRenderer()
{
}
bool COpenGLRenderer::Init()
{
/*if(gl_version < 21)
{
ErrorLog.Set("OpenGL 2.1 not supported!");
return false;
}*/
bool Error = false;
ObjectsCount = 6;
Objects = new CObject[ObjectsCount];
Error |= !Objects[0].Load("Models\\Thor\\", "thor.obj");
Error |= !Objects[1].Load("Models\\Spongebob\\", "spongebob_bind.obj");
Error |= !Objects[2].Load("Models\\Alien2\\", "alien2.obj");
Error |= !Objects[3].Load("Models\\Teapot\\", "teapot.obj");
Error |= !Objects[4].Texture.LoadTexture2D("earthmap.jpg");
if(gl_version >= 21)
{
Error |= !Shader.Load("glsl120shader.vs", "glsl120shader.fs");
}
if(Error)
{
return false;
}
Objects[0].Rotate(-90.0f, vec3(0.0f, 1.0f, 0.0f));
Objects[0].Scale(1.75f / (Objects[0].Max.y - Objects[0].Min.y));
Objects[0].Translate(vec3(-(Objects[0].Min.x + Objects[0].Max.x) / 2.0f, -Objects[0].Min.y, -(Objects[0].Min.z + Objects[0].Max.z) / 2.0f));
Objects[0].Position = vec3(0.5f, 0.0f, 0.0f);
Objects[1].Scale(0.875f / (Objects[1].Max.y - Objects[1].Min.y));
Objects[1].Translate(vec3(-(Objects[1].Min.x + Objects[1].Max.x) / 2.0f, -Objects[1].Min.y, -(Objects[1].Min.z + Objects[1].Max.z) / 2.0f));
Objects[1].Position = vec3(-0.5f, 0.0f, 0.0f);
Objects[2].Scale(1.0f / (Objects[2].Max.y - Objects[2].Min.y));
Objects[2].Translate(vec3(-(Objects[2].Min.x + Objects[2].Max.x) / 2.0f, -Objects[2].Min.y, -(Objects[2].Min.z + Objects[2].Max.z) / 2.0f));
Objects[2].Position = vec3(0.0f, 0.0f, -2.5f);
Objects[3].Color = vec3(1.0f, 0.5f, 0.0f);
Objects[3].CullFace = false;
Objects[3].FrontFace = GL_CW;
Objects[3].Scale(0.25f / (Objects[3].Max.y - Objects[3].Min.y));
Objects[3].Translate(vec3(-(Objects[3].Min.x + Objects[3].Max.x) / 2.0f, -Objects[3].Min.y, -(Objects[3].Min.z + Objects[3].Max.z) / 2.0f));
Objects[3].Position = vec3(0.0f, 0.0f, 0.0f);
Objects[4].CreateSphere(0.5f, 32);
Objects[4].Position = vec3(0.0f, 0.5f, -1.0f);
Objects[5].CreateSphere(0.03125f, 16, true);
Objects[5].Position = vec3(0.0f, 2.0f, 1.0f);
LightObjectID = 5;
for(int i = 0; i < ObjectsCount; i++)
{
Objects[i].InitVertexBuffers();
}
if(gl_version >= 21)
{
Shader.UniformLocations = new GLuint[1];
Shader.UniformLocations[0] = glGetUniformLocation(Shader, "Texturing");
}
GLfloat LightModelAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LightModelAmbient);
GLfloat LightAmbient[] = {0.25f, 0.25f, 0.25f, 1.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);
GLfloat LightDiffuse[] = {0.75f, 0.75f, 0.75f, 1.0f};
glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
GLfloat MaterialAmbient[] = {0.25f, 0.25f, 0.25f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MaterialAmbient);
GLfloat MaterialDiffuse[] = {0.75f, 0.75f, 0.75f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialDiffuse);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
Camera.LookAt(vec3(0.0f, 0.875f, 0.0f), vec3(0.0f, 0.875f, 2.5f), true);
return true;
}
void COpenGLRenderer::Render(float FrameTime)
{
int gl_version = use_gl_version < ::gl_version ? use_gl_version : ::gl_version;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&View);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// render axises and grid -------------------------------------------------------------------------------------------------
if(ShowAxisGrid)
{
glLineWidth(2.0f);
glBegin(GL_LINES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.1f, 0.0f); glVertex3f(1.1f, -0.1f, 0.0f);
glVertex3f(1.1f, 0.1f, 0.0f); glVertex3f(1.0f, -0.1f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, 1.0f, 0.0f);
glVertex3f(-0.05f, 1.25f, 0.0f); glVertex3f(0.0f, 1.15f, 0.0f);
glVertex3f(0.05f,1.25f, 0.0f); glVertex3f(0.0f, 1.15f, 0.0f);
glVertex3f(0.0f,1.15f, 0.0f); glVertex3f(0.0f, 1.05f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f,0.0f,0.0f); glVertex3f(0.0f, 0.0f, 1.0f);
glVertex3f(-0.05f,0.1f,1.05f); glVertex3f(0.05f, 0.1f, 1.05f);
glVertex3f(0.05f,0.1f,1.05f); glVertex3f(-0.05f, -0.1f, 1.05f);
glVertex3f(-0.05f,-0.1f,1.05f); glVertex3f(0.05f, -0.1f, 1.05f);
glEnd();
glLineWidth(1.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINES);
float d = 50.0f;
for(float i = -d; i <= d; i += 1.0f)
{
glVertex3f(i, 0.0f, -d);
glVertex3f(i, 0.0f, d);
glVertex3f(-d, 0.0f, i);
glVertex3f(d, 0.0f, i);
}
glEnd();
}
// render objects ---------------------------------------------------------------------------------------------------------
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, &vec4(Objects[LightObjectID].Position, 1.0f));
if(WireFrame)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
if(gl_version >= 21)
{
glUseProgram(Shader);
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
for(int i = 0; i < ObjectsCount; i++)
{
if(Objects[i].TrianglesCount <= 0) continue;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&View);
glTranslatef(Objects[i].Position.x, Objects[i].Position.y, Objects[i].Position.z);
if(!WireFrame && Objects[i].CullFace)
{
glEnable(GL_CULL_FACE);
}
glColor3fv(&Objects[i].Color);
bool Texturing = this->Texturing && Objects[i].Texture;
if(Texturing)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Objects[i].Texture);
}
if(gl_version >= 21)
{
glUniform1i(Shader.UniformLocations[0], Texturing ? 1 : 0);
}
if(gl_version >= 15)
{
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[0]);
glTexCoordPointer(2, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[1]);
glNormalPointer(GL_FLOAT, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[2]);
glVertexPointer(3, GL_FLOAT, 0, NULL);
}
else
{
glTexCoordPointer(2, GL_FLOAT, 0, Objects[i].TexCoords);
glNormalPointer(GL_FLOAT, 0, Objects[i].Normals);
glVertexPointer(3, GL_FLOAT, 0, Objects[i].Vertices);
}
glFrontFace(Objects[i].FrontFace);
glDrawArrays(GL_TRIANGLES, 0, Objects[i].TrianglesCount * 3);
if(Texturing)
{
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
if(!WireFrame && Objects[i].CullFace)
{
glDisable(GL_CULL_FACE);
}
}
if(gl_version >= 15)
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
if(gl_version >= 21)
{
glUseProgram(0);
}
if(WireFrame)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
}
void COpenGLRenderer::Resize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
glViewport(0, 0, Width, Height);
Projection = PerspectiveProjectionMatrix(45.0f, (float)Width, (float)Height, 0.125f, 512.0f);
ProjectionBiasInverse = PerspectiveProjectionMatrixInverse(Projection) * BiasMatrixInverse();
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Projection);
}
void COpenGLRenderer::Destroy()
{
for(int i = 0; i < ObjectsCount; i++)
{
Objects[i].Destroy();
}
delete [] Objects;
if(gl_version >= 21)
{
Shader.Delete();
}
}
void COpenGLRenderer::MoveSelectedObject(int x, int y)
{
if(SelectedObject < 0 || SelectedObject >= ObjectsCount || !Objects[SelectedObject].Movable) return;
y = Height - 1 - y;
float s = (float)x / (float)(Width - 1);
float t = (float)y / (float)(Height - 1);
vec4 Point = ViewMatrixInverse(View) * (ProjectionBiasInverse * vec4(s, t, 0.5f, 1.0f));
Point /= Point.w;
vec3 Ray = normalize(Point - Camera.Position);
float NdotR = -dot(PlaneNormal, Ray);
if(NdotR != 0.0f)
{
float Distance = (dot(PlaneNormal, Camera.Position) + PlaneD) / NdotR;
vec3 Point = Ray * Distance + Camera.Position;
vec3 Offset = Point - SelectedPoint;
SelectedPoint = Point;
Objects[SelectedObject].Position += Offset;
}
}
void COpenGLRenderer::SelectObject(int x, int y)
{
int gl_version = use_gl_version < ::gl_version ? use_gl_version : ::gl_version;
y = Height - 1 - y;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
for(int i = 0; i < ObjectsCount; i++)
{
if(Objects[i].TrianglesCount <= 0) continue;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&View);
glTranslatef(Objects[i].Position.x, Objects[i].Position.y, Objects[i].Position.z);
if(Objects[i].CullFace)
{
glEnable(GL_CULL_FACE);
}
int ID = i + 1;
glColor3ub(ID & 0xFF, (ID >> 8) & 0xFF, (ID >> 16) & 0xFF);
if(gl_version >= 15)
{
glBindBuffer(GL_ARRAY_BUFFER, Objects[i].VBO[2]);
glVertexPointer(3, GL_FLOAT, 0, NULL);
}
else
{
glVertexPointer(3, GL_FLOAT, 0, Objects[i].Vertices);
}
glFrontFace(Objects[i].FrontFace);
glDrawArrays(GL_TRIANGLES, 0, Objects[i].TrianglesCount * 3);
if(Objects[i].CullFace)
{
glDisable(GL_CULL_FACE);
}
}
if(gl_version >= 15)
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_DEPTH_TEST);
BYTE Pixel[4];
glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &Pixel);
SelectedObject = (Pixel[0] | (Pixel[1] << 8) | (Pixel[2] << 16)) - 1;
if(SelectedObject >= 0 && SelectedObject < ObjectsCount)
{
float s = (float)x / (float)(Width - 1);
float t = (float)y / (float)(Height - 1);
float Depth;
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &Depth);
vec4 Point = ViewMatrixInverse(View) * (ProjectionBiasInverse * vec4(s, t, Depth, 1.0f));
Point /= Point.w;
SelectedPoint = Point;
float omcospi4 = 1.0f - cos((float)M_PI / 4.0f);
if(Camera.Z.y > -omcospi4 && Camera.Z.y < omcospi4)
{
PlaneNormal = normalize(vec3(Camera.Z.x, 0.0f, Camera.Z.z));
}
else
{
PlaneNormal = vec3(0.0f, 1.0f, 0.0f);
}
PlaneD = -dot(PlaneNormal, SelectedPoint);
}
}
...
void CWnd::OnKeyDown(UINT Key)
{
switch(Key)
{
case VK_F1:
OpenGLRenderer.ShowAxisGrid = !OpenGLRenderer.ShowAxisGrid;
break;
case VK_F2:
OpenGLRenderer.WireFrame = !OpenGLRenderer.WireFrame;
break;
case VK_F3:
OpenGLRenderer.Texturing = !OpenGLRenderer.Texturing;
break;
case '1':
use_gl_version = 11;
break;
case '2':
use_gl_version = 15;
break;
case '3':
use_gl_version = 21;
break;
}
}
void CWnd::OnLButtonDown(int cx, int cy)
{
OpenGLRenderer.SelectObject(cx, cy);
}
void CWnd::OnMouseMove(int cx, int cy)
{
if(GetKeyState(VK_LBUTTON) & 0x80)
{
OpenGLRenderer.MoveSelectedObject(cx, cy);
}
...
}
...
glsl120shader.vs
#version 120
varying vec3 Position, Normal;
void main()
{
Position = (gl_ModelViewMatrix * gl_Vertex).xyz;
Normal = gl_NormalMatrix * gl_Normal;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
glsl120shader.fs
#version 120
uniform sampler2D Texture;
uniform int Texturing;
varying vec3 Position, Normal;
void main()
{
vec3 LightDirection = gl_LightSource[0].position.xyz - Position;
float LightDistance2 = dot(LightDirection, LightDirection);
float LightDistance = sqrt(LightDistance2);
LightDirection /= LightDistance;
float Attenuation = gl_LightSource[0].constantAttenuation;
Attenuation += gl_LightSource[0].linearAttenuation * LightDistance;
Attenuation += gl_LightSource[0].quadraticAttenuation * LightDistance2;
float NdotLD = max(dot(normalize(Normal), LightDirection), 0.0);
vec3 Light = (gl_LightSource[0].ambient.rgb + gl_LightSource[0].diffuse.rgb * NdotLD) / Attenuation;
gl_FragColor.rgb = gl_Color.rgb;
if(Texturing == 1) gl_FragColor.rgb *= texture2D(Texture, gl_TexCoord[0].st).rgb;
gl_FragColor.rgb *= Light;
}
Download
|