#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#include <GLTools.h>
#include <math3d.h>
#include <SFML\System.hpp>
#include <SFML\Audio.hpp>
#include <SFML\Window.hpp>
//defines
#define BOX_ARRAY_SIZE 5
#define MAX_X 2
#define MAX_Z 2
#define MAX_TEXTURES 1
#define FOV 70.0f
#define ASPECT_RATIO 800.0f/600.0f
typedef struct Box {
M3DVector4f position;
float rotationOffset, xoffset, zoffset;
int texture;
} Box;
//struct for vertices
typedef struct Vertex {
M3DVector3f position;
M3DVector2f texCoord;
} Vertex;
//A gigantic global to hold all my stuff
static struct {
struct {
M3DMatrix44f projection;
M3DMatrix44f camera;
M3DMatrix44f modelViewProjection;
} modelviewProjection;
GLuint htextures[MAX_TEXTURES];
GLuint hvBuffer, hiBuffer,htcBuffer,hitcBuffer;
struct {
GLint m4ModelViewProjection;
GLint colorMap;
} uniforms;
struct {
GLint vVertex, vTexCoord;
} attributes;
struct {
GLuint hVertexShader, hFragmentShader, hProgram;
} shader;
Vertex points[36];
} resources;
//make a simple box object, this si currently irrelevant
bool readShader(char* name, char** destination) {
FILE *shader;
char* shaderText, *nullOffset;
size_t result;
long size;
shader = fopen(name, "rb");
if(shader == NULL) return false;
fseek(shader, 0, SEEK_END);
size=ftell(shader);
rewind(shader);
*destination = (char*) malloc(sizeof(char)*(size + 1));
result = fread(*destination, 1, size, shader);
nullOffset = (char*)(*destination + sizeof(char)*(size));
*nullOffset='\0';
fprintf(stdout, *destination);
fclose(shader);
return true;
};
//boring copypasted tga loading utiilty
static short le_short(unsigned char *bytes)
{
return bytes[0] | ((char)bytes[1] << 8);
};
void *read_tga(const char *filename, int *width, int *height)
{
struct tga_header {
char id_length;
char color_map_type;
char data_type_code;
unsigned char color_map_origin[2];
unsigned char color_map_length[2];
char color_map_depth;
unsigned char x_origin[2];
unsigned char y_origin[2];
unsigned char width[2];
unsigned char height[2];
char bits_per_pixel;
char image_descriptor;
} header;
int i, color_map_size, pixels_size;
FILE *f;
size_t read;
void *pixels;
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Unable to open %s for reading\n", filename);
return NULL;
}
read = fread(&header, 1, sizeof(header), f);
if (read != sizeof(header)) {
fprintf(stderr, "%s has incomplete tga header\n", filename);
fclose(f);
return NULL;
}
if (header.data_type_code != 2) {
fprintf(stderr, "%s is not an uncompressed RGB tga file\n", filename);
fclose(f);
return NULL;
}
if (header.bits_per_pixel != 24) {
fprintf(stderr, "%s is not a 24-bit uncompressed RGB tga file\n", filename);
fclose(f);
return NULL;
}
for (i = 0; i < header.id_length; ++i)
if (getc(f) == EOF) {
fprintf(stderr, "%s has incomplete id string\n", filename);
fclose(f);
return NULL;
}
color_map_size = le_short(header.color_map_length) * (header.color_map_depth/8);
for (i = 0; i < color_map_size; ++i)
if (getc(f) == EOF) {
fprintf(stderr, "%s has incomplete color map\n", filename);
fclose(f);
return NULL;
}
*width = le_short(header.width); *height = le_short(header.height);
pixels_size = *width * *height * (header.bits_per_pixel/8);
pixels = malloc(pixels_size);
read = fread(pixels, 1, pixels_size, f);
if (read != pixels_size) {
fprintf(stderr, "%s has incomplete image\n", filename);
fclose(f);
free(pixels);
return NULL;
}
return pixels;
};
int shaderSetup() {
char* shaderSrc = NULL;
GLint shaderStatus;
//read the vertex shader
if (!readShader("vertexShader.vs", &shaderSrc)) {
fprintf(stderr, "Vertex Shader Not Found");
return -1;
};
//compile and bind it
resources.shader.hVertexShader=glCreateShader(GL_VERTEX_SHADER);
glShaderSource(resources.shader.hVertexShader, 1, (const GLchar**)&shaderSrc, NULL);
glCompileShader(resources.shader.hVertexShader);
//check for compiling errors
glGetShaderiv(resources.shader.hVertexShader, GL_COMPILE_STATUS, &shaderStatus);
if(shaderStatus==GL_FALSE) {
char infoLog[1024];
glGetShaderInfoLog(resources.shader.hVertexShader, 1024, NULL, infoLog);
fprintf(stderr, "Failed to compile shader:\n%s", infoLog);
return -1;
};
//free the pointer
free(shaderSrc);
//same thing again, not sure why I didn't make it more efficient
if(!readShader("fragmentShader.fs", &shaderSrc)) {
fprintf(stderr, "Fragment Shader Not Found");
return -1;
};
//same thing
resources.shader.hFragmentShader=glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(resources.shader.hFragmentShader, 1, (const GLchar**)&shaderSrc, NULL);
glCompileShader(resources.shader.hFragmentShader);
//check for more fun
glGetShaderiv(resources.shader.hFragmentShader, GL_COMPILE_STATUS, &shaderStatus);
if(shaderStatus==GL_FALSE) {
char infoLog[1024];
glGetShaderInfoLog(resources.shader.hFragmentShader, 1024, NULL, infoLog);
fprintf(stderr, "Failed to compile shader:\n%s", infoLog);
return -1;
};
//refree the pointer
free(shaderSrc);
//create a program, bind shaders to it
resources.shader.hProgram=glCreateProgram();
glAttachShader(resources.shader.hProgram, resources.shader.hVertexShader);
glAttachShader(resources.shader.hProgram, resources.shader.hFragmentShader);
//link it
glLinkProgram(resources.shader.hProgram);
//clean up
glDeleteShader(resources.shader.hFragmentShader);
glDeleteShader(resources.shader.hVertexShader);
//final error check
glGetProgramiv(resources.shader.hProgram, GL_LINK_STATUS, &shaderStatus);
if(shaderStatus == GL_FALSE) {
char infoLog[1024];
glGetProgramInfoLog(resources.shader.hProgram, 1024, NULL, infoLog);
fprintf(stderr, "The program failed to link:\n%s", infoLog);
return -1;
};
//dig around for attributes and uniforms.
resources.attributes.vVertex=glGetAttribLocation(resources.shader.hProgram, "vVertex");
resources.attributes.vTexCoord=glGetAttribLocation(resources.shader.hProgram, "vTexCoord");
//not sure if these are binding correctly.
resources.uniforms.m4ModelViewProjection=glGetUniformLocation(resources.shader.hProgram, "m4ModelViewProjection");
resources.uniforms.colorMap=glGetUniformLocation(resources.shader.hProgram, "colorMap");
};
void textureSetup() {
glGenTextures(4, resources.htextures);
//load image
int width, height;
void *soviet = read_tga("soviet.tga", &width, &height);
if(!soviet) {
fprintf(stderr, "could not load texture");
};
glBindTexture(GL_TEXTURE_2D, resources.htextures[0]);
//set up the right texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//load texture into thing
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, soviet);
free(soviet);
if(resources.htextures[0]==0) fprintf(stderr, "failure");
};
void makeBuffer(GLuint &handle, void* data, GLenum target, GLsizei bufferSize) {
glGenBuffers(1, &handle);
glBindBuffer(target, handle);
glBufferData(target,bufferSize,data,GL_STATIC_DRAW);
};
void testRender() {
glClearColor(.25f, 0.35f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUniformMatrix4fv(resources.uniforms.m4ModelViewProjection, 1, GL_FALSE, (const GLfloat*)resources.modelviewProjection.modelViewProjection);
glEnableVertexAttribArray(resources.attributes.vTexCoord);
glEnableVertexAttribArray(resources.attributes.vVertex);
//deal with vTexCoord first
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,resources.hiBuffer);
glBindBuffer(GL_ARRAY_BUFFER, resources.htcBuffer);
glVertexAttribPointer(resources.attributes.vTexCoord,2,GL_FLOAT,GL_FALSE,sizeof(GLfloat)*2,(void*)0);
//now the other one
glBindBuffer(GL_ARRAY_BUFFER,resources.hvBuffer);
glVertexAttribPointer(resources.attributes.vVertex,3,GL_FLOAT,GL_FALSE,sizeof(GLfloat)*3,(void*)0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, resources.htextures[0]);
glUniform1i(resources.uniforms.colorMap, 0);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (void*)0);
//clean up a bit
};
int main(int argc, char* argv) {
Box boxes[BOX_ARRAY_SIZE];
srand(time(NULL));
sf::Window frame(sf::VideoMode(800, 600, 32), "3D Textured Box Thing");
sf::Event action;
frame.UseVerticalSync(true);
GLenum err=glewInit();
if(GLEW_OK != err) return 1;
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
shaderSetup();
textureSetup();
//setup boxes, five of them. This number is to change with array size
for(int i = 0; i<BOX_ARRAY_SIZE; i++) {
boxes[i].rotationOffset= (rand() % 3600) /10.0f;
boxes[i].position[0]=((rand() % (MAX_X*20))/10.0f)-MAX_X;
boxes[i].position[1]=2.0f;
boxes[i].position[2]=((rand() % (MAX_Z*20))/10.0f)-MAX_Z;
boxes[i].position[3]=1.0f;
boxes[i].texture=rand() % MAX_TEXTURES;
};
/////////////////////////////////////////////////////
//set up the projection matrix and camera matrix
m3dMakePerspectiveMatrix(resources.modelviewProjection.projection, m3dDegToRad(FOV), ASPECT_RATIO, 0.1f, -3.0f);
//load camera with identity and create a matrix to use with operations
M3DMatrix44f operation;
//construct camera as -2 Z
m3dLoadIdentity44(resources.modelviewProjection.camera);
m3dTranslationMatrix44(operation, -0.5f, 0.0f,2.0f);
m3dMatrixMultiply44(resources.modelviewProjection.camera, operation, resources.modelviewProjection.camera);
//construct viewProjectionMatrix
//that is, Projection * Camera
//but first make sure that the camera is inverted
m3dInvertMatrix44(resources.modelviewProjection.camera, resources.modelviewProjection.camera);
m3dMatrixMultiply44(resources.modelviewProjection.modelViewProjection, resources.modelviewProjection.projection, resources.modelviewProjection.camera);
//construct the giant thing of vertex attributes
GLfloat aCoordinates[108]={//front top triangle
-.25f, .25f, .25f,
.25f, .25f, .25f,
.25f, -.25f, .25f,
//front bottom triangle
-.25, -.25f, .25f,
-.25f, .25f, .25f,
.25f, -.25f, .25f,
//top upper triangle
.25f, .25f, -.25f,
-.25, -.25, .25,
.25, .25, .25,
//top lower triangle
-.25, .25, .25,
.25, .25, .25,
-.25, .25, -.25,
//back upper triangle
.25,-.25,-.25,
-.25,-.25,-.25,
.25,.25,-.25,
//back lower trianle, which is upper
-.25,.25,-.25,
.25,.25,-.25,
-.25,-.25,-.25,
//bottom upper triangle
.25,-.25,.25,
-.25,-.25,.25,
.25,-.25,-.25,
//bottom lower triangle
-.25,-.25,-.25,
.25,-.25,-.25,
-.25,-.25,.25,
//right upper triangle
.25,.25,-.25,
.25,.25,.25,
.25,-.25,-.25,
//right lower triangle
.25,-.25,.25,
.25,-.25,-.25,
.25,.25,.25,
//left upper triangle
-.25,.25,.25,
-.25,.25,-.25,
-.25,-.25,-.25,
//left lower triangle
-.25,-.25,.25,
-.25,.25,.25,
-.25,-.25,-.25,
};
GLfloat aTexCoordinates[72]={//front upper triangle
0.0f, 1.0f,
1/6.0f,1.0f,
1/6.0f,1.0f,
//front lower triangle
0.0f,0.0f,
0.0f,1.0f,
1/6.0f,0.0f,
//top upper triangle
2/6.0f,1.0f,
1/6,1.0f,
2/6,0.0f,
//top lower triangle
1/6,0.0f,
2/6,0.0f,
1/6,1.0,
//back upper triangle
3.6,0.0f,
2/6,0.0f,
3/6,1.0f,
//back lower triangle
2/6,1.0f,
3/6,1.0f,
2/6,0.0f,
//bottom upper triangle
4/6,1.0f,
3/6,1.0f,
4/6,0.0f,
//bottom lower triangle
3/6,0.0f,
4/6,0.0f,
3/6,1.0f,
//right upper triangle
5/6,1.0f,
4/6,1.0f,
5/6,0.0f,
//right lower triangle
4/6,0.0f,
5/6,0.0f,
4/6,1.0f,
//left upper triangle
1.0f,1.0f,
5/6,1.0f,
5/6,0.0f,
//left lower triangle
1.0f,0.0f,
1.0f,1.0f,
5/6,0.0f
};
GLint elements[36]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35};
glClearColor(0.35f, 0.35f, 0.35f, 1.0f);
//use the right shader first
glUseProgram(resources.shader.hProgram);
//setup the vertex coordinate buffer
makeBuffer(resources.hvBuffer,aCoordinates,GL_ARRAY_BUFFER,sizeof(GLfloat)*108);
makeBuffer(resources.htcBuffer,aTexCoordinates,GL_ARRAY_BUFFER,sizeof(GLfloat)*72);
makeBuffer(resources.hiBuffer,elements,GL_ELEMENT_ARRAY_BUFFER,sizeof(GLint)*36);
while(frame.IsOpened()) {
frame.GetEvent(action);
testRender();
frame.Display();
if(action.Type == sf::Event::Closed) frame.Close();
};
return 0;
};