Right now I have a UV mapped cube using a VBO. The textures are applied from a single TGA file. See picture:
Instead of reading from a single TGA file I would like to be able to read the texture for each side of the cube from individual files. I’ve looked at using a texture array or just cramming all of the individual files into one texture at run-time (what some people are calling a “texture-atlas”?). I’m not sure what would be best solution.
The end goal is to be able to apply an arbitrary number of textures from individual files to a VBO (which won’t necessarily be a cube, I just picked a cube for simplicity’s sake). So cube maps are out for that reason.
Here are the relevant sections of the code. Any help on how to accomplish this would be appreciated.
struct vertexType
{
GLfloat xPos,yPos,zPos;
GLfloat xNormal,yNormal,zNormal;
GLfloat uTCoord,vTCoord;
};
GLShaderManager shaderManager;
std::vector<vertexType> vertexArray;
std::vector<GLushort> vertexIndex;
std::vector<GLfloat> fNormals;
GLuint vdataBufferID; //vertex data
GLuint viBufferID; //vertex index buffer
GLFrame cameraFrame;
GLFrame modelFrame;
bool rightMouseDown;
int oldMouseX,oldMouseY;
int deltaMouseX,deltaMouseY;
GLfloat lightPos[]={0.0f,1.0f,0.0f};
GLfloat lightColor[]={1.0f,1.0f,1.0f,1.0f};
GLuint textureID;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrustum frustum;
GLGeometryTransform transformPipeline;
//texture and draw
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);
void loadVertexArray(GLfloat x,GLfloat y,GLfloat z, GLfloat u, GLfloat v);
void drawTriCube();
//initialization
void initTriCube(float xPos,float yPos,float zPos);
void SetupRC();
//calculate normals
void calcFaceNormal(GLfloat x0,GLfloat y0,GLfloat z0,
GLfloat x1,GLfloat y1,GLfloat z1,
GLfloat x2,GLfloat y2,GLfloat z2,
GLfloat & fNormalX, GLfloat & fNormalY, GLfloat & fNormalZ);
void getFaceNormal(unsigned int triNum, GLfloat & fnx,GLfloat & fny,GLfloat & fnz);
void populateFaceNormals();
void calculateNormals();
//GLUT Callbacks
void MouseMoved(int x,int y);
void MouseClicked(int button, int state, int x, int y);
void SpecialKeys(int key, int x, int y);
void ChangeSize(int w, int h);
void RenderScene(void);
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
// Read the texture bits
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
free(pBits);
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void loadVertexArray(GLfloat x,GLfloat y,GLfloat z, GLfloat u, GLfloat v)
{
vertexType tempVertex;
tempVertex.xPos=x;
tempVertex.yPos=y;
tempVertex.zPos=z;
tempVertex.xNormal=0.0f; //calculate later
tempVertex.yNormal=0.0f; //calculate later
tempVertex.zNormal=0.0f; //calculate later
tempVertex.uTCoord=u;
tempVertex.vTCoord=v;
vertexArray.push_back(tempVertex);
}
void initTriCube(float xPos,float yPos,float zPos)
{
//vertex positions and colors
loadVertexArray(-0.5f,0.5f,0.0f,0.5f,0.25f); //0 (0.0) BACK x
loadVertexArray(-0.5f,0.5f,0.0f,0.5f,0.25f); //1 (0.1) TOP x
loadVertexArray(-0.5f,0.5f,0.0f,0.25f,0.5f); //2 (0.2) LEFT x
loadVertexArray(-0.5f,-0.5f,0.0f,0.5f,0.0f); //3 (1.0) BACK x
loadVertexArray(-0.5f,-0.5f,0.0f,0.0f,0.25f); //4 (1.1) BOTTOM x
loadVertexArray(-0.5f,-0.5f,0.0f,0.25f,0.25f); //5 (1.2) LEFT x
loadVertexArray(0.5f,-0.5f,0.0f,0.25f,0.0f); //6 (2.0) BACK x
loadVertexArray(0.5f,-0.5f,0.0f,0.25f,0.25f); //7 (2.1) BOTTOM x
loadVertexArray(0.5f,-0.5f,0.0f,0.75f,0.25f); //8 (2.2) RIGHT x
loadVertexArray(0.5f,0.5f,0.0f,0.25f,0.25f); //9 (3.0) BACK x
loadVertexArray(0.5f,0.5f,0.0f,0.75f,0.25f); //10 (3.1) TOP x
loadVertexArray(0.5f,0.5f,0.0f,0.75f,0.5f); //11 (3.2) RIGHT x
loadVertexArray(-0.5f,0.5f,1.0f,0.0f,0.25f); //12 (4.0) FRONT x
loadVertexArray(-0.5f,0.5f,1.0f,0.5f,0.0f); //13 (4.1) TOP x
loadVertexArray(-0.5f,0.5f,1.0f,0.5f,0.5f); //14 (4.2) LEFT x
loadVertexArray(-0.5f,-0.5f,1.0f,0.0f,0.0f); //15 (5.0) FRONT x
loadVertexArray(-0.5f,-0.5f,1.0f,0.0f,0.5f); //16 (5.1) BOTTOM x
loadVertexArray(-0.5f,-0.5f,1.0f,0.5f,0.25f); //17 (5.2) LEFT x
loadVertexArray(0.5f,-0.5f,1.0f,0.25f,0.0f); //18 (6.0) FRONT x
loadVertexArray(0.5f,-0.5f,1.0f,0.25f,0.5f); //19 (6.1) BOTTOM x
loadVertexArray(0.5f,-0.5f,1.0f,0.5f,0.25f); //20 (6.2) RIGHT x
loadVertexArray(0.5f,0.5f,1.0f,0.25f,0.25f); //21 (7.0) FRONT x
loadVertexArray(0.5f,0.5f,1.0f,0.75f,0.0f); //22 (7.1) TOP x
loadVertexArray(0.5f,0.5f,1.0f,0.5f,0.5f); //23 (7.2) RIGHT x
//tri indixies
//front 0
vertexIndex.push_back(12); vertexIndex.push_back(15); vertexIndex.push_back(18);
vertexIndex.push_back(18); vertexIndex.push_back(21); vertexIndex.push_back(12);
//back 1
vertexIndex.push_back(6); vertexIndex.push_back(3); vertexIndex.push_back(0);
vertexIndex.push_back(0); vertexIndex.push_back(9); vertexIndex.push_back(6);
//top 2
vertexIndex.push_back(22); vertexIndex.push_back(10); vertexIndex.push_back(1);
vertexIndex.push_back(1); vertexIndex.push_back(13); vertexIndex.push_back(22);
//bottom 3
vertexIndex.push_back(7); vertexIndex.push_back(19); vertexIndex.push_back(16);
vertexIndex.push_back(16); vertexIndex.push_back(4); vertexIndex.push_back(7);
//left side 4
vertexIndex.push_back(17); vertexIndex.push_back(14); vertexIndex.push_back(2);
vertexIndex.push_back(2); vertexIndex.push_back(5); vertexIndex.push_back(17);
//right side 5
vertexIndex.push_back(8); vertexIndex.push_back(11); vertexIndex.push_back(23);
vertexIndex.push_back(23); vertexIndex.push_back(20); vertexIndex.push_back(8);
//calcualte vertex normals
calculateNormals();
//build VBO (verticies)
glGenBuffers(1,&vdataBufferID);
glBindBuffer(GL_ARRAY_BUFFER,vdataBufferID);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertexType)*vertexArray.size(),&(vertexArray[0]),GL_STATIC_DRAW);
//bind texture
glGenTextures(1,&textureID);
glBindTexture(GL_TEXTURE_2D,textureID);
LoadTGATexture("cubetest_flat.tga",GL_LINEAR,GL_LINEAR,GL_CLAMP_TO_EDGE);
//build VBO (indixies)
glGenBuffers(1,&viBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,viBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*vertexIndex.size(),&(vertexIndex[0]),GL_STATIC_DRAW);
//set frame
modelFrame.SetOrigin(xPos,yPos,zPos);
modelFrame.SetUpVector(0.0f,1.0f,0.0f);
modelFrame.SetForwardVector(0.0f,0.0f,1.0f);
}
void drawTriCube()
{
glBindBuffer(GL_ARRAY_BUFFER,vdataBufferID);
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX,3,GL_FLOAT,GL_FALSE,sizeof(vertexType),BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLT_ATTRIBUTE_NORMAL);
glVertexAttribPointer(GLT_ATTRIBUTE_NORMAL,3,GL_FLOAT,GL_FALSE,sizeof(vertexType),BUFFER_OFFSET(12));
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0,2,GL_FLOAT,GL_FALSE,sizeof(vertexType),BUFFER_OFFSET(24));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,viBufferID);
glDrawElements(GL_TRIANGLES,vertexIndex.size(),GL_UNSIGNED_SHORT,BUFFER_OFFSET(0));
glDisableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glDisableVertexAttribArray(GLT_ATTRIBUTE_NORMAL);
glDisableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
}
void SetupRC()
{
glClearColor(255.0f, 255.0f, 255.0f, 1.0f );
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
shaderManager.InitializeStockShaders();
initTriCube(0.0f,0.0f,-8.0f);
}
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix(); //save identity matrix
M3DMatrix44f cameraMatrix;
M3DVector4f vLightTransformed;
cameraFrame.GetCameraMatrix(cameraMatrix);
m3dTransformVector4(vLightTransformed, lightPos, cameraMatrix);
modelViewMatrix.PushMatrix(cameraMatrix);
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(modelFrame);
glBindTexture(GL_TEXTURE_2D,textureID);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),transformPipeline.GetProjectionMatrix(),vLightTransformed,lightColor,0);
drawTriCube();
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix(); //restore identity matrix
glutSwapBuffers();
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
rightMouseDown=false;
oldMouseX=0;
oldMouseY=0;
deltaMouseX=0;
deltaMouseY=0;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
glutInitWindowSize(800, 600);
glutCreateWindow("Triangle");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
glutMotionFunc(MouseMoved);
glutMouseFunc(MouseClicked);
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "GLEW Error: %s
", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
//delete texture
glDeleteTextures(1,&textureID);
//delete VBO
glDeleteBuffers(1,&vdataBufferID);
glDeleteBuffers(1,&viBufferID);
return 0;
}