// Parallel radiosity front end #include #include #include #define WIN32_LEAN_AND_MEAN #include #include #include #include "vector.h" //#define GENERATE_FORM_FACTORS #define NETWORK const int BLOCK_SIZE = 2; const int KILL_THRESHOLD = 5; #define M_PI 3.141593f #define MAX_QUADS 15000 #define MAX_EDGES 40000 #define MAX_MATERIALS 10 #define MAX_SIMPLE_POLYS 1000 #define MAX_SIMPLE_POLY_VERTICES 5000 #define MAX_CYLINDERS 300 #define MAX_LIGHTS 64 #define MAX_RUNS 10000 #define MAX_GRIDS 20 #define CUBESIZE 128 #define SHINY 10.0f #define DIFF_CUBE 1 #define SPEC_CUBE 2 #define GRID_BASE 100 #define SERVER "beowulf.lcs.mit.edu" #define PORT 5353 #define FF_SIZE 256 #define NJITTER 1 #define SCALE_PROBLEM 0.4f /* ARB_multitexture */ typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); /* ARB_multitexture */ #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF /* ARB_texture_cube_map */ #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C /* EXT_stencil_wrap */ #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 /* EXT_texture_edge_clamp */ #define GL_CLAMP_TO_EDGE_EXT 0x812F /* NV_texture_rectangle */ #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 /* ARB_multitexture */ PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; #define ArraySize(array) (sizeof(array)/sizeof(array[0])) char *requiredExtensions[] = { "GL_ARB_texture_cube_map", "GL_EXT_stencil_wrap", "GL_EXT_texture_edge_clamp", "GL_NV_texture_rectangle", }; enum LightModel { LIGHT_PERVERTEX, LIGHT_PERVERTEX_SHADOWED, LIGHT_PERPIXEL_SHADOWED, LIGHT_RADIOSITY_BASELINE, LIGHT_RADIOSITY, LIGHT_RADIOSITY_PERPIXEL_SHADOWED, MAX_LIGHTMODEL, }; float theta, phi; float eyeX = 0.0f; float eyeY = 0.0f; float eyeZ = 1.5f; float globalAmbient[4] = {0.0f, 0.0f, 0.0f, 1.0f}; int wireframe = 0; int lightModel = LIGHT_PERVERTEX; int showLights = 0; int showSpecular = 0; int filterSolutions = 0; int networkThreadDie = 0; int nMaterials; int nMaterialQuads[MAX_MATERIALS]; float diffuse[MAX_MATERIALS][4]; float specular[MAX_MATERIALS][4]; int nQuads; VECTOR vertices[MAX_QUADS][4]; VECTOR texcoords[MAX_QUADS][4]; VECTOR tangents[MAX_QUADS]; VECTOR binormals[MAX_QUADS]; VECTOR normals[MAX_QUADS]; VECTOR baseRadiosity[MAX_QUADS]; VECTOR radiosity[MAX_QUADS]; bool quadLightFrontFace[MAX_QUADS]; unsigned short receiveRadiosity[MAX_QUADS][3]; int nEdges; int quad0[MAX_EDGES]; int quad1[MAX_EDGES]; VECTOR vtx0[MAX_EDGES]; VECTOR vtx1[MAX_EDGES]; int nSimplePolys; int nTotalSimplePolyVertices; int nSimplePolyVertices[MAX_SIMPLE_POLYS]; VECTOR simplePolyNormals[MAX_SIMPLE_POLYS]; float simplePolyDistances[MAX_SIMPLE_POLYS]; VECTOR simplePolyVertices[MAX_SIMPLE_POLY_VERTICES]; int nCylinders; int cylinderPolyStart[MAX_CYLINDERS]; int cylinderPolyVertexStart[MAX_CYLINDERS]; float cylinderX[MAX_CYLINDERS]; float cylinderY[MAX_CYLINDERS]; float cylinderMinZ[MAX_CYLINDERS]; float cylinderMaxZ[MAX_CYLINDERS]; float cylinderR[MAX_CYLINDERS]; int nLights; VECTOR lightPositions[MAX_LIGHTS]; int nRuns; int runLengths[MAX_RUNS]; int nGrids; int gridStarts[MAX_GRIDS]; int gridWidths[MAX_GRIDS]; int gridHeights[MAX_GRIDS]; float c, s, xOffset, yOffset; WSADATA wsadata; SOCKET sock; int width, height; float ffWeights[FF_SIZE][3*FF_SIZE]; GLubyte ffImage[FF_SIZE][3*FF_SIZE][4]; float formFactors[MAX_QUADS]; static void StartMaterial(float dr, float dg, float db, float sr, float sg, float sb) { diffuse[nMaterials][0] = dr; diffuse[nMaterials][1] = dg; diffuse[nMaterials][2] = db; diffuse[nMaterials][3] = 1.0f; specular[nMaterials][0] = sr; specular[nMaterials][1] = sg; specular[nMaterials][2] = sb; specular[nMaterials][3] = 1.0f; } static void EndMaterial(void) { nMaterials++; nRuns++; } static void SetTransform(float theta, float x, float y) { c = cosf(theta * M_PI / 180.0f); s = sinf(theta * M_PI / 180.0f); xOffset = x; yOffset = y; } static void SetSimpleNormal(float x, float y, float z) { simplePolyNormals[nSimplePolys].x = c*x - s*y; simplePolyNormals[nSimplePolys].y = s*x + c*y; simplePolyNormals[nSimplePolys].z = z; } static void SimplePolyVertex(float x, float y, float z) { simplePolyVertices[nTotalSimplePolyVertices].x = c*x - s*y + xOffset; simplePolyVertices[nTotalSimplePolyVertices].y = s*x + c*y + yOffset; simplePolyVertices[nTotalSimplePolyVertices].z = z; nTotalSimplePolyVertices++; nSimplePolyVertices[nSimplePolys]++; } static void EndSimplePoly(void) { simplePolyDistances[nSimplePolys] = DotProduct(simplePolyNormals[nSimplePolys], simplePolyVertices[nTotalSimplePolyVertices-1]); nSimplePolys++; } static void BeginCylinder(float x, float y, float minZ, float maxZ, float r) { cylinderPolyStart[nCylinders] = nSimplePolys; cylinderPolyVertexStart[nCylinders] = nTotalSimplePolyVertices; cylinderX[nCylinders] = c*x - s*y + xOffset; cylinderY[nCylinders] = s*x + c*y + yOffset; cylinderMinZ[nCylinders] = minZ - 0.001f; cylinderMaxZ[nCylinders] = maxZ + 0.001f; cylinderR[nCylinders] = r; nCylinders++; } static void AddEdge(VECTOR v0, VECTOR v1, int quad) { int i; // Search for existing edge for (i = 0; i < nEdges; i++) { if ((v1.x == vtx0[i].x) && (v0.x == vtx1[i].x) && (v1.y == vtx0[i].y) && (v0.y == vtx1[i].y) && (v1.z == vtx0[i].z) && (v0.z == vtx1[i].z)) { quad1[i] = quad; return; } } // Create a new edge quad0[nEdges] = quad; quad1[nEdges] = -1; vtx0[nEdges] = v0; vtx1[nEdges] = v1; nEdges++; } static void AddQuad(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float nx, float ny, float nz, bool autoSimple = true) { float length; length = nx*nx + ny*ny + nz*nz; length = 1.0f / sqrtf(length); nx *= length; ny *= length; nz *= length; if (autoSimple) { SetSimpleNormal(nx, ny, nz); SimplePolyVertex(x0, y0, z0); SimplePolyVertex(x1, y1, z1); SimplePolyVertex(x2, y2, z2); SimplePolyVertex(x3, y3, z3); EndSimplePoly(); } vertices[nQuads][0].x = c*x0 - s*y0 + xOffset; vertices[nQuads][0].y = s*x0 + c*y0 + yOffset; vertices[nQuads][0].z = z0; vertices[nQuads][1].x = c*x1 - s*y1 + xOffset; vertices[nQuads][1].y = s*x1 + c*y1 + yOffset; vertices[nQuads][1].z = z1; vertices[nQuads][2].x = c*x2 - s*y2 + xOffset; vertices[nQuads][2].y = s*x2 + c*y2 + yOffset; vertices[nQuads][2].z = z2; vertices[nQuads][3].x = c*x3 - s*y3 + xOffset; vertices[nQuads][3].y = s*x3 + c*y3 + yOffset; vertices[nQuads][3].z = z3; AddEdge(vertices[nQuads][0], vertices[nQuads][1], nQuads); AddEdge(vertices[nQuads][1], vertices[nQuads][2], nQuads); AddEdge(vertices[nQuads][2], vertices[nQuads][3], nQuads); AddEdge(vertices[nQuads][3], vertices[nQuads][0], nQuads); normals[nQuads].x = c*nx - s*ny; normals[nQuads].y = s*nx + c*ny; normals[nQuads].z = nz; tangents[nQuads] = Normalize(vertices[nQuads][1] - vertices[nQuads][0]); binormals[nQuads] = CrossProduct(normals[nQuads], tangents[nQuads]); nQuads++; nMaterialQuads[nMaterials]++; if (nQuads > 1) { if ((normals[nQuads-2].x != normals[nQuads-1].x) || (normals[nQuads-2].y != normals[nQuads-1].y) || (normals[nQuads-2].z != normals[nQuads-1].z)) { nRuns++; } } runLengths[nRuns]++; } static void TessQuad(float v1[3], float v2[3], float v3[3], float v4[3], int n, int m, float nx, float ny, float nz) { int i, j, ii, jj; float s0, s1, t0, t1; int saveEdges; saveEdges = nEdges; gridStarts[nGrids] = nQuads; gridWidths[nGrids] = n; gridHeights[nGrids] = m; nGrids++; for (ii = 0; ii < n; ii += BLOCK_SIZE) { for (jj = 0; jj < m; jj += BLOCK_SIZE) { for (i = 0; (i < BLOCK_SIZE) && (ii+i < n); i++) { s0 = (float)(ii+i) / n; s1 = (float)(ii+i+1) / n; for (j = 0; (j < BLOCK_SIZE) && (jj+j < m); j++) { t0 = (float)(jj+j) / m; t1 = (float)(jj+j+1) / m; AddQuad(v1[0]*(1-s0)*(1-t0) + v2[0]*s0*(1-t0) + v3[0]*s0*t0 + v4[0]*(1-s0)*t0, v1[1]*(1-s0)*(1-t0) + v2[1]*s0*(1-t0) + v3[1]*s0*t0 + v4[1]*(1-s0)*t0, v1[2]*(1-s0)*(1-t0) + v2[2]*s0*(1-t0) + v3[2]*s0*t0 + v4[2]*(1-s0)*t0, v1[0]*(1-s1)*(1-t0) + v2[0]*s1*(1-t0) + v3[0]*s1*t0 + v4[0]*(1-s1)*t0, v1[1]*(1-s1)*(1-t0) + v2[1]*s1*(1-t0) + v3[1]*s1*t0 + v4[1]*(1-s1)*t0, v1[2]*(1-s1)*(1-t0) + v2[2]*s1*(1-t0) + v3[2]*s1*t0 + v4[2]*(1-s1)*t0, v1[0]*(1-s1)*(1-t1) + v2[0]*s1*(1-t1) + v3[0]*s1*t1 + v4[0]*(1-s1)*t1, v1[1]*(1-s1)*(1-t1) + v2[1]*s1*(1-t1) + v3[1]*s1*t1 + v4[1]*(1-s1)*t1, v1[2]*(1-s1)*(1-t1) + v2[2]*s1*(1-t1) + v3[2]*s1*t1 + v4[2]*(1-s1)*t1, v1[0]*(1-s0)*(1-t1) + v2[0]*s0*(1-t1) + v3[0]*s0*t1 + v4[0]*(1-s0)*t1, v1[1]*(1-s0)*(1-t1) + v2[1]*s0*(1-t1) + v3[1]*s0*t1 + v4[1]*(1-s0)*t1, v1[2]*(1-s0)*(1-t1) + v2[2]*s0*(1-t1) + v3[2]*s0*t1 + v4[2]*(1-s0)*t1, nx, ny, nz, false); } } } } nEdges = saveEdges; } void AddLeg(float x, float y) { int i, j; float s0, s1, s2, t0, t1, t2, c0, c1, c2; SetTransform(0.0f, x, y); BeginCylinder(0.0f, 0.0f, 0.05f, 0.9f, 0.05f*0.96f); for (i = 0; i < 12; i++) { t0 = 2 * M_PI * (float)i / 12; t1 = 2 * M_PI * (float)((i+1)%12) / 12; t2 = 2 * M_PI * (i+0.5f) / 12; s0 = sinf(t0); c0 = cosf(t0); s1 = sinf(t1); c1 = cosf(t1); s2 = sinf(t2); c2 = cosf(t2); for (j = 0; j < 5; j++) { AddQuad(0.05f*c0, 0.05f*s0, 0.05f + j*0.17f, 0.05f*c1, 0.05f*s1, 0.05f + j*0.17f, 0.05f*c1, 0.05f*s1, 0.05f + (j+1)*0.17f, 0.05f*c0, 0.05f*s0, 0.05f + (j+1)*0.17f, c2, s2, 0.0f, false); } AddQuad(0.2f*c0, 0.2f*s0, 0.05f, 0.2f*c1, 0.2f*s1, 0.05f, 0.05f*c1, 0.05f*s1, 0.05f, 0.05f*c0, 0.05f*s0, 0.05f, 0.0f, 0.0f, 1.0f, false); AddQuad(0.2f*c1, 0.2f*s1, 0.0f, 0.2f*c0, 0.2f*s0, 0.0f, 0.0f*c0, 0.0f*s0, 0.0f, 0.0f*c1, 0.0f*s1, 0.0f, 0.0f, 0.0f, 1.0f, false); AddQuad(0.05f*c0, 0.05f*s0, 0.05f + j*0.17f, 0.05f*c1, 0.05f*s1, 0.05f + j*0.17f, 0.0f*c1, 0.0f*s1, 0.05f + j*0.17f, 0.0f*c0, 0.0f*s0, 0.05f + j*0.17f, 0.0f, 0.0f, 1.0f, false); } BeginCylinder(0.0f, 0.0f, 0.0f, 0.05f, 0.2f*0.96f); for (i = 0; i < 12; i++) { t0 = 2 * M_PI * (float)i / 12; t1 = 2 * M_PI * (float)((i+1)%12) / 12; t2 = 2 * M_PI * (i+0.5f) / 12; s0 = sinf(t0); c0 = cosf(t0); s1 = sinf(t1); c1 = cosf(t1); s2 = sinf(t2); c2 = cosf(t2); AddQuad(0.2f*c0, 0.2f*s0, 0.0f, 0.2f*c1, 0.2f*s1, 0.0f, 0.2f*c1, 0.2f*s1, 0.05f, 0.2f*c0, 0.2f*s0, 0.05f, c2, s2, 0.0f, false); } SetTransform(0.0f, 0.0f, 0.0f); } void AddChair(float x, float y, float angle) { SetTransform(angle, x, y); BeginCylinder(0.0f, 0.0f, 0.5f, 0.6f, 0.71f); // Bottom of base SetSimpleNormal(0, 0, -1); SimplePolyVertex(-0.5f, -0.5f, 0.5f); SimplePolyVertex(-0.5f, 0.5f, 0.5f); SimplePolyVertex( 0.5f, 0.5f, 0.5f); SimplePolyVertex( 0.5f, -0.5f, 0.5f); EndSimplePoly(); AddQuad(-0.35f, -0.35f, 0.5f, -0.35f, -0.1f, 0.5f, 0.0f, -0.1f, 0.5f, 0.0f, -0.35f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, -0.35f, 0.5f, 0.0f, -0.1f, 0.5f, 0.35f, -0.1f, 0.5f, 0.35f, -0.35f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, -0.1f, 0.5f, -0.35f, 0.1f, 0.5f, 0.0f, 0.1f, 0.5f, 0.0f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, -0.1f, 0.5f, 0.0f, 0.1f, 0.5f, 0.35f, 0.1f, 0.5f, 0.35f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.1f, 0.5f, -0.35f, 0.35f, 0.5f, 0.0f, 0.35f, 0.5f, 0.0f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, 0.1f, 0.5f, 0.0f, 0.35f, 0.5f, 0.35f, 0.35f, 0.5f, 0.35f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, -0.1f, 0.5f, -0.35f, -0.35f, 0.5f, -0.45f, -0.35f, 0.5f, -0.45f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.1f, 0.5f, -0.35f, -0.1f, 0.5f, -0.45f, -0.1f, 0.5f, -0.45f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.35f, 0.5f, -0.35f, 0.1f, 0.5f, -0.45f, 0.1f, 0.5f, -0.45f, 0.35f, 0.5f, 0, 0, -1, false); AddQuad(0.35f, -0.35f, 0.5f, 0.35f, -0.1f, 0.5f, 0.45f, -0.1f, 0.5f, 0.45f, -0.35f, 0.5f, 0, 0, -1, false); AddQuad(0.35f, -0.1f, 0.5f, 0.35f, 0.1f, 0.5f, 0.45f, 0.1f, 0.5f, 0.45f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad(0.35f, 0.1f, 0.5f, 0.35f, 0.35f, 0.5f, 0.45f, 0.35f, 0.5f, 0.45f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.35f, 0.5f, -0.35f, 0.45f, 0.5f, 0.0f, 0.45f, 0.5f, 0.0f, 0.35f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, 0.35f, 0.5f, 0.0f, 0.45f, 0.5f, 0.35f, 0.45f, 0.5f, 0.35f, 0.35f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, -0.45f, 0.5f, -0.35f, -0.35f, 0.5f, 0.0f, -0.35f, 0.5f, 0.0f, -0.45f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, -0.45f, 0.5f, 0.0f, -0.35f, 0.5f, 0.35f, -0.35f, 0.5f, 0.35f, -0.45f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, -0.1f, 0.5f, -0.45f, -0.35f, 0.5f, -0.5f, -0.3f, 0.5f, -0.5f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, 0.1f, 0.5f, -0.45f, -0.1f, 0.5f, -0.5f, -0.1f, 0.5f, -0.5f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, 0.35f, 0.5f, -0.45f, 0.1f, 0.5f, -0.5f, 0.1f, 0.5f, -0.5f, 0.3f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, -0.35f, 0.5f, 0.45f, -0.1f, 0.5f, 0.5f, -0.1f, 0.5f, 0.5f, -0.3f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, -0.1f, 0.5f, 0.45f, 0.1f, 0.5f, 0.5f, 0.1f, 0.5f, 0.5f, -0.1f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, 0.1f, 0.5f, 0.45f, 0.35f, 0.5f, 0.5f, 0.3f, 0.5f, 0.5f, 0.1f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.45f, 0.5f, -0.35f, 0.5f, 0.5f, -0.1f, 0.5f, 0.5f, 0.0f, 0.45f, 0.5f, 0, 0, -1, false); AddQuad( 0.0f, 0.45f, 0.5f, -0.1f, 0.5f, 0.5f, 0.2f, 0.5f, 0.5f, 0.35f, 0.45f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, -0.5f, 0.5f, -0.35f, -0.45f, 0.5f, 0.0f, -0.45f, 0.5f, -0.1f, -0.5f, 0.5f, 0, 0, -1, false); AddQuad(-0.1f, -0.5f, 0.5f, 0.0f, -0.45f, 0.5f, 0.35f, -0.45f, 0.5f, 0.2f, -0.5f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, -0.35f, 0.5f, -0.45f, -0.45f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.3f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, -0.45f, 0.5f, -0.35f, -0.45f, 0.5f, -0.35f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0, 0, -1, false); AddQuad(-0.45f, 0.45f, 0.5f, -0.45f, 0.35f, 0.5f, -0.5f, 0.3f, 0.5f, -0.5f, 0.5f, 0.5f, 0, 0, -1, false); AddQuad(-0.35f, 0.45f, 0.5f, -0.45f, 0.45f, 0.5f, -0.5f, 0.5f, 0.5f, -0.35f, 0.5f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, -0.45f, 0.5f, 0.45f, -0.35f, 0.5f, 0.5f, -0.3f, 0.5f, 0.5f, -0.5f, 0.5f, 0, 0, -1, false); AddQuad(0.35f, -0.45f, 0.5f, 0.45f, -0.45f, 0.5f, 0.5f, -0.5f, 0.5f, 0.2f, -0.5f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, 0.35f, 0.5f, 0.45f, 0.45f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.3f, 0.5f, 0, 0, -1, false); AddQuad(0.45f, 0.45f, 0.5f, 0.35f, 0.45f, 0.5f, 0.2f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0, 0, -1, false); // Top of base SetSimpleNormal(0, 0, 1); SimplePolyVertex(-0.4f, -0.5f, 0.6f); SimplePolyVertex( 0.5f, -0.5f, 0.6f); SimplePolyVertex( 0.5f, 0.5f, 0.6f); SimplePolyVertex(-0.4f, 0.5f, 0.6f); EndSimplePoly(); AddQuad(-0.4f, -0.3f, 0.6f, -0.4f, -0.5f, 0.6f, -0.1f, -0.5f, 0.6f, -0.1f, -0.3f, 0.6f, 0, 0, 1, false); AddQuad(-0.4f, -0.1f, 0.6f, -0.4f, -0.3f, 0.6f, -0.1f, -0.3f, 0.6f, -0.1f, -0.1f, 0.6f, 0, 0, 1, false); AddQuad(-0.4f, 0.1f, 0.6f, -0.4f, -0.1f, 0.6f, -0.1f, -0.1f, 0.6f, -0.1f, 0.1f, 0.6f, 0, 0, 1, false); AddQuad(-0.4f, 0.3f, 0.6f, -0.4f, 0.1f, 0.6f, -0.1f, 0.1f, 0.6f, -0.1f, 0.3f, 0.6f, 0, 0, 1, false); AddQuad(-0.4f, 0.5f, 0.6f, -0.4f, 0.3f, 0.6f, -0.1f, 0.3f, 0.6f, -0.1f, 0.5f, 0.6f, 0, 0, 1, false); AddQuad(-0.1f, -0.3f, 0.6f, -0.1f, -0.5f, 0.6f, 0.2f, -0.5f, 0.6f, 0.2f, -0.3f, 0.6f, 0, 0, 1, false); AddQuad(-0.1f, -0.1f, 0.6f, -0.1f, -0.3f, 0.6f, 0.2f, -0.3f, 0.6f, 0.2f, -0.1f, 0.6f, 0, 0, 1, false); AddQuad(-0.1f, 0.1f, 0.6f, -0.1f, -0.1f, 0.6f, 0.2f, -0.1f, 0.6f, 0.2f, 0.1f, 0.6f, 0, 0, 1, false); AddQuad(-0.1f, 0.3f, 0.6f, -0.1f, 0.1f, 0.6f, 0.2f, 0.1f, 0.6f, 0.2f, 0.3f, 0.6f, 0, 0, 1, false); AddQuad(-0.1f, 0.5f, 0.6f, -0.1f, 0.3f, 0.6f, 0.2f, 0.3f, 0.6f, 0.2f, 0.5f, 0.6f, 0, 0, 1, false); AddQuad( 0.2f, -0.3f, 0.6f, 0.2f, -0.5f, 0.6f, 0.5f, -0.5f, 0.6f, 0.5f, -0.3f, 0.6f, 0, 0, 1, false); AddQuad( 0.2f, -0.1f, 0.6f, 0.2f, -0.3f, 0.6f, 0.5f, -0.3f, 0.6f, 0.5f, -0.1f, 0.6f, 0, 0, 1, false); AddQuad( 0.2f, 0.1f, 0.6f, 0.2f, -0.1f, 0.6f, 0.5f, -0.1f, 0.6f, 0.5f, 0.1f, 0.6f, 0, 0, 1, false); AddQuad( 0.2f, 0.3f, 0.6f, 0.2f, 0.1f, 0.6f, 0.5f, 0.1f, 0.6f, 0.5f, 0.3f, 0.6f, 0, 0, 1, false); AddQuad( 0.2f, 0.5f, 0.6f, 0.2f, 0.3f, 0.6f, 0.5f, 0.3f, 0.6f, 0.5f, 0.5f, 0.6f, 0, 0, 1, false); // Sides of base SetSimpleNormal(-1, 1, 0); SimplePolyVertex(-0.5f, -0.5f, 0.5f); SimplePolyVertex(-0.5f, -0.5f, 0.6f); SimplePolyVertex( 0.5f, 0.5f, 0.6f); SimplePolyVertex( 0.5f, 0.5f, 0.5f); EndSimplePoly(); SetSimpleNormal(1, 1, 0); SimplePolyVertex( 0.5f, -0.5f, 0.5f); SimplePolyVertex( 0.5f, -0.5f, 0.6f); SimplePolyVertex(-0.5f, 0.5f, 0.6f); SimplePolyVertex(-0.5f, 0.5f, 0.5f); EndSimplePoly(); AddQuad(-0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.6f, -0.5f, -0.3f, 0.6f, -0.5f, -0.3f, 0.5f, -1, 0, 0, false); AddQuad(-0.5f, -0.3f, 0.5f, -0.5f, -0.3f, 0.6f, -0.5f, -0.1f, 0.6f, -0.5f, -0.1f, 0.5f, -1, 0, 0, false); AddQuad(-0.5f, -0.1f, 0.5f, -0.5f, -0.1f, 0.6f, -0.5f, 0.1f, 0.6f, -0.5f, 0.1f, 0.5f, -1, 0, 0, false); AddQuad(-0.5f, 0.1f, 0.5f, -0.5f, 0.1f, 0.6f, -0.5f, 0.3f, 0.6f, -0.5f, 0.3f, 0.5f, -1, 0, 0, false); AddQuad(-0.5f, 0.3f, 0.5f, -0.5f, 0.3f, 0.6f, -0.5f, 0.5f, 0.6f, -0.5f, 0.5f, 0.5f, -1, 0, 0, false); AddQuad(0.5f, -0.5f, 0.6f, 0.5f, -0.5f, 0.5f, 0.5f, -0.3f, 0.5f, 0.5f, -0.3f, 0.6f, 1, 0, 0, false); AddQuad(0.5f, -0.3f, 0.6f, 0.5f, -0.3f, 0.5f, 0.5f, -0.1f, 0.5f, 0.5f, -0.1f, 0.6f, 1, 0, 0, false); AddQuad(0.5f, -0.1f, 0.6f, 0.5f, -0.1f, 0.5f, 0.5f, 0.1f, 0.5f, 0.5f, 0.1f, 0.6f, 1, 0, 0, false); AddQuad(0.5f, 0.1f, 0.6f, 0.5f, 0.1f, 0.5f, 0.5f, 0.3f, 0.5f, 0.5f, 0.3f, 0.6f, 1, 0, 0, false); AddQuad(0.5f, 0.3f, 0.6f, 0.5f, 0.3f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.6f, 1, 0, 0, false); AddQuad(-0.5f, -0.5f, 0.6f, -0.5f, -0.5f, 0.5f, -0.35f, -0.5f, 0.5f, -0.4f, -0.5f, 0.6f, 0, -1, 0, false); AddQuad(-0.4f, -0.5f, 0.6f, -0.35f, -0.5f, 0.5f, -0.1f, -0.5f, 0.5f, -0.1f, -0.5f, 0.6f, 0, -1, 0, false); AddQuad(-0.1f, -0.5f, 0.6f, -0.1f, -0.5f, 0.5f, 0.2f, -0.5f, 0.5f, 0.2f, -0.5f, 0.6f, 0, -1, 0, false); AddQuad( 0.2f, -0.5f, 0.6f, 0.2f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.6f, 0, -1, 0, false); AddQuad(-0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.6f, -0.4f, 0.5f, 0.6f, -0.35f, 0.5f, 0.5f, 0, 1, 0, false); AddQuad(-0.35f, 0.5f, 0.5f, -0.4f, 0.5f, 0.6f, -0.1f, 0.5f, 0.6f, -0.1f, 0.5f, 0.5f, 0, 1, 0, false); AddQuad(-0.1f, 0.5f, 0.5f, -0.1f, 0.5f, 0.6f, 0.2f, 0.5f, 0.6f, 0.2f, 0.5f, 0.5f, 0, 1, 0, false); AddQuad( 0.2f, 0.5f, 0.5f, 0.2f, 0.5f, 0.6f, 0.5f, 0.5f, 0.6f, 0.5f, 0.5f, 0.5f, 0, 1, 0, false); // Four legs BeginCylinder(-0.4f, -0.4f, 0.0f, 0.5f, 0.049f); AddQuad(-0.45f, -0.45f, 0.0f, -0.45f, -0.45f, 0.5f, -0.45f, -0.35f, 0.5f, -0.45f, -0.35f, 0.0f, -1, 0, 0, false); AddQuad(-0.35f, -0.45f, 0.5f, -0.35f, -0.45f, 0.0f, -0.35f, -0.35f, 0.0f, -0.35f, -0.35f, 0.5f, 1, 0, 0, false); AddQuad(-0.45f, -0.45f, 0.5f, -0.45f, -0.45f, 0.0f, -0.35f, -0.45f, 0.0f, -0.35f, -0.45f, 0.5f, 0, -1, 0, false); AddQuad(-0.45f, -0.35f, 0.0f, -0.45f, -0.35f, 0.5f, -0.35f, -0.35f, 0.5f, -0.35f, -0.35f, 0.0f, 0, 1, 0, false); AddQuad(-0.45f, -0.45f, 0.0f, -0.45f, -0.35f, 0.0f, -0.35f, -0.35f, 0.0f, -0.35f, -0.45f, 0.0f, 0, 0, -1, false); BeginCylinder(0.4f, -0.4f, 0.0f, 0.5f, 0.049f); AddQuad(0.35f, -0.45f, 0.0f, 0.35f, -0.45f, 0.5f, 0.35f, -0.35f, 0.5f, 0.35f, -0.35f, 0.0f, -1, 0, 0, false); AddQuad(0.45f, -0.45f, 0.5f, 0.45f, -0.45f, 0.0f, 0.45f, -0.35f, 0.0f, 0.45f, -0.35f, 0.5f, 1, 0, 0, false); AddQuad(0.35f, -0.45f, 0.5f, 0.35f, -0.45f, 0.0f, 0.45f, -0.45f, 0.0f, 0.45f, -0.45f, 0.5f, 0, -1, 0, false); AddQuad(0.35f, -0.35f, 0.0f, 0.35f, -0.35f, 0.5f, 0.45f, -0.35f, 0.5f, 0.45f, -0.35f, 0.0f, 0, 1, 0, false); AddQuad(0.35f, -0.45f, 0.0f, 0.35f, -0.35f, 0.0f, 0.45f, -0.35f, 0.0f, 0.45f, -0.45f, 0.0f, 0, 0, -1, false); BeginCylinder(0.4f, 0.4f, 0.0f, 0.5f, 0.049f); AddQuad(0.35f, 0.35f, 0.0f, 0.35f, 0.35f, 0.5f, 0.35f, 0.45f, 0.5f, 0.35f, 0.45f, 0.0f, -1, 0, 0, false); AddQuad(0.45f, 0.35f, 0.5f, 0.45f, 0.35f, 0.0f, 0.45f, 0.45f, 0.0f, 0.45f, 0.45f, 0.5f, 1, 0, 0, false); AddQuad(0.35f, 0.35f, 0.5f, 0.35f, 0.35f, 0.0f, 0.45f, 0.35f, 0.0f, 0.45f, 0.35f, 0.5f, 0, -1, 0, false); AddQuad(0.35f, 0.45f, 0.0f, 0.35f, 0.45f, 0.5f, 0.45f, 0.45f, 0.5f, 0.45f, 0.45f, 0.0f, 0, 1, 0, false); AddQuad(0.35f, 0.35f, 0.0f, 0.35f, 0.45f, 0.0f, 0.45f, 0.45f, 0.0f, 0.45f, 0.35f, 0.0f, 0, 0, -1, false); BeginCylinder(-0.4f, 0.4f, 0.0f, 0.5f, 0.049f); AddQuad(-0.45f, 0.35f, 0.0f, -0.45f, 0.35f, 0.5f, -0.45f, 0.45f, 0.5f, -0.45f, 0.45f, 0.0f, -1, 0, 0, false); AddQuad(-0.35f, 0.35f, 0.5f, -0.35f, 0.35f, 0.0f, -0.35f, 0.45f, 0.0f, -0.35f, 0.45f, 0.5f, 1, 0, 0, false); AddQuad(-0.45f, 0.35f, 0.5f, -0.45f, 0.35f, 0.0f, -0.35f, 0.35f, 0.0f, -0.35f, 0.35f, 0.5f, 0, -1, 0, false); AddQuad(-0.45f, 0.45f, 0.0f, -0.45f, 0.45f, 0.5f, -0.35f, 0.45f, 0.5f, -0.35f, 0.45f, 0.0f, 0, 1, 0, false); AddQuad(-0.45f, 0.35f, 0.0f, -0.45f, 0.45f, 0.0f, -0.35f, 0.45f, 0.0f, -0.35f, 0.35f, 0.0f, 0, 0, -1, false); BeginCylinder(-0.45f, 0.0f, 0.6f, 1.4f, 0.51f); // Sides of back SetSimpleNormal(-1.0f, 0.1f, 0.0f); SimplePolyVertex(-0.5f, -0.5f, 0.6f); SimplePolyVertex(-0.5f, -0.5f, 1.4f); SimplePolyVertex(-0.4f, 0.5f, 1.4f); SimplePolyVertex(-0.4f, 0.5f, 0.6f); EndSimplePoly(); SetSimpleNormal(1.0f, 0.1f, 0.0f); SimplePolyVertex(-0.5f, 0.5f, 0.6f); SimplePolyVertex(-0.5f, 0.5f, 1.4f); SimplePolyVertex(-0.4f, -0.5f, 1.4f); SimplePolyVertex(-0.4f, -0.5f, 0.6f); EndSimplePoly(); AddQuad(-0.5f, -0.5f, 0.6f, -0.5f, -0.5f, 0.8f, -0.5f, -0.3f, 0.8f, -0.5f, -0.3f, 0.6f, -1, 0, 0, false); AddQuad(-0.5f, -0.5f, 0.8f, -0.5f, -0.5f, 1.0f, -0.5f, -0.3f, 1.0f, -0.5f, -0.3f, 0.8f, -1, 0, 0, false); AddQuad(-0.5f, -0.5f, 1.0f, -0.5f, -0.5f, 1.2f, -0.5f, -0.3f, 1.2f, -0.5f, -0.3f, 1.0f, -1, 0, 0, false); AddQuad(-0.5f, -0.5f, 1.2f, -0.5f, -0.5f, 1.4f, -0.5f, -0.3f, 1.4f, -0.5f, -0.3f, 1.2f, -1, 0, 0, false); AddQuad(-0.5f, -0.3f, 0.6f, -0.5f, -0.3f, 0.8f, -0.5f, -0.1f, 0.8f, -0.5f, -0.1f, 0.6f, -1, 0, 0, false); AddQuad(-0.5f, -0.3f, 0.8f, -0.5f, -0.3f, 1.0f, -0.5f, -0.1f, 1.0f, -0.5f, -0.1f, 0.8f, -1, 0, 0, false); AddQuad(-0.5f, -0.3f, 1.0f, -0.5f, -0.3f, 1.2f, -0.5f, -0.1f, 1.2f, -0.5f, -0.1f, 1.0f, -1, 0, 0, false); AddQuad(-0.5f, -0.3f, 1.2f, -0.5f, -0.3f, 1.4f, -0.5f, -0.1f, 1.4f, -0.5f, -0.1f, 1.2f, -1, 0, 0, false); AddQuad(-0.5f, -0.1f, 0.6f, -0.5f, -0.1f, 0.8f, -0.5f, 0.1f, 0.8f, -0.5f, 0.1f, 0.6f, -1, 0, 0, false); AddQuad(-0.5f, -0.1f, 0.8f, -0.5f, -0.1f, 1.0f, -0.5f, 0.1f, 1.0f, -0.5f, 0.1f, 0.8f, -1, 0, 0, false); AddQuad(-0.5f, -0.1f, 1.0f, -0.5f, -0.1f, 1.2f, -0.5f, 0.1f, 1.2f, -0.5f, 0.1f, 1.0f, -1, 0, 0, false); AddQuad(-0.5f, -0.1f, 1.2f, -0.5f, -0.1f, 1.4f, -0.5f, 0.1f, 1.4f, -0.5f, 0.1f, 1.2f, -1, 0, 0, false); AddQuad(-0.5f, 0.1f, 0.6f, -0.5f, 0.1f, 0.8f, -0.5f, 0.3f, 0.8f, -0.5f, 0.3f, 0.6f, -1, 0, 0, false); AddQuad(-0.5f, 0.1f, 0.8f, -0.5f, 0.1f, 1.0f, -0.5f, 0.3f, 1.0f, -0.5f, 0.3f, 0.8f, -1, 0, 0, false); AddQuad(-0.5f, 0.1f, 1.0f, -0.5f, 0.1f, 1.2f, -0.5f, 0.3f, 1.2f, -0.5f, 0.3f, 1.0f, -1, 0, 0, false); AddQuad(-0.5f, 0.1f, 1.2f, -0.5f, 0.1f, 1.4f, -0.5f, 0.3f, 1.4f, -0.5f, 0.3f, 1.2f, -1, 0, 0, false); AddQuad(-0.5f, 0.3f, 0.6f, -0.5f, 0.3f, 0.8f, -0.5f, 0.5f, 0.8f, -0.5f, 0.5f, 0.6f, -1, 0, 0, false); AddQuad(-0.5f, 0.3f, 0.8f, -0.5f, 0.3f, 1.0f, -0.5f, 0.5f, 1.0f, -0.5f, 0.5f, 0.8f, -1, 0, 0, false); AddQuad(-0.5f, 0.3f, 1.0f, -0.5f, 0.3f, 1.2f, -0.5f, 0.5f, 1.2f, -0.5f, 0.5f, 1.0f, -1, 0, 0, false); AddQuad(-0.5f, 0.3f, 1.2f, -0.5f, 0.3f, 1.4f, -0.5f, 0.5f, 1.4f, -0.5f, 0.5f, 1.2f, -1, 0, 0, false); AddQuad(-0.4f, -0.5f, 0.8f, -0.4f, -0.5f, 0.6f, -0.4f, -0.3f, 0.6f, -0.4f, -0.3f, 0.8f, 1, 0, 0, false); AddQuad(-0.4f, -0.5f, 1.0f, -0.4f, -0.5f, 0.8f, -0.4f, -0.3f, 0.8f, -0.4f, -0.3f, 1.0f, 1, 0, 0, false); AddQuad(-0.4f, -0.5f, 1.2f, -0.4f, -0.5f, 1.0f, -0.4f, -0.3f, 1.0f, -0.4f, -0.3f, 1.2f, 1, 0, 0, false); AddQuad(-0.4f, -0.5f, 1.4f, -0.4f, -0.5f, 1.2f, -0.4f, -0.3f, 1.2f, -0.4f, -0.3f, 1.4f, 1, 0, 0, false); AddQuad(-0.4f, -0.3f, 0.8f, -0.4f, -0.3f, 0.6f, -0.4f, -0.1f, 0.6f, -0.4f, -0.1f, 0.8f, 1, 0, 0, false); AddQuad(-0.4f, -0.3f, 1.0f, -0.4f, -0.3f, 0.8f, -0.4f, -0.1f, 0.8f, -0.4f, -0.1f, 1.0f, 1, 0, 0, false); AddQuad(-0.4f, -0.3f, 1.2f, -0.4f, -0.3f, 1.0f, -0.4f, -0.1f, 1.0f, -0.4f, -0.1f, 1.2f, 1, 0, 0, false); AddQuad(-0.4f, -0.3f, 1.4f, -0.4f, -0.3f, 1.2f, -0.4f, -0.1f, 1.2f, -0.4f, -0.1f, 1.4f, 1, 0, 0, false); AddQuad(-0.4f, -0.1f, 0.8f, -0.4f, -0.1f, 0.6f, -0.4f, 0.1f, 0.6f, -0.4f, 0.1f, 0.8f, 1, 0, 0, false); AddQuad(-0.4f, -0.1f, 1.0f, -0.4f, -0.1f, 0.8f, -0.4f, 0.1f, 0.8f, -0.4f, 0.1f, 1.0f, 1, 0, 0, false); AddQuad(-0.4f, -0.1f, 1.2f, -0.4f, -0.1f, 1.0f, -0.4f, 0.1f, 1.0f, -0.4f, 0.1f, 1.2f, 1, 0, 0, false); AddQuad(-0.4f, -0.1f, 1.4f, -0.4f, -0.1f, 1.2f, -0.4f, 0.1f, 1.2f, -0.4f, 0.1f, 1.4f, 1, 0, 0, false); AddQuad(-0.4f, 0.1f, 0.8f, -0.4f, 0.1f, 0.6f, -0.4f, 0.3f, 0.6f, -0.4f, 0.3f, 0.8f, 1, 0, 0, false); AddQuad(-0.4f, 0.1f, 1.0f, -0.4f, 0.1f, 0.8f, -0.4f, 0.3f, 0.8f, -0.4f, 0.3f, 1.0f, 1, 0, 0, false); AddQuad(-0.4f, 0.1f, 1.2f, -0.4f, 0.1f, 1.0f, -0.4f, 0.3f, 1.0f, -0.4f, 0.3f, 1.2f, 1, 0, 0, false); AddQuad(-0.4f, 0.1f, 1.4f, -0.4f, 0.1f, 1.2f, -0.4f, 0.3f, 1.2f, -0.4f, 0.3f, 1.4f, 1, 0, 0, false); AddQuad(-0.4f, 0.3f, 0.8f, -0.4f, 0.3f, 0.6f, -0.4f, 0.5f, 0.6f, -0.4f, 0.5f, 0.8f, 1, 0, 0, false); AddQuad(-0.4f, 0.3f, 1.0f, -0.4f, 0.3f, 0.8f, -0.4f, 0.5f, 0.8f, -0.4f, 0.5f, 1.0f, 1, 0, 0, false); AddQuad(-0.4f, 0.3f, 1.2f, -0.4f, 0.3f, 1.0f, -0.4f, 0.5f, 1.0f, -0.4f, 0.5f, 1.2f, 1, 0, 0, false); AddQuad(-0.4f, 0.3f, 1.4f, -0.4f, 0.3f, 1.2f, -0.4f, 0.5f, 1.2f, -0.4f, 0.5f, 1.4f, 1, 0, 0, false); AddQuad(-0.5f, -0.5f, 0.8f, -0.5f, -0.5f, 0.6f, -0.4f, -0.5f, 0.6f, -0.4f, -0.5f, 0.8f, 0, -1, 0, false); AddQuad(-0.5f, -0.5f, 1.0f, -0.5f, -0.5f, 0.8f, -0.4f, -0.5f, 0.8f, -0.4f, -0.5f, 1.0f, 0, -1, 0, false); AddQuad(-0.5f, -0.5f, 1.2f, -0.5f, -0.5f, 1.0f, -0.4f, -0.5f, 1.0f, -0.4f, -0.5f, 1.2f, 0, -1, 0, false); AddQuad(-0.5f, -0.5f, 1.4f, -0.5f, -0.5f, 1.2f, -0.4f, -0.5f, 1.2f, -0.4f, -0.5f, 1.4f, 0, -1, 0, false); AddQuad(-0.5f, 0.5f, 0.6f, -0.5f, 0.5f, 0.8f, -0.4f, 0.5f, 0.8f, -0.4f, 0.5f, 0.6f, 0, 1, 0, false); AddQuad(-0.5f, 0.5f, 0.8f, -0.5f, 0.5f, 1.0f, -0.4f, 0.5f, 1.0f, -0.4f, 0.5f, 0.8f, 0, 1, 0, false); AddQuad(-0.5f, 0.5f, 1.0f, -0.5f, 0.5f, 1.2f, -0.4f, 0.5f, 1.2f, -0.4f, 0.5f, 1.0f, 0, 1, 0, false); AddQuad(-0.5f, 0.5f, 1.2f, -0.5f, 0.5f, 1.4f, -0.4f, 0.5f, 1.4f, -0.4f, 0.5f, 1.2f, 0, 1, 0, false); // Top of back SetSimpleNormal(0, 0, 1); SimplePolyVertex(-0.5f, -0.5f, 1.4f); SimplePolyVertex(-0.4f, -0.5f, 1.4f); SimplePolyVertex(-0.4f, 0.5f, 1.4f); SimplePolyVertex(-0.5f, 0.5f, 1.4f); EndSimplePoly(); AddQuad(-0.5f, -0.3f, 1.4f, -0.5f, -0.5f, 1.4f, -0.4f, -0.5f, 1.4f, -0.4f, -0.3f, 1.4f, 0, 0, 1, false); AddQuad(-0.5f, -0.1f, 1.4f, -0.5f, -0.3f, 1.4f, -0.4f, -0.3f, 1.4f, -0.4f, -0.1f, 1.4f, 0, 0, 1, false); AddQuad(-0.5f, 0.1f, 1.4f, -0.5f, -0.1f, 1.4f, -0.4f, -0.1f, 1.4f, -0.4f, 0.1f, 1.4f, 0, 0, 1, false); AddQuad(-0.5f, 0.3f, 1.4f, -0.5f, 0.1f, 1.4f, -0.4f, 0.1f, 1.4f, -0.4f, 0.3f, 1.4f, 0, 0, 1, false); AddQuad(-0.5f, 0.5f, 1.4f, -0.5f, 0.3f, 1.4f, -0.4f, 0.3f, 1.4f, -0.4f, 0.5f, 1.4f, 0, 0, 1, false); SetTransform(0.0f, 0.0f, 0.0f); } void GetCubeVector(int i, int x, int y, VECTOR *vector) { float s, t, sc, tc; s = ((float)x + 0.5) / (float)CUBESIZE; t = ((float)y + 0.5) / (float)CUBESIZE; sc = s*2.0 - 1.0; tc = t*2.0 - 1.0; switch (i) { case 0: vector->x = 1.0; vector->y = -tc; vector->z = -sc; break; case 1: vector->x = -1.0; vector->y = -tc; vector->z = sc; break; case 2: vector->x = sc; vector->y = 1.0; vector->z = tc; break; case 3: vector->x = sc; vector->y = -1.0; vector->z = -tc; break; case 4: vector->x = sc; vector->y = -tc; vector->z = 1.0; break; case 5: vector->x = -sc; vector->y = -tc; vector->z = -1.0; break; } *vector = Normalize(*vector); } void BuildCube(void) { VECTOR v; float pixels[CUBESIZE][CUBESIZE]; int i, x, y; glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, DIFF_CUBE); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, SPEC_CUBE); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); for (i = 0; i < 6; i++) { for (y = 0; y < CUBESIZE; y++) { for (x = 0; x < CUBESIZE; x++) { GetCubeVector(i, x, y, &v); pixels[y][x] = (v.z > 0) ? v.z : 0; } } glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, DIFF_CUBE); gluBuild2DMipmaps(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+i, GL_LUMINANCE8, CUBESIZE, CUBESIZE, GL_LUMINANCE, GL_FLOAT, pixels); for (y = 0; y < CUBESIZE; y++) { for (x = 0; x < CUBESIZE; x++) { GetCubeVector(i, x, y, &v); pixels[y][x] = (v.z > 0) ? powf(v.z, SHINY) : 0; } } glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, SPEC_CUBE); gluBuild2DMipmaps(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+i, GL_LUMINANCE8, CUBESIZE, CUBESIZE, GL_LUMINANCE, GL_FLOAT, pixels); } } #ifdef NETWORK int NetRead(char *buf, int n) { int bcount; int br; bcount = 0; br = 0; while (bcount < n) { if (networkThreadDie) { return bcount; } br = recv(sock, buf, n-bcount, 0); if (br != SOCKET_ERROR) { bcount += br; buf += br; } else { printf("Error\n"); br = WSAGetLastError(); return -1; } } return bcount; } void NetworkProc(void *arg) { int i; for (;;) { if (networkThreadDie) { break; } if (NetRead((char *)&lightPositions[0].x, nLights*sizeof(VECTOR)) == -1) { break; } if (networkThreadDie) { break; } if (NetRead((char *)&receiveRadiosity[0][0], nQuads*3*sizeof(unsigned short)) == -1) { break; } if (networkThreadDie) { break; } for (i = 0; i < nQuads; i++) { baseRadiosity[i].x = receiveRadiosity[i][0] / (65536.0f * SCALE_PROBLEM); baseRadiosity[i].y = receiveRadiosity[i][1] / (65536.0f * SCALE_PROBLEM); baseRadiosity[i].z = receiveRadiosity[i][2] / (65536.0f * SCALE_PROBLEM); } if (NetRead((char *)&receiveRadiosity[0][0], nQuads*3*sizeof(unsigned short)) == -1) { break; } if (networkThreadDie) { break; } for (i = 0; i < nQuads; i++) { radiosity[i].x = receiveRadiosity[i][0] / (65536.0f * SCALE_PROBLEM); radiosity[i].y = receiveRadiosity[i][1] / (65536.0f * SCALE_PROBLEM); radiosity[i].z = receiveRadiosity[i][2] / (65536.0f * SCALE_PROBLEM); } } printf("Shutting down network thread\n"); closesocket(sock); } #endif #pragma optimize("", off) // Set up state, build geometry void init(void) { int i, j, ii, jj; float s0, s1, t0, t1; float v1[3], v2[3], v3[3], v4[3]; #ifdef NETWORK int res; HOSTENT *host; struct sockaddr_in sa; #endif glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB"); glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB"); glClearColor(0.0, 0.0, 0.0, 1.0); glClearStencil(0); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vertices); glTexCoordPointer(3, GL_FLOAT, 0, texcoords); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbient); glMaterialf(GL_FRONT, GL_SHININESS, SHINY); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glBlendFunc(GL_ONE, GL_ONE); BuildCube(); SetTransform(0.0f, 0.0f, 0.0f); // Floor StartMaterial(0.3f, 0.3f, 0.3f, 0.0f, 0.0f, 0.0f); v1[0] = -10; v1[1] = -10; v1[2] = 0; v2[0] = 10; v2[1] = -10; v2[2] = 0; v3[0] = 10; v3[1] = 10; v3[2] = 0; v4[0] = -10; v4[1] = 10; v4[2] = 0; TessQuad(v1, v2, v3, v4, 50, 50, 0, 0, 1); EndMaterial(); // Walls/ceiling StartMaterial(0.6f, 0.6f, 0.6f, 0.3f, 0.3f, 0.3f); v1[0] = -10; v1[1] = -10; v1[2] = 3; v2[0] = -10; v2[1] = 10; v2[2] = 3; v3[0] = 10; v3[1] = 10; v3[2] = 3; v4[0] = 10; v4[1] = -10; v4[2] = 3; TessQuad(v1, v2, v3, v4, 50, 50, 0, 0, -1); v1[0] = 10; v1[1] = -10; v1[2] = 0; v2[0] = 10; v2[1] = -10; v2[2] = 3; v3[0] = 10; v3[1] = 10; v3[2] = 3; v4[0] = 10; v4[1] = 10; v4[2] = 0; TessQuad(v1, v2, v3, v4, 15, 50, -1, 0, 0); v1[0] = -10; v1[1] = -10; v1[2] = 0; v2[0] = -10; v2[1] = 10; v2[2] = 0; v3[0] = -10; v3[1] = 10; v3[2] = 3; v4[0] = -10; v4[1] = -10; v4[2] = 3; TessQuad(v1, v2, v3, v4, 50, 15, 1, 0, 0); v1[0] = -10; v1[1] = 10; v1[2] = 0; v2[0] = 10; v2[1] = 10; v2[2] = 0; v3[0] = 10; v3[1] = 10; v3[2] = 3; v4[0] = -10; v4[1] = 10; v4[2] = 3; TessQuad(v1, v2, v3, v4, 50, 15, 0, -1, 0); v1[0] = -10; v1[1] = -10; v1[2] = 0; v2[0] = -10; v2[1] = -10; v2[2] = 3; v3[0] = 10; v3[1] = -10; v3[2] = 3; v4[0] = 10; v4[1] = -10; v4[2] = 0; TessQuad(v1, v2, v3, v4, 15, 50, 0, 1, 0); EndMaterial(); StartMaterial(0.4f, 0.2f, 0.05f, 1.0f, 1.0f, 1.0f); gridStarts[nGrids] = nQuads; gridWidths[nGrids] = 50; gridHeights[nGrids] = 20; nGrids++; for (ii = 0; ii < 50; ii += BLOCK_SIZE) { for (jj = 0; jj < 20; jj += BLOCK_SIZE) { for (i = 0; (i < BLOCK_SIZE) && (ii+i < 50); i++) { s0 = 2 * (float)(ii+i) / 50 - 1; s1 = 2 * (float)(ii+i+1) / 50 - 1; for (j = 0; (j < BLOCK_SIZE) && (jj+j < 20); j++) { t0 = 2 * (float)(jj+j) / 20 - 1; t1 = 2 * (float)(jj+j+1) / 20 - 1; AddQuad(5*s0, (3-s0*s0)*t0, 1.0f, 5*s1, (3-s1*s1)*t0, 1.0f, 5*s1, (3-s1*s1)*t1, 1.0f, 5*s0, (3-s0*s0)*t1, 1.0f, 0, 0, 1, false); } } } } gridStarts[nGrids] = nQuads; gridWidths[nGrids] = 50; gridHeights[nGrids] = 20; nGrids++; for (ii = 0; ii < 50; ii += BLOCK_SIZE) { for (jj = 0; jj < 20; jj += BLOCK_SIZE) { for (i = 0; (i < BLOCK_SIZE) && (ii+i < 50); i++) { s0 = 2 * (float)(ii+i) / 50 - 1; s1 = 2 * (float)(ii+i+1) / 50 - 1; for (j = 0; (j < BLOCK_SIZE) && (jj+j < 20); j++) { t0 = 2 * (float)(jj+j) / 20 - 1; t1 = 2 * (float)(jj+j+1) / 20 - 1; AddQuad(5*s0, (3-s0*s0)*t0, 0.9f, 5*s0, (3-s0*s0)*t1, 0.9f, 5*s1, (3-s1*s1)*t1, 0.9f, 5*s1, (3-s1*s1)*t0, 0.9f, 0, 0, -1, false); } } } } // Global cylinder (a hack) BeginCylinder(0, 0, 0.0f, 1.4f, 5.66f); BeginCylinder(0, 0, 0.9f, 1.0f, 5.39f); SetSimpleNormal(0, 0, 1); for (i = 0; i <= 10; i++) { s0 = 2 * (float)i / 10 - 1; SimplePolyVertex(5*s0, s0*s0-3, 1.0f); } for (i = 10; i >= 0; i--) { s0 = 2 * (float)i / 10 - 1; SimplePolyVertex(5*s0, 3-s0*s0, 1.0f); } EndSimplePoly(); SetSimpleNormal(0, 0, -1); for (i = 0; i <= 10; i++) { s0 = 2 * (float)i / 10 - 1; SimplePolyVertex(5*s0, s0*s0-3, 0.9f); } for (i = 10; i >= 0; i--) { s0 = 2 * (float)i / 10 - 1; SimplePolyVertex(5*s0, 3-s0*s0, 0.9f); } EndSimplePoly(); SetSimpleNormal(-1, 0, 0); SimplePolyVertex(-5, -2, 1.0f); SimplePolyVertex(-5, 2, 1.0f); SimplePolyVertex(-5, 2, 0.9f); SimplePolyVertex(-5, -2, 0.9f); EndSimplePoly(); SetSimpleNormal(1, 0, 0); SimplePolyVertex(5, -2, 1.0f); SimplePolyVertex(5, 2, 1.0f); SimplePolyVertex(5, 2, 0.9f); SimplePolyVertex(5, -2, 0.9f); EndSimplePoly(); SetSimpleNormal(-1, -5, 0); SimplePolyVertex(-5, -2, 1.0f); SimplePolyVertex(-5, -2, 0.9f); SimplePolyVertex( 0, -3, 0.9f); SimplePolyVertex( 0, -3, 1.0f); EndSimplePoly(); SetSimpleNormal(-1, 5, 0); SimplePolyVertex(-5, 2, 1.0f); SimplePolyVertex( 0, 3, 1.0f); SimplePolyVertex( 0, 3, 0.9f); SimplePolyVertex(-5, 2, 0.9f); EndSimplePoly(); SetSimpleNormal(1, -5, 0); SimplePolyVertex( 0, -3, 1.0f); SimplePolyVertex( 0, -3, 0.9f); SimplePolyVertex( 5, -2, 0.9f); SimplePolyVertex( 5, -2, 1.0f); EndSimplePoly(); SetSimpleNormal(1, 5, 0); SimplePolyVertex( 0, 3, 1.0f); SimplePolyVertex( 5, 2, 1.0f); SimplePolyVertex( 5, 2, 0.9f); SimplePolyVertex( 0, 3, 0.9f); EndSimplePoly(); AddChair(-5.0f, -0.8f, 0.0f); AddChair(-5.0f, 0.8f, 0.0f); AddChair(-3.9f, -2.15f, 70.0f); AddChair(-3.9f, 2.15f, 290.0f); AddChair(-2.4f, -2.6f, 75.0f); AddChair(-2.4f, 2.6f, 285.0f); AddChair(-0.9f, -2.9f, 83.0f); AddChair(-0.9f, 2.9f, 277.0f); AddChair( 0.9f, -2.9f, 97.0f); AddChair( 0.9f, 2.9f, 263.0f); AddChair( 2.4f, -2.6f, 105.0f); AddChair( 2.4f, 2.6f, 255.0f); AddChair( 3.9f, -2.15f, 110.0f); AddChair( 3.9f, 2.15f, 250.0f); AddChair( 5.0f, -0.8f, 180.0f); AddChair( 5.0f, 0.8f, 180.0f); for (j = 0; j < 20; j++) { t0 = 2 * (float)j / 20 - 1; t1 = 2 * (float)(j+1) / 20 - 1; AddQuad(-5, 2*t0, 1.0f, -5, 2*t1, 1.0f, -5, 2*t1, 0.9f, -5, 2*t0, 0.9f, -1, 0, 0, false); } for (j = 0; j < 20; j++) { t0 = 2 * (float)j / 20 - 1; t1 = 2 * (float)(j+1) / 20 - 1; AddQuad(5, 2*t0, 1.0f, 5, 2*t0, 0.9f, 5, 2*t1, 0.9f, 5, 2*t1, 1.0f, 1, 0, 0, false); } for (i = 0; i < 50; i++) { s0 = 2 * (float)i / 50 - 1; s1 = 2 * (float)(i+1) / 50 - 1; AddQuad(5*s0, s0*s0-3, 1.0f, 5*s0, s0*s0-3, 0.9f, 5*s1, s1*s1-3, 0.9f, 5*s1, s1*s1-3, 1.0f, s0+s1, -5, 0, false); AddQuad(5*s0, 3-s0*s0, 1.0f, 5*s1, 3-s1*s1, 1.0f, 5*s1, 3-s1*s1, 0.9f, 5*s0, 3-s0*s0, 0.9f, s0+s1, 5, 0, false); } EndMaterial(); StartMaterial(0.2f, 0.2f, 0.2f, 0.4f, 0.4f, 0.4f); AddLeg(-4.5f, -1.5f); AddLeg(-4.5f, 1.5f); AddLeg( 0.0f, -2.5f); AddLeg( 0.0f, 2.5f); AddLeg( 4.5f, -1.5f); AddLeg( 4.5f, 1.5f); EndMaterial(); #if 1 nLights = 16; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { //lightPositions[4*i+j] = VECTOR(-5+3.333f*i, -3+2*j, 2); lightPositions[4*i+j] = VECTOR(-5+3.333f*i, -2.0+1.333*j, 2); } } #else nLights = 1; lightPositions[0] = VECTOR(0,0,2); #endif printf("%d materials\n", nMaterials); printf("%d quads\n", nQuads); printf("%d edges\n", nEdges); printf("%d simple polys (%d vertices)\n", nSimplePolys, nTotalSimplePolyVertices); printf("%d bounding cylinders\n", nCylinders); printf("%d lights\n", nLights); printf("%d runs\n", nRuns); printf("%d grids\n", nGrids); float weightSum = 0.0f; for (j = 0; j < FF_SIZE; j++) { float y = 2*(j+0.5f) / FF_SIZE - 1.0f; for (i = 0; i < FF_SIZE; i++) { float x = 2*(i+0.5f) / FF_SIZE - 1.0f; float w = 1.0+x*x+y*y; w = 1.0f/(w*w); w /= 0.25f*FF_SIZE*FF_SIZE * M_PI; ffWeights[j][i] = w; weightSum += w; } } for (j = 0; j < FF_SIZE/2; j++) { float y = 2*(j+0.5f) / FF_SIZE; for (i = 0; i < FF_SIZE; i++) { float x = 2*(i+0.5f) / FF_SIZE - 1.0f; float w = 1.0+x*x+y*y; w = y/(w*w); w /= 0.25f*FF_SIZE*FF_SIZE * M_PI; ffWeights[j][i+FF_SIZE] = w; ffWeights[j+FF_SIZE/2][i+FF_SIZE] = w; ffWeights[j][i+2*FF_SIZE] = w; ffWeights[j+FF_SIZE/2][i+2*FF_SIZE] = w; weightSum += 4*w; } } printf("Weight sum = %f\n", weightSum); #ifdef NETWORK WSAStartup(0x202, &wsadata); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.S_un.S_addr = inet_addr(SERVER); if (sa.sin_addr.S_un.S_addr == INADDR_NONE) { host = gethostbyname(SERVER); memcpy(&sa.sin_addr, host->h_addr_list[0], sizeof(sa.sin_addr)); } sa.sin_port = htons(PORT); connect(sock, (struct sockaddr *)&sa, sizeof(sa)); printf("Sending scene... "); res = send(sock, (char *)&nMaterials, sizeof(int), 0); res = send(sock, (char *)nMaterialQuads, nMaterials*sizeof(int), 0); res = send(sock, (char *)diffuse, nMaterials*4*sizeof(float), 0); res = send(sock, (char *)&nQuads, sizeof(int), 0); for (i = 0; i < nQuads; i++) { res = send(sock, (char *)&vertices[i], 4*sizeof(VECTOR), 0); res = send(sock, (char *)&normals[i], sizeof(VECTOR), 0); } res = send(sock, (char *)&nSimplePolys, sizeof(int), 0); res = send(sock, (char *)&nTotalSimplePolyVertices, sizeof(int), 0); res = send(sock, (char *)nSimplePolyVertices, nSimplePolys*sizeof(int), 0); res = send(sock, (char *)simplePolyNormals, nSimplePolys*sizeof(VECTOR), 0); res = send(sock, (char *)simplePolyDistances, nSimplePolys*sizeof(float), 0); res = send(sock, (char *)simplePolyVertices, nTotalSimplePolyVertices*sizeof(VECTOR), 0); res = send(sock, (char *)&nCylinders, sizeof(int), 0); res = send(sock, (char *)cylinderPolyStart, nCylinders*sizeof(int), 0); res = send(sock, (char *)cylinderPolyVertexStart, nCylinders*sizeof(int), 0); res = send(sock, (char *)cylinderX, nCylinders*sizeof(float), 0); res = send(sock, (char *)cylinderY, nCylinders*sizeof(float), 0); res = send(sock, (char *)cylinderMinZ, nCylinders*sizeof(float), 0); res = send(sock, (char *)cylinderMaxZ, nCylinders*sizeof(float), 0); res = send(sock, (char *)cylinderR, nCylinders*sizeof(float), 0); res = send(sock, (char *)&nLights, sizeof(int), 0); for (i = 0; i < nLights; i++) { res = send(sock, (char *)&lightPositions[i], sizeof(VECTOR), 0); } printf("done\n"); printf("Starting network thread...\n"); _beginthread(NetworkProc, 0, NULL); #endif } #pragma optimize("", on) // Window reshape handler void reshape(int w, int h) { width = w; height = h; } // Event (menu and keyboard) handler void MenuProc(int menuitem) { switch (menuitem) { case '1': lightModel = LIGHT_PERVERTEX; break; case '2': lightModel = LIGHT_PERVERTEX_SHADOWED; break; case '3': lightModel = LIGHT_PERPIXEL_SHADOWED; break; case '4': lightModel = LIGHT_RADIOSITY_BASELINE; break; case '5': lightModel = LIGHT_RADIOSITY; break; case '6': lightModel = LIGHT_RADIOSITY_PERPIXEL_SHADOWED; break; case 'l': showLights = !showLights; break; case 's': showSpecular = !showSpecular; break; case 'f': filterSolutions = !filterSolutions; break; case 'w': wireframe = !wireframe; break; case 'a': eyeZ += 0.1f; break; case 'z': eyeZ -= 0.1f; break; case '&': networkThreadDie = 1; break; } glutPostRedisplay(); } // Keyboard handler void keyboard(unsigned char key, int x, int y) { if (key == 27) exit(0); MenuProc(key); } void special(int key, int x, int y) { glutPostRedisplay(); } static void LoadGrids(void) { int i, j, ii, jj, gridIndex, quadIndex; float gridPixels[3000][3], color[3]; float s0, s1, t0, t1; for (gridIndex = 0; gridIndex < nGrids; gridIndex++) { quadIndex = gridStarts[gridIndex]; for (ii = 0; ii < gridWidths[gridIndex]; ii += BLOCK_SIZE) { for (jj = 0; jj < gridHeights[gridIndex]; jj += BLOCK_SIZE) { for (i = 0; (i < BLOCK_SIZE) && (ii+i < gridWidths[gridIndex]); i++) { s0 = (float)(ii+i); s1 = (float)(ii+i+1); for (j = 0; (j < BLOCK_SIZE) && (jj+j < gridHeights[gridIndex]); j++) { t0 = (float)(jj+j); t1 = (float)(jj+j+1); switch (lightModel) { case LIGHT_RADIOSITY_BASELINE: color[0] = baseRadiosity[quadIndex].x; color[1] = baseRadiosity[quadIndex].y; color[2] = baseRadiosity[quadIndex].z; break; case LIGHT_RADIOSITY: color[0] = radiosity[quadIndex].x; color[1] = radiosity[quadIndex].y; color[2] = radiosity[quadIndex].z; break; case LIGHT_RADIOSITY_PERPIXEL_SHADOWED: color[0] = radiosity[quadIndex].x - baseRadiosity[quadIndex].x; color[1] = radiosity[quadIndex].y - baseRadiosity[quadIndex].y; color[2] = radiosity[quadIndex].z - baseRadiosity[quadIndex].z; break; } gridPixels[(jj+j)*gridWidths[gridIndex] + ii+i][0] = color[0]; gridPixels[(jj+j)*gridWidths[gridIndex] + ii+i][1] = color[1]; gridPixels[(jj+j)*gridWidths[gridIndex] + ii+i][2] = color[2]; texcoords[quadIndex][0].x = s0; texcoords[quadIndex][0].y = t0; texcoords[quadIndex][0].z = 0; texcoords[quadIndex][1].x = s1; texcoords[quadIndex][1].y = t0; texcoords[quadIndex][1].z = 0; texcoords[quadIndex][2].x = s1; texcoords[quadIndex][2].y = t1; texcoords[quadIndex][2].z = 0; texcoords[quadIndex][3].x = s0; texcoords[quadIndex][3].y = t1; texcoords[quadIndex][3].z = 0; quadIndex++; } } } } glBindTexture(GL_TEXTURE_RECTANGLE_NV, GRID_BASE+gridIndex); glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGB8, gridWidths[gridIndex], gridHeights[gridIndex], 0, GL_RGB, GL_FLOAT, gridPixels); glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, filterSolutions ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, filterSolutions ? GL_LINEAR : GL_NEAREST); } } // Display handler void display(void) { float position[4]; float zero[4] = {0, 0, 0, 0}; float one[4] = {1, 1, 1, 1}; float lightDiffuse[4] = {1, 1, 1, 1}; float lightSpecular[4] = {1, 1, 1, 1}; int i, j, k, start, end, lightIndex; #ifdef GENERATE_FORM_FACTORS int x, y, ii, jj; static int first = 1; int zeros = 0; int zeroRun; int zeroRuns = 0; int lastType, thisType, runLength, runStart, ff; float sum, fullSum; FILE *f; #endif glDepthMask(GL_TRUE); #ifdef GENERATE_FORM_FACTORS // Render from a particular vantage point if (!first) goto done; first = 0; f = fopen("form_factors", "wb"); glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); glScissor(0, 0, FF_SIZE*3, FF_SIZE); sum = fullSum = 0; for (i = 0; i < nQuads; i++) { VECTOR pos, dir, up; for (j = 0; j < nQuads; j++) { formFactors[j] = 0; } for (jj = 0; jj < NJITTER; jj++) { float t = (jj+0.5f)/NJITTER; for (ii = 0; ii < NJITTER; ii++) { float s = (ii+0.5f)/NJITTER; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); pos = (1-s)*(1-t)*vertices[i][0] + s*(1-t)*vertices[i][1] + s* t*vertices[i][2] + (1-s)* t*vertices[i][3]; dir = pos + normals[i]; up = tangents[i]; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90.0, 1.0, 0.1, 40.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); glViewport(0, 0, FF_SIZE, FF_SIZE); for (j = 0; j < nQuads; j++) { glColor3ub((j*100+1) & 255, ((j*100+1) >> 8) & 255, ((j*100+1) >> 16) & 255); glDrawArrays(GL_QUADS, j*4, 4); } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glScalef(1, 2, 1); glTranslatef(0, -0.5, 0); gluPerspective(90.0, 1.0, 0.1, 40.0); up = normals[i]; dir = pos + tangents[i]; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); glViewport(FF_SIZE, 0, FF_SIZE, FF_SIZE/2); for (j = 0; j < nQuads; j++) { glColor3ub((j*100+1) & 255, ((j*100+1) >> 8) & 255, ((j*100+1) >> 16) & 255); glDrawArrays(GL_QUADS, j*4, 4); } dir = pos - tangents[i]; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); glViewport(FF_SIZE, FF_SIZE/2, FF_SIZE, FF_SIZE/2); for (j = 0; j < nQuads; j++) { glColor3ub((j*100+1) & 255, ((j*100+1) >> 8) & 255, ((j*100+1) >> 16) & 255); glDrawArrays(GL_QUADS, j*4, 4); } dir = pos + binormals[i]; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); glViewport(2*FF_SIZE, 0, FF_SIZE, FF_SIZE/2); for (j = 0; j < nQuads; j++) { glColor3ub((j*100+1) & 255, ((j*100+1) >> 8) & 255, ((j*100+1) >> 16) & 255); glDrawArrays(GL_QUADS, j*4, 4); } dir = pos - binormals[i]; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z); glViewport(2*FF_SIZE, FF_SIZE/2, FF_SIZE, FF_SIZE/2); for (j = 0; j < nQuads; j++) { glColor3ub((j*100+1) & 255, ((j*100+1) >> 8) & 255, ((j*100+1) >> 16) & 255); glDrawArrays(GL_QUADS, j*4, 4); } glReadPixels(0, 0, 3*FF_SIZE, FF_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, ffImage); for (y = 0; y < FF_SIZE; y++) { for (x = 0; x < 3*FF_SIZE; x++) { int j = ffImage[y][x][0] + 256*ffImage[y][x][1] + 65536*ffImage[y][x][2]; if (j == 0) { continue; } formFactors[(j-1)/100] += ffWeights[y][x] / (NJITTER*NJITTER); } } } } zeroRun = 0; for (j = 0; j < nQuads; j++) { // Experience shows that this scaling/truncation works fairly well formFactors[j] *= 65536.0f; fullSum += formFactors[j]; formFactors[j] = (int)(formFactors[j] + 0.5f); sum += formFactors[j]; if (formFactors[j] == 0) { zeroRun++; } else { if (zeroRun > KILL_THRESHOLD) { zeros += zeroRun; zeroRuns++; } zeroRun = 0; } } if (zeroRun > KILL_THRESHOLD) { zeros += zeroRun; zeroRuns++; } // Write with a very simple RLE compression scheme ff = (int)formFactors[0]; if (ff == 0) { lastType = 0; } else if (ff <= 255) { lastType = 1; } else { lastType = 2; } runLength = 1; runStart = 0; for (j = 1; j < nQuads; j++) { ff = (int)formFactors[j]; if (ff == 0) { thisType = 0; } else if (ff <= 255) { thisType = 1; } else { thisType = 2; } if ((thisType != lastType) || (runLength == 84)) { fputc(runLength * 3 + lastType, f); switch (lastType) { case 0: break; case 1: for (k = runStart; k < runStart+runLength; k++) { int ff = (int)formFactors[k]; fputc(ff, f); } break; case 2: for (k = runStart; k < runStart+runLength; k++) { int ff = (int)formFactors[k]; fputc(ff & 0xFF, f); fputc(ff >> 8, f); } break; } runLength = 1; runStart = j; } else if (thisType == lastType) { runLength++; } lastType = thisType; } fputc(runLength * 3 + lastType, f); switch (lastType) { case 0: break; case 1: for (k = runStart; k < runStart+runLength; k++) { int ff = (int)formFactors[k]; fputc(ff, f); } break; case 2: for (k = runStart; k < runStart+runLength; k++) { int ff = (int)formFactors[k]; fputc(ff & 0xFF, f); fputc(ff >> 8, f); } break; } } fclose(f); glDisable(GL_SCISSOR_TEST); glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK); printf("%d/%d zeros\n", zeros, nQuads*nQuads); printf("%d zero runs\n", zeroRuns); printf("%f average zero run length\n", (float)zeros / zeroRuns); printf("%f: %f/%f\n", sum/fullSum, sum, fullSum); done: #endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); glViewport(0, 0, (GLsizei)width, (GLsizei)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLdouble)width/(GLdouble)height, 0.1, 40.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eyeX, eyeY, eyeZ, eyeX+cos(theta), eyeY+sin(theta), eyeZ, 0, 0, 1); // Draw scene into depth buffer glDisable(GL_STENCIL_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDisable(GL_LIGHTING); glDrawArrays(GL_QUADS, 0, nQuads*4); for (lightIndex = 0; lightIndex < nLights; lightIndex++) { VECTOR lightPosition = lightPositions[lightIndex]; glDepthFunc(GL_LEQUAL); switch (lightModel) { case LIGHT_PERVERTEX_SHADOWED: case LIGHT_PERPIXEL_SHADOWED: case LIGHT_RADIOSITY_PERPIXEL_SHADOWED: for (i = 0; i < nQuads; i++) { if (DotProduct(lightPosition - vertices[i][0], normals[i]) > 0.0f) { quadLightFrontFace[i] = true; } else { quadLightFrontFace[i] = false; } } glClear(GL_STENCIL_BUFFER_BIT); // Draw shadow volumes glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xFF); glDepthMask(GL_FALSE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDisable(GL_LIGHTING); glCullFace(GL_BACK); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT); glBegin(GL_TRIANGLES); for (i = 0; i < nEdges; i++) { if (quadLightFrontFace[quad0[i]] != quadLightFrontFace[quad1[i]]) { glVertex4f(-lightPosition.x, -lightPosition.y, -lightPosition.z, -1.0f); if (quadLightFrontFace[quad0[i]]) { glVertex3fv(&vtx1[i].x); glVertex3fv(&vtx0[i].x); } else { glVertex3fv(&vtx0[i].x); glVertex3fv(&vtx1[i].x); } } } glEnd(); glCullFace(GL_FRONT); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT); glBegin(GL_TRIANGLES); for (i = 0; i < nEdges; i++) { if (quadLightFrontFace[quad0[i]] != quadLightFrontFace[quad1[i]]) { glVertex4f(-lightPosition.x, -lightPosition.y, -lightPosition.z, -1.0f); if (quadLightFrontFace[quad0[i]]) { glVertex3fv(&vtx1[i].x); glVertex3fv(&vtx0[i].x); } else { glVertex3fv(&vtx0[i].x); glVertex3fv(&vtx1[i].x); } } } glEnd(); glCullFace(GL_BACK); break; } position[0] = lightPosition.x; position[1] = lightPosition.y; position[2] = lightPosition.z; position[3] = 1.0f; glLightfv(GL_LIGHT0, GL_POSITION, position); glLightfv(GL_LIGHT0, GL_AMBIENT, zero); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse); if (showSpecular) { glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular); } else { glLightfv(GL_LIGHT0, GL_SPECULAR, zero); } glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.0f); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 1.0f); // Draw lit scene glEnable(GL_BLEND); glDisable(GL_STENCIL_TEST); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glDepthMask(GL_FALSE); glDepthFunc(GL_EQUAL); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); switch (lightModel) { case LIGHT_PERVERTEX: glEnable(GL_LIGHTING); start = 0; k = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, diffuse[j]); glMaterialfv(GL_FRONT, GL_SPECULAR, specular[j]); end = start + nMaterialQuads[j]; i = start; while (i < end) { glNormal3fv(&normals[i].x); glDrawArrays(GL_QUADS, i*4, runLengths[k]*4); i += runLengths[k]; k++; } start = end; } break; case LIGHT_PERVERTEX_SHADOWED: glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0, 0xFF); glEnable(GL_LIGHTING); start = 0; k = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, diffuse[j]); glMaterialfv(GL_FRONT, GL_SPECULAR, specular[j]); end = start + nMaterialQuads[j]; i = start; while (i < end) { glNormal3fv(&normals[i].x); glDrawArrays(GL_QUADS, i*4, runLengths[k]*4); i += runLengths[k]; k++; } start = end; } break; case LIGHT_PERPIXEL_SHADOWED: glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0, 0xFF); glLightfv(GL_LIGHT0, GL_AMBIENT, one); glEnable(GL_LIGHTING); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, DIFF_CUBE); for (i = 0; i < nQuads; i++) { for (j = 0; j < 4; j++) { VECTOR lightDir = lightPosition-vertices[i][j]; texcoords[i][j].x = DotProduct(lightDir, tangents[i]); texcoords[i][j].y = DotProduct(lightDir, binormals[i]); texcoords[i][j].z = DotProduct(lightDir, normals[i]); } } start = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse[j]); glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); glMaterialfv(GL_FRONT, GL_SPECULAR, zero); end = start + nMaterialQuads[j]; glDrawArrays(GL_QUADS, start*4, (end-start)*4); start = end; } if (showSpecular) { glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, SPEC_CUBE); for (i = 0; i < nQuads; i++) { for (j = 0; j < 4; j++) { VECTOR lightDir = lightPosition-vertices[i][j]; VECTOR viewerDir = VECTOR(eyeX,eyeY,eyeZ)-vertices[i][j]; VECTOR halfDir = Normalize(lightDir)+Normalize(viewerDir); texcoords[i][j].x = DotProduct(halfDir, tangents[i]); texcoords[i][j].y = DotProduct(halfDir, binormals[i]); texcoords[i][j].z = DotProduct(halfDir, normals[i]); } } start = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT, specular[j]); glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); glMaterialfv(GL_FRONT, GL_SPECULAR, zero); end = start + nMaterialQuads[j]; glDrawArrays(GL_QUADS, start*4, (end-start)*4); start = end; } } glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_CUBE_MAP_ARB); break; case LIGHT_RADIOSITY_BASELINE: glDisable(GL_LIGHTING); if (lightIndex == 0) { LoadGrids(); k = 0; for (j = 0; j < nGrids; j++) { for (i = k; i < gridStarts[j]; i++) { glColor3fv(&baseRadiosity[i].x); glDrawArrays(GL_QUADS, i*4, 4); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_RECTANGLE_NV); glBindTexture(GL_TEXTURE_RECTANGLE_NV, GRID_BASE+j); glColor3f(1,1,1); glDrawArrays(GL_QUADS, gridStarts[j]*4, gridWidths[j]*gridHeights[j]*4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_RECTANGLE_NV); k = gridStarts[j] + gridWidths[j]*gridHeights[j]; } for (i = k; i < nQuads; i++) { glColor3fv(&baseRadiosity[i].x); glDrawArrays(GL_QUADS, i*4, 4); } } break; case LIGHT_RADIOSITY: glDisable(GL_LIGHTING); if (lightIndex == 0) { LoadGrids(); k = 0; for (j = 0; j < nGrids; j++) { for (i = k; i < gridStarts[j]; i++) { glColor3fv(&radiosity[i].x); glDrawArrays(GL_QUADS, i*4, 4); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_RECTANGLE_NV); glBindTexture(GL_TEXTURE_RECTANGLE_NV, GRID_BASE+j); glColor3f(1,1,1); glDrawArrays(GL_QUADS, gridStarts[j]*4, gridWidths[j]*gridHeights[j]*4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_RECTANGLE_NV); k = gridStarts[j] + gridWidths[j]*gridHeights[j]; } for (i = k; i < nQuads; i++) { glColor3fv(&radiosity[i].x); glDrawArrays(GL_QUADS, i*4, 4); } } break; case LIGHT_RADIOSITY_PERPIXEL_SHADOWED: glDisable(GL_LIGHTING); if (lightIndex == 0) { LoadGrids(); k = 0; for (j = 0; j < nGrids; j++) { for (i = k; i < gridStarts[j]; i++) { VECTOR indirect = radiosity[i] - baseRadiosity[i]; glColor3fv(&indirect.x); glDrawArrays(GL_QUADS, i*4, 4); } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_RECTANGLE_NV); glBindTexture(GL_TEXTURE_RECTANGLE_NV, GRID_BASE+j); glColor3f(1,1,1); glDrawArrays(GL_QUADS, gridStarts[j]*4, gridWidths[j]*gridHeights[j]*4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_RECTANGLE_NV); k = gridStarts[j] + gridWidths[j]*gridHeights[j]; } for (i = k; i < nQuads; i++) { VECTOR indirect = radiosity[i] - baseRadiosity[i]; glColor3fv(&indirect.x); glDrawArrays(GL_QUADS, i*4, 4); } } glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0, 0xFF); glLightfv(GL_LIGHT0, GL_AMBIENT, one); glEnable(GL_LIGHTING); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, DIFF_CUBE); for (i = 0; i < nQuads; i++) { for (j = 0; j < 4; j++) { VECTOR lightDir = lightPosition-vertices[i][j]; texcoords[i][j].x = DotProduct(lightDir, tangents[i]); texcoords[i][j].y = DotProduct(lightDir, binormals[i]); texcoords[i][j].z = DotProduct(lightDir, normals[i]); } } start = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT, diffuse[j]); glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); glMaterialfv(GL_FRONT, GL_SPECULAR, zero); end = start + nMaterialQuads[j]; glDrawArrays(GL_QUADS, start*4, (end-start)*4); start = end; } if (showSpecular) { glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, SPEC_CUBE); for (i = 0; i < nQuads; i++) { for (j = 0; j < 4; j++) { VECTOR lightDir = lightPosition-vertices[i][j]; VECTOR viewerDir = VECTOR(eyeX,eyeY,eyeZ)-vertices[i][j]; VECTOR halfDir = Normalize(lightDir)+Normalize(viewerDir); texcoords[i][j].x = DotProduct(halfDir, tangents[i]); texcoords[i][j].y = DotProduct(halfDir, binormals[i]); texcoords[i][j].z = DotProduct(halfDir, normals[i]); } } start = 0; for (j = 0; j < nMaterials; j++) { glMaterialfv(GL_FRONT, GL_AMBIENT, specular[j]); glMaterialfv(GL_FRONT, GL_DIFFUSE, zero); glMaterialfv(GL_FRONT, GL_SPECULAR, zero); end = start + nMaterialQuads[j]; glDrawArrays(GL_QUADS, start*4, (end-start)*4); start = end; } } glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_CUBE_MAP_ARB); break; } } glDisable(GL_BLEND); glDepthFunc(GL_ALWAYS); glPointSize(3.0f); glColor3f(1,0,0); glDisable(GL_LIGHTING); if (showLights) { glBegin(GL_POINTS); for (lightIndex = 0; lightIndex < nLights; lightIndex++) { glVertex3fv(&lightPositions[lightIndex].x); } glEnd(); glBegin(GL_LINES); for (i = 0; i < nEdges; i++) { if (quad1[i] < 0) { glVertex3fv(&vtx0[i].x); glVertex3fv(&vtx1[i].x); } } glEnd(); } glutReportErrors(); glutSwapBuffers(); } void idle(void) { if (GetAsyncKeyState(VK_LEFT)) { theta += 0.05f; } if (GetAsyncKeyState(VK_RIGHT)) { theta -= 0.05f; } if (GetAsyncKeyState(VK_UP)) { eyeX += 0.3f * cos(theta); eyeY += 0.3f * sin(theta); } if (GetAsyncKeyState(VK_DOWN)) { eyeX -= 0.3f * cos(theta); eyeY -= 0.3f * sin(theta); } glutPostRedisplay(); } // Build the popup menu void SetupMenus() { int menu; menu = glutCreateMenu(MenuProc); glutAddMenuEntry("Per-vertex lighting", '1'); glutAddMenuEntry("Per-vertex lighting w/ shadows", '2'); glutAddMenuEntry("Per-pixel lighting w/ shadows", '3'); glutAddMenuEntry("Radiosity algorithm input", '4'); glutAddMenuEntry("Pure radiosity lighting", '5'); glutAddMenuEntry("Radiosity + per-pixel w/ shadows", '6'); glutAddMenuEntry("--------------------------------", 0); glutAddMenuEntry("Toggle show lights", 'l'); glutAddMenuEntry("Toggle specular", 's'); glutAddMenuEntry("Toggle filtering", 'f'); glutAddMenuEntry("--------------------------------", 0); glutAddMenuEntry("Kill network thread", '&'); glutAttachMenu(GLUT_RIGHT_BUTTON); } // Stop redrawing when the menu pops up void MenuStateProc(int state) { if (state == GLUT_MENU_NOT_IN_USE) { glutIdleFunc(idle); } else { glutIdleFunc(NULL); } } int main(int argc, char **argv) { int i; glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(800, 400); glutCreateWindow("Parallel Radiosity Solver"); printf("Extensions available: %s\n", glGetString(GL_EXTENSIONS)); for (i = 0; i < ArraySize(requiredExtensions); i++) { if (!glutExtensionSupported(requiredExtensions[i])) { fprintf(stderr, "This app requires the %s extension.\n", requiredExtensions[i]); getchar(); return 0; } } init(); SetupMenus(); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutDisplayFunc(display); glutIdleFunc(idle); glutMenuStateFunc(MenuStateProc); glutMainLoop(); return 0; }