Code:
#include "Common.h"
#include "math3d.h"
#include <vector>
#include <string>
const double PI = 3.14159265358979323846;
const double PI_2 = PI * 2;
const double PI_OVER_180 = PI / 180.0;
//GLfloat vOrigin[] = {0.0f, 0.0f, 0.0f};
//GLfloat vAmbientLight[] = {0.3f, 0.3f, 0.3f, 1.0f};
//GLfloat vDiffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f};
//GLfloat vSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
//GLfloat vGrey[] = {0.75f, 0.75f, 0.75f, 1.0f};
//
//GLfloat xRot = 0.0f;
//GLfloat yRot = 0.0f;
//GLfloat zRot = 0.0f;
//GLdouble dFov = 60.0;
//GLfloat zTrans = -100.0f;
//int specShininess = 128;
//bool smoothShading = true;
//bool depthTesting = true;
//bool cullFace = true;
//bool wireframe = false;
//bool light0 = true;
GLfloat red = 1.0f;
GLfloat green = 1.0f;
GLfloat blue = 1.0f;
GLint filtering = GL_LINEAR;
const int TEXTURE_COUNT = 1;
GLuint textures[TEXTURE_COUNT];
std::string resident("UNKNOWN");
GLboolean residences[TEXTURE_COUNT];
template <typename T> inline void SafeDelete(T*& ptr)
{
if (ptr)
{
delete ptr;
ptr = NULL;
}
}
template <typename T> inline void SafeDeleteArray(T*& ptr)
{
if (ptr)
{
delete[] ptr;
ptr = NULL;
}
}
class VBO
{
GLfloat* m_vVerts;
GLfloat* m_vTexCoords;
GLushort* m_Indices;
GLuint m_BufferObjects[3];
int m_NumVerts;
public:
VBO()
: m_vVerts(NULL),
m_vTexCoords(NULL),
m_Indices(NULL),
m_NumVerts(0)
{
}
~VBO()
{
Cleanup();
}
void BeginMesh(GLuint requiredVerts)
{
Cleanup();
std::cout << "Allocating " << requiredVerts * 2 << " bytes for vertices and tex coords\n";
std::cout << "Allocating " << requiredVerts << " bytes for indices\n";
m_vVerts = new GLfloat[requiredVerts * 2];
m_vTexCoords = new GLfloat[requiredVerts * 2];
m_Indices = new GLushort[requiredVerts];
}
void AddVertex(M3DVector2f vert, M3DVector2f vTexCoord)
{
memcpy(m_vVerts + (m_NumVerts * 2), vert, sizeof(M3DVector2f));
memcpy(m_vTexCoords + (m_NumVerts * 2), vTexCoord, sizeof(M3DVector2f));
m_Indices[m_NumVerts] = (GLushort) m_NumVerts;
m_NumVerts++;
}
void EndMesh()
{
if (!m_NumVerts)
{
std::cout << "VBO::EndMesh(): No verts specified\n";
return;
}
glGenBuffers(3, m_BufferObjects);
// Copy data to vid mem
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_NumVerts * 2, m_vVerts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_NumVerts * 2, m_vTexCoords, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferObjects[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * m_NumVerts, m_Indices, GL_STATIC_DRAW);
// Can safely free the vert memory now since GL copies
Cleanup();
}
void Draw()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Verts
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[0]);
glVertexPointer(2, GL_FLOAT, 0, 0);
// Tex coords
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjects[1]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_BufferObjects[2]);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//GLenum err = glGetError();
//if (err != GL_NO_ERROR)
// std::cout << "........\n";
}
void DumpVerts()
{
int i = 0;
std::cout << "\n" << m_NumVerts << " vertices\n";
for ( ; i < m_NumVerts*2; i++)
{
std::cout << m_vVerts[i];
if (!(i % 2))
std::cout << ",";
else
std::cout << "\n";
}
for (i = 0; i < m_NumVerts * 2; i++)
{
std::cout << m_vTexCoords[i];
if (!(i % 2))
std::cout << ",";
else
std::cout << "\n";
}
for (i = 0; i < m_NumVerts; i++)
std::cout << m_Indices[i] << "\n";
}
private:
void Cleanup()
{
SafeDeleteArray(m_vVerts);
SafeDeleteArray(m_vTexCoords);
SafeDeleteArray(m_Indices);
m_NumVerts = 0;
glDeleteBuffers(3, m_BufferObjects);
}
};
VBO vbo;
GLfloat mIdentity[] = { 1.0f, 0.0f, 0.0f, 0.0f, // X column
0.0f, 1.0f, 0.0f, 0.0f, // Y column
0.0f, 0.0f, 1.0f, 0.0f, // Z column
0.0f, 0.0f, 0.0f, 1.0f }; // Translation
// Define targa header. This is only used locally.
#pragma pack(1)
typedef struct
{
GLbyte identsize; // Size of ID field that follows header (0)
GLbyte colorMapType; // 0 = None, 1 = paletted
GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
unsigned short colorMapStart; // First colour map entry
unsigned short colorMapLength; // Number of colors
unsigned char colorMapBits; // bits per palette entry
unsigned short xstart; // image x origin
unsigned short ystart; // image y origin
unsigned short width; // width in pixels
unsigned short height; // height in pixels
GLbyte bits; // bits per pixel (8 16, 24, 32)
GLbyte descriptor; // image descriptor
} TGAHEADER;
#pragma pack(8)
GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
{
FILE *pFile; // File pointer
TGAHEADER tgaHeader; // TGA file header
unsigned long lImageSize; // Size in bytes of image
short sDepth; // Pixel depth;
GLbyte *pBits = NULL; // Pointer to bits
// Default/Failed values
*iWidth = 0;
*iHeight = 0;
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;
// Attempt to open the fil
pFile = fopen(szFileName, "rb");
if(pFile == NULL)
return NULL;
// Read in header (binary)
fread(&tgaHeader, 18/* sizeof(TGAHEADER)*/, 1, pFile);
// Do byte swap for big vs little endian
#ifdef __APPLE__
LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart);
LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength);
LITTLE_ENDIAN_WORD(&tgaHeader.xstart);
LITTLE_ENDIAN_WORD(&tgaHeader.ystart);
LITTLE_ENDIAN_WORD(&tgaHeader.width);
LITTLE_ENDIAN_WORD(&tgaHeader.height);
#endif
// Get width, height, and depth of texture
*iWidth = tgaHeader.width;
*iHeight = tgaHeader.height;
sDepth = tgaHeader.bits / 8;
// Put some validity checks here. Very simply, I only understand
// or care about 8, 24, or 32 bit targa's.
if(tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
return NULL;
// Calculate size of image buffer
lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
// Allocate memory and check for success
pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
if(pBits == NULL)
return NULL;
// Read in the bits
// Check for read error. This should catch RLE or other
// weird formats that I don't want to recognize
if(fread(pBits, lImageSize, 1, pFile) != 1)
{
free(pBits);
return NULL;
}
// Set OpenGL format expected
switch(sDepth)
{
case 3: // Most likely case
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;
break;
case 4:
*eFormat = GL_BGRA_EXT;
*iComponents = GL_RGBA8;
break;
case 1:
*eFormat = GL_LUMINANCE;
*iComponents = GL_LUMINANCE8;
break;
};
// Done with File
fclose(pFile);
// Return pointer to image data
return pBits;
}
template <typename T> inline T Clamp(T value, T min, T max)
{
if (value < min)
value = min;
if (value > max)
value = max;
return value;
}
template <typename T> inline T ClampInPlace(T& value, T min, T max)
{
if (value < min)
value = min;
if (value > max)
value = max;
return value;
}
void ChangeSize(GLsizei width, GLsizei height);
inline double DegToRad(double degrees)
{
return degrees * PI_OVER_180;
}
inline double RadToDeg(double radians)
{
return 180.0 * (PI / radians);
}
const char* VPrintf(const char* format, ...)
{
static char buffers[3][1024];
static int index = 0;
va_list args;
char* destBuff = buffers[index++ & 1];
va_start(args, format);
vsprintf(destBuff, format, args);
va_end(args);
return destBuff;
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
//glutSetWindowTitle(VPrintf("xRot: %f - yRot: %f - zRot: %f - zTrans: %f - FOV: %f - Spec: %d",
// xRot, yRot, zRot, zTrans, dFov, specShininess));
//if (smoothShading)
// glShadeModel(GL_SMOOTH);
//else
// glShadeModel(GL_FLAT);
//
//if (depthTesting)
// glEnable(GL_DEPTH_TEST);
//else
// glDisable(GL_DEPTH_TEST);
//
//if (cullFace)
// glEnable(GL_CULL_FACE);
//else
// glDisable(GL_CULL_FACE);
//
//if (wireframe)
//{
// glPolygonMode(GL_BACK, GL_LINE);
// glPolygonMode(GL_FRONT, GL_LINE);
//}
//else
//{
// glPolygonMode(GL_BACK, GL_FILL);
// glPolygonMode(GL_FRONT, GL_FILL);
//}
//
//if (light0)
// glEnable(GL_LIGHT0);
//else
// glDisable(GL_LIGHT0);
// Pull back along the Z
//glTranslatef(0.0f, 0.0f, zTrans);
//M3DMatrix44f mTransZ;
//m3dTranslationMatrix44(mTransZ, 0.0f, 0.0f, zTrans);
//glMultMatrixf(mTransZ);
glAreTexturesResident(TEXTURE_COUNT, textures, residences);
if (residences[0])
resident = "RESIDENT";
else
resident = "NOT RESIDENT";
glutSetWindowTitle(VPrintf("R: %f - G: %f - B: %f - %s", red, green, blue, resident.c_str()));
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
glColor3f(ClampInPlace(red, 0.0f, 1.0f), ClampInPlace(green, 0.0f, 1.0f), ClampInPlace(blue, 0.0f, 1.0f));
vbo.Draw();
//glBegin(GL_QUADS);
// glTexCoord2i(0, 0);
// glVertex2i(100, 200);
//
// glTexCoord2i(1, 0);
// glVertex2i(200, 200);
//
// glTexCoord2i(1, 1);
// glVertex2i(200, 100);
//
// glTexCoord2i(0, 1);
// glVertex2i(100, 100);
//glEnd();
glutSwapBuffers();
}
void SpecialKeys(int key, int x, int y)
{
//switch (key)
//{
//case GLUT_KEY_LEFT:
// yRot -= 5.0f;
// break;
//case GLUT_KEY_RIGHT:
// yRot += 5.0f;
// break;
//case GLUT_KEY_UP:
// xRot -= 5.0f;
// break;
//case GLUT_KEY_DOWN:
// xRot += 5.0f;
// break;
//case GLUT_KEY_PAGE_UP:
// zRot += 5.0f;
// break;
//case GLUT_KEY_PAGE_DOWN:
// zRot -= 5.0f;
// break;
//case GLUT_KEY_HOME:
// zTrans += 10.0f;
// break;
//case GLUT_KEY_END:
// zTrans -= 10.0f;
// break;
//case GLUT_KEY_F1:
// smoothShading = !smoothShading;
// break;
//case GLUT_KEY_F2:
// depthTesting = !depthTesting;
// break;
//case GLUT_KEY_F3:
// cullFace = !cullFace;
// break;
//case GLUT_KEY_F4:
// wireframe = !wireframe;
// break;
//case GLUT_KEY_F5:
// dFov += 10.0;
// ChangeSize(800, 600);
// break;
//case GLUT_KEY_F6:
// dFov -= 10.0;
// ChangeSize(800, 600);
// break;
//case GLUT_KEY_F7:
// light0 = !light0;
// break;
//case GLUT_KEY_F8:
// specShininess += 1;
// break;
//case GLUT_KEY_F9:
// specShininess -= 1;
// break;
//}
switch (key)
{
case GLUT_KEY_F1:
red += 0.1f;
break;
case GLUT_KEY_F2:
red -= 0.1f;
break;
case GLUT_KEY_F3:
green += 0.1f;
break;
case GLUT_KEY_F4:
green -= 0.1f;
break;
case GLUT_KEY_F5:
blue += 0.1f;
break;
case GLUT_KEY_F6:
blue -= 0.1f;
break;
case GLUT_KEY_F11:
filtering = GL_LINEAR;
break;
case GLUT_KEY_F12:
filtering = GL_NEAREST;
break;
}
glutPostRedisplay();
}
void TimerFunction(int value)
{
glutPostRedisplay();
glutTimerFunc(33, TimerFunction, 1);
}
void SetupRC()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLbyte* bytes;
GLint width, height, comp;
GLenum fmt;
glGenTextures(TEXTURE_COUNT, textures);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
bytes = gltLoadTGA("AILogo.tga", &width, &height, &comp, &fmt);
glTexImage2D(GL_TEXTURE_2D, 0, comp, width, height, 0, fmt, GL_UNSIGNED_BYTE, bytes);
free(bytes);
glAreTexturesResident(TEXTURE_COUNT, textures, residences);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
//glBegin(GL_QUADS);
// glTexCoord2i(0, 0);
// glVertex2i(100, 200);
//
// glTexCoord2i(1, 0);
// glVertex2i(200, 200);
//
// glTexCoord2i(1, 1);
// glVertex2i(200, 100);
//
// glTexCoord2i(0, 1);
// glVertex2i(100, 100);
//glEnd();
M3DVector2f lowerLeft = {100, 200};
M3DVector2f lowerLeftT = {0, 0};
M3DVector2f lowerRight = {200, 200};
M3DVector2f lowerRightT = {1, 0};
M3DVector2f upperRight = {200, 100};
M3DVector2f upperRightT = {1, 1};
M3DVector2f upperLeft = {100, 100};
M3DVector2f upperLeftT = {0, 1};
vbo.BeginMesh(4);
vbo.AddVertex(lowerLeft, lowerLeftT);
vbo.AddVertex(lowerRight, lowerRightT);
vbo.AddVertex(upperRight, upperRightT);
vbo.AddVertex(upperLeft, upperLeftT);
vbo.DumpVerts();
vbo.EndMesh();
/*
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
If you want to simply replace the color of the underlying geometry, you can specify
GL_REPLACE for the environment mode. Doing so replaces fragment colors from the geom-
etry directly with the texel colors. Making this change eliminates any effect on the texture
from the underlying geometry. If the texture has an alpha channel, you can enable blend-
ing (or use the alpha test), and you can use this mode to create transparent geometry
patterned after the alpha channel in the texture map.
*/
glEnable(GL_TEXTURE_2D);
//glShadeModel(GL_SMOOTH);
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_STENCIL_TEST);
//glEnable(GL_LIGHTING);
//glEnable(GL_COLOR_MATERIAL);
//glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vAmbientLight);
//glLightfv(GL_LIGHT0, GL_AMBIENT, vAmbientLight);
//glLightfv(GL_LIGHT0, GL_DIFFUSE, vDiffuseLight);
//glLightfv(GL_LIGHT0, GL_SPECULAR, vSpecular);
//glDisable(GL_BLEND);
//std::cout << "OpenGL Setup\n\n";
//int stackDepth;
//glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &stackDepth);
//std::cout << "Modelview matrix stack depth: " << stackDepth << "\n";
}
void ShutdownRC()
{
glDeleteTextures(TEXTURE_COUNT, textures);
}
void ChangeSize(GLsizei width, GLsizei height)
{
if (height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(mIdentity);
//GLfloat aspectRatio = (GLfloat) width / (GLfloat) height;
//gluPerspective(dFov, aspectRatio, 1.0, -1.0);
glOrtho(0, width, height, 0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(mIdentity);
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL Fiddle");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
//glutTimerFunc(33, TimerFunction, 1);
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}