#include #include #include #include #include #include // Mesh Data Structure struct mesh { long numverts; long numtris; float (*verts)[3]; float (*norms)[3]; float (*texs)[2]; long (*tris)[3]; }; // Image struct image { int depth; int width; int height; int components; GLubyte *data; }; // Screen Size int width = 400; int height = 400; // Frame Timer Data float tottime = 0; int frames = 0; int ttime = 0; float tdiff = 0; // Mesh Data struct mesh flag; float conv = 3.14159 / 180.0; int numx = 50; int numy = 50; int wx = 200; int wy = 200; // Color Data int numcolor = 12; float col = 0; int col_mode = 0; // Texture Data int cur_tex = 0; struct image i1, i2; GLuint texptrs[2]; // Rainbow GLfloat rainbowcol [][3] = {{1, 0, 1}, {0.5, 0, 1}, {0, 0, 1}, {0, 0.5, 1}, {0, 1, 1}, {0, 1, 0.5}, {0, 1, 0}, {0.5, 1, 0}, {1, 1, 0}, {1, 0.5, 0}, {1, 0, 0}, {1, 0, 0.5}}; // Lighting parameters GLfloat ambient[] = {0.1, 0.1, 0.1, 1.0}; GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat position[] = {200.0, 200.0, -300.0, 0.0}; GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0}; GLfloat local_view[] = {0.0}; GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_shininess[] = {77.0}; // rotation float rotation = 0; void normalize (GLfloat vec[3]) { float len = sqrtf((vec[0] * vec[0]) + (vec[1] * vec[1]) + (vec[2] * vec[2])); vec[0] /= len; vec[1] /= len; vec[2] /= len; } void cross (GLfloat u[3], GLfloat v[3], GLfloat w[3]) { w[0] = (u[1] * v[2]) - (u[2] * v[1]); w[1] = (u[2] * v[0]) - (u[0] * v[2]); w[2] = (u[0] * v[1]) - (u[1] * v[0]); } GLfloat *abs_norm (GLfloat vec[3]) { static GLfloat col[3]; col[0] = fabsf(vec[0]); col[1] = fabsf(vec[1]); col[2] = fabsf(vec[2]); return col; } GLfloat *rainbow4fv (int color, GLfloat alpha) { static GLfloat col[4]; col[0] = rainbowcol[color][0]; col[1] = rainbowcol[color][1]; col[2] = rainbowcol[color][2]; col[3] = alpha; return col; } GLfloat *rainbow3fv (int color) { static GLfloat col[3]; col[0] = rainbowcol[color][0]; col[1] = rainbowcol[color][1]; col[2] = rainbowcol[color][2]; return col; } void timer_update () { tdiff = (glutGet(GLUT_ELAPSED_TIME) - ttime) / 1000.0; ttime = glutGet(GLUT_ELAPSED_TIME); } // Borrowed from ATI ImageIO library int load_tga (struct image *img, char *filename) { FILE *fp; GLubyte tmp; unsigned char header [18]; if (!(fp = fopen(filename, "rb"))) { return 1; } fread(header, 18, 1, fp); if (header[2] != 2) { fclose(fp); return 1; } if (header[16] < 24) { fclose(fp); return 1; } img->depth = 1; img->width = header[12] + (header[13] << 8); img->height = header[14] + (header[15] << 8); img->components = header[16] / 8; img->data = new GLubyte[img->width * img->height * img->components]; fseek(fp, header[0], SEEK_CUR); fread(img->data, img->width * img->height * img->components, 1, fp); fclose(fp); for (int i = 0; i < img->width * img->height * img->components; i += img->components) { tmp = img->data[i]; img->data[i] = img->data[i+2]; img->data[i+2] = tmp; } return 0; } void generate_mesh (struct mesh *m, int x, int y, float dx, float dy) { // Calculations int ind, tri; float stepx = dx / (float)(x - 1); float stepy = dy / (float)(y - 1); float stepsx = 1.0 / (float)(x - 1); float stepsy = 1.0 / (float)(y - 1); // Sizes m->numverts = x * y; m->numtris = (x - 1) * (y - 1) * 2; // Allocate mesh memory m->verts = (float (*)[3])malloc(sizeof(float [3]) * m->numverts); m->norms = (float (*)[3])malloc(sizeof(float [3]) * m->numverts); m->texs = (float (*)[2])malloc(sizeof(float [2]) * m->numverts); m->tris = (long (*)[3])malloc(sizeof(long [3]) * m->numtris); // Generate verts and normals for (int i = 0; i < x; i++) for (int j = 0; j < y; j++) { ind = j * x + i; // Vertex Position m->verts[ind][0] = i * stepx; m->verts[ind][1] = j * stepy; m->verts[ind][2] = 0.0; // Normal Direction m->norms[ind][0] = 0.0; m->norms[ind][1] = 0.0; m->norms[ind][2] = 1.0; // Texture Coordinates m->texs[ind][0] = i * stepsx; m->texs[ind][1] = j * stepsy; } // Generate triangle tri = 0; for (int i = 0; i < x - 1; i++) for (int j = 0; j < y - 1; j++) { ind = j * x + i; // Top Left m->tris[tri][0] = ind; m->tris[tri][1] = ind + x + 1; m->tris[tri][2] = ind + x; tri++; // Bottom Right m->tris[tri][0] = ind; m->tris[tri][1] = ind + 1; m->tris[tri][2] = ind + x + 1; tri++; } } void drawmesh () { GLboolean light; int color = (int)col; // Position Mesh glRotatef(-90, 1, 0, 0); glTranslatef(-wx / 2.0, -wy / 2.0, 0); // Collect info glGetBooleanv(GL_LIGHTING, &light); // Bind Current Selected Texture glBindTexture(GL_TEXTURE_2D, texptrs[cur_tex]); // Draw Mesh glBegin(GL_TRIANGLES); // White Only if (col_mode == 0) glColor3f(1.0, 1.0, 1.0); // Rainbow Color if (col_mode == 1) glColor3fv(rainbow3fv(color)); // Use Lighting Material Color if (light) { if (col_mode == 0) { glMaterialfv(GL_FRONT, GL_AMBIENT, mat_specular); // White glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_specular); } else if (col_mode == 1) { glMaterialfv(GL_FRONT, GL_AMBIENT, rainbow4fv(color, 1.0)); glMaterialfv(GL_FRONT, GL_DIFFUSE, rainbow4fv(color, 1.0)); } glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); } // Draw Triangles for(int i = 0; i < flag.numtris; i++) { if (col_mode == 2) glColor3fv(abs_norm(flag.norms[flag.tris[i][0]])); glNormal3fv(flag.norms[flag.tris[i][0]]); glTexCoord2fv(flag.texs[flag.tris[i][0]]); glVertex3fv(flag.verts[flag.tris[i][0]]); if (col_mode == 2) glColor3fv(abs_norm(flag.norms[flag.tris[i][1]])); glNormal3fv(flag.norms[flag.tris[i][1]]); glTexCoord2fv(flag.texs[flag.tris[i][1]]); glVertex3fv(flag.verts[flag.tris[i][1]]); if (col_mode == 2) glColor3fv(abs_norm(flag.norms[flag.tris[i][2]])); glNormal3fv(flag.norms[flag.tris[i][2]]); glTexCoord2fv(flag.texs[flag.tris[i][2]]); glVertex3fv(flag.verts[flag.tris[i][2]]); } glEnd(); } void draw () { static float t = 0; float dx, dy, dz; // Clear buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Setup viewport glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, width / (float)height, 10, 10000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 200, 300, 0, 0, 0, 0, 1, 0); // Update the timer timer_update(); tottime += tdiff; // Animation Update col = fmodf(col + tdiff, numcolor); t = fmodf(t + (tdiff * 360.0 / 10.0), 360); // Clear Motion From Last Frame for (int i = 0; i < numx; i++) for (int j = 0; j < numy; j++) { flag.verts[j * numx + i][2] = 0; flag.norms[j * numx + i][0] = 0; flag.norms[j * numx + i][1] = 0; flag.norms[j * numx + i][2] = 0; } // Introduce Waves for (int i = 0; i < numx; i++) for (int j = 0; j < numy; j++) { dx = fabs((wx / 2.0) - (wx * i / (float)numx)); dy = fabs((wy / 2.0) - (wy * j / (float)numy)); dz = sqrtf((dx * dx) + (dy * dy)); flag.verts[j * numx + i][2] += 5.0 * sin(conv * fmodf(t + dz, 360.0) * 10.0); } // Correct Normals float u[3], v[3], n[3]; for (int i = 0; i < flag.numtris; i++) { // Find Triangle Normal u[0] = flag.verts[flag.tris[i][1]][0] - flag.verts[flag.tris[i][0]][0]; u[1] = flag.verts[flag.tris[i][1]][1] - flag.verts[flag.tris[i][0]][1]; u[2] = flag.verts[flag.tris[i][1]][2] - flag.verts[flag.tris[i][0]][2]; v[0] = flag.verts[flag.tris[i][2]][0] - flag.verts[flag.tris[i][0]][0]; v[1] = flag.verts[flag.tris[i][2]][1] - flag.verts[flag.tris[i][0]][1]; v[2] = flag.verts[flag.tris[i][2]][2] - flag.verts[flag.tris[i][0]][2]; cross(u, v, n); // Add Normal into Normal flag.norms[flag.tris[i][0]][0] += n[0]; flag.norms[flag.tris[i][0]][1] += n[1]; flag.norms[flag.tris[i][0]][2] += n[2]; flag.norms[flag.tris[i][1]][0] += n[0]; flag.norms[flag.tris[i][1]][1] += n[1]; flag.norms[flag.tris[i][1]][2] += n[2]; flag.norms[flag.tris[i][2]][0] += n[0]; flag.norms[flag.tris[i][2]][1] += n[1]; flag.norms[flag.tris[i][2]][2] += n[2]; } // Normalize Normals for (int i = 0; i < flag.numverts; i++) normalize(flag.norms[i]); // Perform rotation glRotatef(rotation, 0.0f, 1.0f, 0.0f); rotation = fmodf(rotation + 10.0 * tdiff, 360.0); // Draw the Mesh drawmesh(); // Billboard the frame rate glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Setup GLboolean light; glGetBooleanv(GL_LIGHTING, &light); if (light) glDisable(GL_LIGHTING); // Draw text char txt[60], *c; sprintf(txt, "FPS: %.1lf\n", frames / tottime); glColor3f(0.0f, 0.0f, 0.0f); glRasterPos2f(20.0, 20.0); for (c = txt; (*c); c++) glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *c); // Unsetup if (light) glEnable(GL_LIGHTING); // Put buffer on screen glutSwapBuffers(); // Record each frame frames++; if (frames > 1000000) { frames = 0; tottime = 0; } } void keys (unsigned char key, int x, int y) { GLboolean btmp; switch (key) { case 'q': case 27: exit(0); break; // Change color mode case 'c': col_mode = ++col_mode % 3; printf("col_mode: %d\n", col_mode); break; // Change Texture case 'p': cur_tex = ++cur_tex % 2; break; // Toggle Texturing case 't': glGetBooleanv(GL_TEXTURE_2D, &btmp); if (btmp) glDisable(GL_TEXTURE_2D); else glEnable(GL_TEXTURE_2D); break; // Toggle Lighting case 'l': glGetBooleanv(GL_LIGHTING, &btmp); if (btmp) glDisable(GL_LIGHTING); else glEnable(GL_LIGHTING); break; }; } int main (int argc, char **argv) { // Setup OpenGL glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(width, height); glutCreateWindow("Texturing and Lighting 1"); // Setup callbacks glutDisplayFunc(draw); glutIdleFunc(draw); glutKeyboardFunc(keys); // Enable depth testing glEnable(GL_DEPTH_TEST); // Enable blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Enable lighting glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); // Enable Texture Mapping glEnable(GL_TEXTURE_2D); load_tga(&i1, "wood.tga"); load_tga(&i2, "white.tga"); glGenTextures(2, texptrs); glBindTexture(GL_TEXTURE_2D, texptrs[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, i1.width, i1.height, 0, GL_RGB, GL_UNSIGNED_BYTE, i1.data); glBindTexture(GL_TEXTURE_2D, texptrs[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, i2.width, i2.height, 0, GL_RGB, GL_UNSIGNED_BYTE, i2.data); // Enable Backface culling glCullFace(GL_BACK); glEnable(GL_CULL_FACE); // Change background color glClearColor(0.5, 0.5, 0.5, 1.0); generate_mesh(&flag, numx, numy, wx, wy); // Give control to OpenGL ttime = glutGet(GLUT_ELAPSED_TIME); glutMainLoop(); return 0; }