Code:
#pragma warning (disable: 4786)
#ifdef _MSC_VER
#include <GL/glew.h>
#else
#include <GL/gl.h>
#endif
#include <Graphics/TrackBall.h>
#include <Graphics/DisplayText.h>
#include <GL/glut.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
using namespace std;
using namespace Graphics;
using namespace CGLA;
TrackBall *ball;
DisplayText displaytext;
int old_state = GLUT_UP;
CGcontext context;
CGprogram vertexProgram, fragmentProgram;
CGprofile vertexProfile, fragmentProfile;
static void handleCgError();
static void LoadCgPrograms();
static void ChooseProfiles();
#ifndef CWD
# define CWD ""
#endif
bool two_mouse = true;
// additions //////////////////////////////////////////////////////////////////////////////////////////////////
// OglExt.lib is used to allow easy implementation
// of the glMultiTexCoordARB functions
#pragma comment (lib, "OglExt.lib")
// used for loading and storing .tga textures
#include "TGAImg.h"
// had problems with CGLA when constructing
// the TBN matrix, so used this alternative
#include "3DMath_Lean.h"
// the coordinates for the plane (2 triangles of 3 vertices each)
CVector plane[2][3] = { {CVector(-75.0f, -75.0f, 0.0f), CVector(75.0f, -75.0f, 0.0f), CVector(75.0f, 75.0f, 0.0f)},
{CVector(-75.0f, 75.0f, 0.0f), CVector(-75.0f, -75.0f, 0.0f), CVector(75.0f, -75.0f, 0.0f)} };
// texture coordinates for the 2 triangles
CVector2 texCoords[2][3] = { {CVector2(1.0f, 1.0f), CVector2(0.0f, 1.0f), CVector2(0.0f, 0.0)},
{CVector2(1.0f, 0.0f), CVector2(1.0f, 1.0f), CVector2(0.0f, 1.0)} };
// the textures
GLuint texture, normalMap;
// the inverse TBN matrices
CVector invTBN[2][3];
// function prototypes
void drawPlane(void);
void invTBNmatrix(const CVector*, const CVector2*, CVector*);
GLuint LoadTexture(char *TexName);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void initBall(float max_value) {
Vec3f v(0,0,0);
ball = new TrackBall(v, 200, 500, 750, 750);
}
void initGL(void) {
// initialize textures
texture = LoadTexture("apeBase.tga");
normalMap = LoadTexture("apeNormal.tga");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-10.0,10.0,-10.0,10.0,15,50000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.,0.,-10.5);
glClearColor(0.0f, 0.0f, 0.0f, 0.f);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
ChooseProfiles();
LoadCgPrograms();
}
static void handleCgError()
{
fprintf(stderr, "Cg error: %s\n", cgGetErrorString(cgGetError()));
exit(1);
}
static void ChooseProfiles()
{
// Make sure that the appropriate profiles are available on the
// user's system.
if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1))
vertexProfile = CG_PROFILE_ARBVP1;
else {
// try VP30
if (cgGLIsProfileSupported(CG_PROFILE_VP30))
vertexProfile = CG_PROFILE_VP30;
else {
fprintf(stderr, "Neither arbvp1 or vp30 vertex profiles supported on this system.\n");
exit(1);
}
}
if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1))
fragmentProfile = CG_PROFILE_ARBFP1;
else {
// try FP30
if (cgGLIsProfileSupported(CG_PROFILE_FP30))
fragmentProfile = CG_PROFILE_FP30;
else {
fprintf(stderr, "Neither arbfp1 or fp30 fragment profiles supported on this system.\n");
exit(1);
}
}
}
static void LoadCgPrograms()
{
assert(cgIsContext(context));
// Load and compile the vertex program from demo_vert.cg; hold on to the
// handle to it that is returned.
vertexProgram = cgCreateProgramFromFile(context, CG_SOURCE, CWD "shader_vp.cg", vertexProfile, NULL, NULL);
if (!cgIsProgramCompiled(vertexProgram))
cgCompileProgram(vertexProgram);
// Enable the appropriate vertex profile and load the vertex program.
cgGLEnableProfile(vertexProfile);
cgGLLoadProgram(vertexProgram);
// And similarly set things up for the fragment program.
fragmentProgram = cgCreateProgramFromFile(context, CG_SOURCE, CWD "shader_fp.cg",
fragmentProfile, NULL, NULL);
if (!cgIsProgramCompiled(fragmentProgram))
cgCompileProgram(fragmentProgram);
cgGLEnableProfile(fragmentProfile);
cgGLLoadProgram(fragmentProgram);
}
void display() {
Vec3f eye;
Vec3f center(0,0,-1);
Vec3f up(0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
ball->get_view_param(eye, center, up);
ball->do_spin();
ball->set_gl_modelview();
// Now make sure that the vertex and fragment programs, loaded
// in LoadCgPrograms() are bound.
//cgGLEnableProfile(vertexProfile);
//cgGLEnableProfile(fragmentProfile);
cgGLBindProgram(vertexProgram);
cgGLBindProgram(fragmentProgram);
// Bind uniform parameters to vertex shader
cgGLSetStateMatrixParameter(cgGetNamedParameter(vertexProgram, "ModelViewProj"),
CG_GL_MODELVIEW_PROJECTION_MATRIX,
CG_GL_MATRIX_IDENTITY);
cgGLSetStateMatrixParameter(cgGetNamedParameter(vertexProgram, "ModelView"),
CG_GL_MODELVIEW_MATRIX,
CG_GL_MATRIX_IDENTITY);
cgGLSetStateMatrixParameter(cgGetNamedParameter(vertexProgram, "ModelViewIT"),
CG_GL_MODELVIEW_MATRIX,
CG_GL_MATRIX_INVERSE_TRANSPOSE);
// We can also go ahead and bind varying parameters to vertex shader
// that we just want to have the same value for all vertices. The
// vertex shader could be modified so that these were uniform for
// better efficiency, but this gives us flexibility for the future.
float lightPos[3] = { 100, 100, 100 };
float lightColor[3] = { 1, 1, 1 };
float Kd[3] = { .6, .6, .6 };
float Ks[3] = { .9, .9, .9 };
float ior = 1.5;
float m = 0.1;
// Now bind uniform parameters to fragment shader
cgGLSetParameter3fv(cgGetNamedParameter(fragmentProgram, "lightPos"), lightPos);
cgGLSetParameter3fv(cgGetNamedParameter(fragmentProgram, "lightCol"), lightColor);
cgGLSetParameter3fv(cgGetNamedParameter(fragmentProgram, "specCol"), Ks);
cgGLSetParameter3fv(cgGetNamedParameter(fragmentProgram, "difCol"), Kd);
cgGLSetParameter3fv(cgGetNamedParameter(fragmentProgram, "eyePos"), eye.get());
cgGLSetParameter1f(cgGetNamedParameter(fragmentProgram, "ior"), ior);
cgGLSetParameter1f(cgGetNamedParameter(fragmentProgram, "m"), m);
/*
// Enable and bind the rock texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
// Enable and bind the normal map
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, normalMap);
*/
drawPlane();
cgGLDisableProfile(vertexProfile);
cgGLDisableProfile(fragmentProfile);
/*
// Disable textures
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
*/
displaytext.draw();
glutSwapBuffers();
}
void mouse(int button, int state, int x, int y) {
if (old_state==GLUT_UP && state==GLUT_DOWN) {
if (button==GLUT_LEFT_BUTTON)
ball->grab_ball(ROTATE_ACTION,Vec2i(x,y));
else if (button==GLUT_MIDDLE_BUTTON)
ball->grab_ball(ZOOM_ACTION,Vec2i(x,y));
else if (button==GLUT_RIGHT_BUTTON)
ball->grab_ball(PAN_ACTION,Vec2i(x,y));
}
if (old_state==GLUT_DOWN && state==GLUT_UP)
ball->release_ball();
old_state=state;
}
void motion(int x, int y) {
if (old_state==GLUT_DOWN)
ball->roll_ball(Vec2i(x,y));
}
void keyboard(unsigned char key, int x, int y) {
switch(key) {
case '\033': exit(0); break;
}
}
void animate() {
glutPostRedisplay();
}
void drawPlane() {
glEnable(GL_TEXTURE_2D);
glColor3f(1.0f,1.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(texCoords[0][0].x, texCoords[0][0].y);
glVertex3f(plane[0][0].x, plane[0][0].y, plane[0][0].z);
glTexCoord2f(texCoords[0][1].x, texCoords[0][1].y);
glVertex3f(plane[0][1].x, plane[0][1].y, plane[0][1].z);
glTexCoord2f(texCoords[0][2].x, texCoords[0][2].y);
glVertex3f(plane[0][2].x, plane[0][2].y, plane[0][2].z);
glTexCoord2f(texCoords[1][0].x, texCoords[1][0].y);
glVertex3f(plane[1][0].x, plane[1][0].y, plane[1][0].z);
glTexCoord2f(texCoords[1][1].x, texCoords[1][1].y);
glVertex3f(plane[1][1].x, plane[1][1].y, plane[1][1].z);
glTexCoord2f(texCoords[1][2].x, texCoords[1][2].y);
glVertex3f(plane[1][2].x, plane[1][2].y, plane[1][2].z);
glEnd();
}
GLuint LoadTexture(char *TexName) {
TGAImg Img; // image loader
GLuint Texture;
// load our Texture
if(Img.Load(TexName)!=IMG_OK)
return -1;
glGenTextures(1,&Texture); // allocate space for texture
glBindTexture(GL_TEXTURE_2D, Texture); // bind texture
// create the texture
if(Img.GetBPP()==24)
glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,
GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
else
return -1;
// specify filtering and edge actions
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
return Texture;
}
void invTBNmatrix(const CVector *triangle, const CVector *tCoords, CVector *invTBN) {
// here the inverse TBN matrix is calculated
// the function follows the theory of the
// report stricly.. no magic at all
// vertex point differences
CVector v2v1(triangle[1] - triangle[0]);
CVector v3v1(triangle[2] - triangle[0]);
// texcoords differences
float c2c1t = tCoords[1].x - tCoords[0].x;
float c2c1b = tCoords[1].y - tCoords[0].y;
float c3c1t = tCoords[2].x - tCoords[0].x;
float c3c1b = tCoords[2].y - tCoords[0].y;
// tanget, bitangent and normal
CVector T, B, N;
float scale = 1/(c2c1t*c3c1b - c3c1t*c2c1b);
T = CVector( scale*(c3c1b*v2v1.x - c2c1b*v3v1.x),
scale*(c3c1b*v2v1.y - c2c1b*v3v1.y),
scale*(c3c1b*v2v1.z - c2c1b*v3v1.z) );
B = CVector( scale*(-c3c1t*v2v1.x - c2c1t*v3v1.x),
scale*(-c3c1t*v2v1.y - c2c1t*v3v1.y),
scale*(-c3c1t*v2v1.z - c2c1t*v3v1.z) );
N = T.CrossProduct(B);
// start calculation of inverse TBN matrix
float scale2 = 1/((T.x*B.y*N.z - T.z*B.y*N.x) + (B.x*N.y*T.z - B.z*N.y*T.x) + (N.x*T.y*B.z - N.z*T.y*B.x));
// cross products for the inverse matrix
CVector BxN = B.CrossProduct(N);
CVector NxT = N.CrossProduct(T);
CVector TxB = T.CrossProduct(B);
// finally construct the inverse TBN matrix
invTBN[0].x = BxN.x * scale2;
invTBN[0].y = BxN.y * scale2;
invTBN[0].z = BxN.z * scale2;
invTBN[0].Normalize();
invTBN[1].x = NxT.x * scale2;
invTBN[1].y = NxT.y * scale2;
invTBN[1].z = NxT.z * scale2;
invTBN[1].Normalize();
invTBN[2].x = TxB.x * scale2;
invTBN[2].y = TxB.y * scale2;
invTBN[2].z = TxB.z * scale2;
invTBN[2].Normalize();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA | GLUT_STENCIL);
glutInitWindowSize(700, 700);
glutCreateWindow("CG Exercise + Bumpmapping");
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutIdleFunc(animate);
glutMouseFunc(mouse);
glutMotionFunc(motion);
cgSetErrorCallback(handleCgError);
context = cgCreateContext();
initGL();
//THESE ARE THE TROUBLE MAKERS!!//
////////////////////////////////////////////////////
//invTBNmatrix(plane[0], texCoords[0], invTBN[0]);//
//invTBNmatrix(plane[1], texCoords[1], invTBN[1]);//
////////////////////////////////////////////////////
displaytext.addFramerate();
initBall(50);
#ifdef _MSC_VER
glewInit();
#endif
glutMainLoop();
return 0;
}
I know it's rather messy, but I REALLY hope that someone can help my out.