hypertile.cpp | vector.cpp | ||
hypertile.h | vector.h |
// ************************************************************************************** // ************************************************************************************** // *** HyperTile.cpp (HypEngine) // *** Copyright (c) 1999-2000 Bernie Freidin // *** Ported to OpenGL on 2-6-00 // *** (3Dfx Glide code is still here, but commented-out) // ************************************************************************************** // ************************************************************************************** #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <time.h> #include <gl/glut.h> #include "vector.h" #include "hypertile.h" static int WAIT_FOR_CLOCK = 1; static int MAIN__STOP = 0; static int TILES_HIT = 0; #define FLOOR_TEX_ID 1 // 1 #define WALL_TEX_ID 2 // 5 #define CORNER_TEX_ID 2 // 5 #define CEIL_TEX_ID 3 int MAIN__texcount = 4; unsigned int MAIN__texid[10]; char MAIN__texnames[][200] = { "Textures/floor.tga", // floor "Textures/wall.tga", // wall,corner "Textures/wall.tga", // ceiling "" }; static void MAIN__LoadTGA(char *fpath) { FILE *tga = fopen(fpath, "rb"); if(!tga) { fprintf(stderr, "\n\ncan't find required TGA (%s)\n", fpath); fprintf(stderr, "PRESS RETURN TO EXIT\n"); char wait[200]; gets(wait); exit(-1); } // **************************** // 2 bytes offset = N // 10 bytes of crap // 2 bytes = WIDTH // 2 bytes = HEIGHT // 2 bytes = BPP (24) // N bytes of crap.. // PIXEL DATA FOLLOWS (24bpp) // **************************** short offset, width, height; fread(&offset, sizeof(short), 1, tga); fseek(tga, 10, SEEK_CUR); fread(&width, sizeof(short), 1, tga); fread(&height, sizeof(short), 1, tga); fseek(tga, offset+2, SEEK_CUR); char *rgb = (char*)malloc(3*width*height); fread(rgb, 3, width*height, tga); fclose(tga); // Swap red and blue values for(int i = 0; i < width*height; i++) { char tmp = rgb[i*3]; rgb[i*3] = rgb[i*3+2]; rgb[i*3+2] = tmp; } gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb); free(rgb); } static void MAIN__LoadAlphaMask(int size) { char *rgb = (char*)malloc(3*size*size); for(int y = 0; y < size; y++) { for(int x = 0; x < size; x++) { vec2 v = vec2((float)(x-size/2), (float)(y-size/2)); v /= (float)(size/2); float fog = 1.f - (float)pow(v*v, 3.f); if(fog < 0.f) fog = 0.f; if(fog > 1.f) fog = 1.f; int fogi = (int)(fog * 255.f); rgb[x*3 + y*size*3 + 0] = fogi; rgb[x*3 + y*size*3 + 1] = fogi; rgb[x*3 + y*size*3 + 2] = fogi; } } gluBuild2DMipmaps(GL_TEXTURE_2D, 3, size, size, GL_RGB, GL_UNSIGNED_BYTE, rgb); free(rgb); } static void MAIN__TrackFPS(void) { static double sum = 0.f; static double num = 0.f; static int clk_count = 1; static clock_t clk1; static clock_t clk2; clk1 = clk2; clk2 = clock(); sum += (double)(clk2-clk1); num += 1.f; if(MAIN__STOP) { // FILE *fps_out = fopen("fps.txt", "w"); // if(!fps_out) return; // double fps = (double)CLOCKS_PER_SEC * num / sum; // fprintf(fps_out, "AVERAGE FPS= %lf\n", fps); // fclose(fps_out); exit(0); } } static void MAIN__RenderScene(void) { } // ********************************************************* // Backface rejection improves vertex stability by balancing // the recursion tree. However, it also occasionally omits a // tile when rendering near the border. This should be fixed // at some point.. // // (note - this is NOT triangle backface rejection!) // ********************************************************* #define BACKFACE_REJECT 1 // ************************************************************************************** // ************************************************************************************** // *** Structures // ************************************************************************************** // ************************************************************************************** struct vertex_t { vec3 v; // viewspace coords (x,y,z=1) vec3 c; // color value (r,g,b) float a; vec2 t; // texture coords (s,t) }; #define OBJ_FLAG_PLAYER 0x001 #define OBJ_FLAG_GHOST 0x002 #define OBJ_FLAG_MOVING 0x004 #define OBJ_FLAG_CAMERA 0x008 struct tile_t; struct obj_t { int flags; float r; // object radius float r_max; // object radius (target) mat3 m; // object transform mat3 m_inv; // inverse transform tile_t *tile; // parent tile obj_t *next; // next object in tile int verts; vec3 color1; vec3 color2; }; struct mesh_t // (432 bytes) { tile_t *tile; vec2 v[49]; // mesh verts (poincare) mat3 m; vec3 color; }; struct tile_t // (36 bytes) { int flags; // 4 bits WALL, 4 bits CORNER int frame_rendered; int frame_visited; tile_t *next[4]; obj_t *obj; mesh_t *mesh; }; // ************************************************************************************** // ************************************************************************************** // *** Defines // ************************************************************************************** // ************************************************************************************** //Link: http://teach.belmont.edu/ht/applet/htbu.html #define MAX_WORLD_OBJECTS 4000 #define MAX_ONSCREEN_OBJECTS 500 #define MAX_WORLD_TILES 30000 #define MAX_ONSCREEN_TILES 1000 #define RENDER 1 #if RENDER /* - 3Dfx Glide Macros #define RenderPoly(v,c) \ grDrawVertexArrayContiguous(GR_POLYGON, c, v, sizeof(vertex_t)) #define RenderTriFan(v,c) \ grDrawVertexArrayContiguous(GR_TRIANGLE_FAN, c, v, sizeof(vertex_t)) #define RenderTriStrip(v,c) \ grDrawVertexArrayContiguous(GR_TRIANGLE_STRIP, c, v, sizeof(vertex_t)) #define RenderWireframe(v,c) \ grDrawVertexArrayContiguous(GR_LINE_STRIP, c, v, sizeof(vertex_t)); \ grDrawVertexArrayContiguous(GR_LINE_STRIP, c/2, v, sizeof(vertex_t)*2) #define RenderPoint(v) grDrawPoint(v) */ // OpenGL Macros static void RenderPoly(vertex_t *v, int c) { glBegin(GL_POLYGON); for(int i = 0; i < c; i++) { glColor3fv((GLfloat*)&v[i].c); glTexCoord2fv((GLfloat*)&v[i].t); glVertex3fv((GLfloat*)&v[i].v); } glEnd(); } static void RenderTriFan(vertex_t *v, int c) { glBegin(GL_TRIANGLE_FAN); for(int i = 0; i < c; i++) { glColor3fv((GLfloat*)&v[i].c); glTexCoord2fv((GLfloat*)&v[i].t); glVertex3fv((GLfloat*)&v[i].v); } glEnd(); } static void RenderTriStrip(vertex_t *v, int c) { glBegin(GL_TRIANGLE_STRIP); for(int i = 0; i < c; i++) { glColor3fv((GLfloat*)&v[i].c); glTexCoord2fv((GLfloat*)&v[i].t); glVertex3fv((GLfloat*)&v[i].v); } glEnd(); } #define RenderWireframe(v,c) // not used #define RenderPoint(v) // not used #else #define RenderPoly(v,c) #define RenderTriFan(v,c) #define RenderTriStrip(v,c) #define RenderWireframe(v,c) #define RenderPoint(v) #endif /* - 3Dfx Glide int Render_LoadTexture(char *fn) { GrTexInfo info; Gu3dfInfo info2; long startaddr = grTexMinAddress(GR_TMU0); // download from disk gu3dfGetInfo(fn, &info2); info2.data = malloc(info2.mem_required); gu3dfLoad (fn, &info2); // setup info.smallLodLog2 = info2.header.small_lod; info.largeLodLog2 = info2.header.large_lod; info.aspectRatioLog2 = info2.header.aspect_ratio; info.format = info2.header.format; info.data = info2.data; // upload to hardware grTexDownloadMipMap(GR_TMU0, startaddr, GR_MIPMAPLEVELMASK_BOTH, &info); grTexSource (GR_TMU0, startaddr, GR_MIPMAPLEVELMASK_BOTH, &info); free(info2.data); return 0; // ok } */ // ************************************************************************************** // ************************************************************************************** // *** Global Variables and Macros // ************************************************************************************** // ************************************************************************************** #define TILE_FLOOR_FLAG 0x0100 #define TILE_FREE_FLAG 0x0200 #define SetWall(tile,k) (tile)->flags |= ( 1<<(k)) #define SetCorner(tile,k) (tile)->flags |= (16<<(k)) #define SetFloor(tile) (tile)->flags |= TILE_FLOOR_FLAG #define SetFree(tile) (tile)->flags |= TILE_FREE_FLAG #define ClearWall(tile,k) (tile)->flags &= ~( 1<<(k)) #define ClearCorner(tile,k) (tile)->flags &= ~(16<<(k)) #define ClearFloor(tile) (tile)->flags &= ~TILE_FLOOR_FLAG #define ClearFree(tile) (tile)->flags &= ~TILE_FREE_FLAG #define IsWall(tile,k) ((tile)->flags & ( 1<<(k))) #define IsCorner(tile,k) ((tile)->flags & (16<<(k))) #define IsFloor(tile) ((tile)->flags & TILE_FLOOR_FLAG) #define IsFree(tile) ((tile)->flags & TILE_FREE_FLAG) static obj_t ObjectList[MAX_WORLD_OBJECTS]; static tile_t TileList[MAX_WORLD_TILES]; static mesh_t MeshList[MAX_ONSCREEN_TILES]; static int ObjectCount = 0; static int TileCount = 0; static int MeshCount = 0; static float TileLength = 0.485898000000000f; // Euclidean static float TileAngle = 1.256637061435917f; // 2Pi/5 static float ProjectionScale; static float ProjectionMorph; static int CurrentFrame = 1; static float LimR; static mat3 MESH__M[16]; // Tile-to-tile traversal transformations static vec2 MESH__T[49]; // Texture coordinates static vec2 MESH__V[49]; // Untransformed tile vertices // ************************************************************************************** // ************************************************************************************** // *** Private Function Prototypes // ************************************************************************************** // ************************************************************************************** static tile_t *AddTile(tile_t *next); static int FindIndex(tile_t *to, tile_t *from); static void CurlLeft(tile_t *tile); static void CurlRight(tile_t *tile); static int IntersectCS(float r, vec2 &a, vec2 &b); static void DrawFloor(tile_t *tile, float height); static void DrawWall(tile_t *tile, int k, float height); static void DrawCorner(tile_t *tile, int k, float height); static void DrawObjects(tile_t *tile); static void DrawScene(obj_t *obj); static void VisitTile(tile_t *tile); static void PlaceObj(obj_t *obj, tile_t *tile); static void UpdateObj(obj_t *obj, mat3 &m); static int CollideObjNode(obj_t *obj); static int GetSwapSync(void); // ************************************************************************************** // ************************************************************************************** // *** Functions For Generating Tiling Topology // ************************************************************************************** // ************************************************************************************** static tile_t *AddTile(tile_t *next) { tile_t *tile = &TileList[TileCount++]; tile->frame_rendered = 0; tile->frame_visited = 0; tile->next[0] = next; tile->next[1] = NULL; tile->next[2] = NULL; tile->next[3] = NULL; tile->obj = NULL; SetWall(tile, 0); SetWall(tile, 1); SetWall(tile, 2); SetWall(tile, 3); SetFloor(tile); SetFree(tile); return tile; } static int FindIndex(tile_t *to, tile_t *from) { if(from->next[0] == to) return 0; if(from->next[1] == to) return 1; if(from->next[2] == to) return 2; if(from->next[3] == to) return 3; return -1; } static void CurlLeft(tile_t *tile) { tile_t *save = tile; int i = 0, count = 1; while(tile->next[i]) { tile_t *next = tile->next[i]; i = (FindIndex(tile, next) + 1)&3; tile = next; count++; } if(count >= 5) { tile->next[i] = save; save->next[3] = tile; } } static void CurlRight(tile_t *tile) { tile_t *save = tile; int i = 0, count = 1; while(tile->next[i]) { tile_t *next = tile->next[i]; i = (FindIndex(tile, next) - 1)&3; tile = next; count++; } if(count >= 5) { tile->next[i] = save; save->next[1] = tile; } } static int IntersectCS(float r, vec2 &a, vec2 &b) { // ********************************************** // Returns 1 if circle and line segment intersect // ********************************************** float tmp1, tmp2; vec2 n; r*=r; if(a*a < r || b*b < r) return 1; n = vec2(a.y - b.y, b.x - a.x); tmp1 = a*n; if(tmp1*tmp1 >= (n*n)*r) return 0; tmp1 = a.x*n.y - a.y*n.x; tmp2 = b.x*n.y - b.y*n.x; return (tmp1 > 0.f) != (tmp2 > 0.f); } static vec2 HProject(vec2 &v) { float q = ProjectionMorph * (float)sqrt(1.f - v*v); return v * ProjectionScale / (1.f + q); } static void UpdateMesh(mesh_t *mesh) { #define UpdateMeshVert(i, table) \ v[table[i]] = HProject((mesh->m*MESH__V[table[i]])) #define CopyMeshVert(i, j, table) \ v[table[i]] = next->mesh->v[table[j]] tile_t *tile = mesh->tile; vec2 *v = mesh->v; static char outer_edge_table[] = {1,2,3,4,5,13,20,27,34,41,47, 46,45,44,43,35,28,21,14,7}; static char inner_edge_table[] = {9,10,11,19,26,33,39,38,37, 29,22,15}; static char outer_corner_table[] = {0,6,48,42}; static char inner_corner_table[] = {8,12,40,36}; static char inner_vert_table[] = {16,17,18,23,24,25,30,31,32}; int i, k, k1, k2; for(i = 0; i < 9; i++) { UpdateMeshVert(i, inner_vert_table); } for(k = 0; k < 4; k++) { tile_t *next = tile->next[k]; // **************************** // Update/copy OUTER EDGE verts // **************************** if(next && next->frame_rendered == CurrentFrame) { k1 = 5*k; k2 = 5*FindIndex(tile, next) + 4; for(i = 0; i < 5; i++) { CopyMeshVert(k1 + i, k2 - i, outer_edge_table); } } else { k1 = 5*k; for(i = 1; i < 4; i++) { UpdateMeshVert(k1 + i, outer_edge_table); } if(IsCorner(tile, k) || (IsWall(tile, (k-1)&3) && !IsWall(tile, k))) { UpdateMeshVert(k1, outer_edge_table); } if(IsCorner(tile, (k+1)&3) || (IsWall(tile, (k+1)&3) && !IsWall(tile, k))) { UpdateMeshVert(k1 + 4, outer_edge_table); } } // ****************************** // Update/copy OUTER CORNER verts // ****************************** if(next && next->frame_rendered == CurrentFrame) { k2 = (FindIndex(tile, next) + 1)&3; CopyMeshVert(k, k2, outer_corner_table); } else { next = tile->next[(k-1)&3]; if(next && next->frame_rendered == CurrentFrame) { k2 = FindIndex(tile, next); CopyMeshVert(k, k2, outer_corner_table); } else { UpdateMeshVert(k, outer_corner_table); } } // *********************** // Update INNER EDGE verts // *********************** k1 = 3*k; if(IsWall(tile, k)) { for(i = 0; i < 3; i++) { UpdateMeshVert(k1 + i, inner_edge_table); } } // ************************* // Update INNER CORNER verts // ************************* if(IsWall(tile, k) && IsWall(tile, (k-1)&3)) { UpdateMeshVert(k, inner_corner_table); } } #undef UpdateMeshVert #undef CopyMeshVert } static void DrawFloor(tile_t *tile, float height) { mesh_t *mesh = tile->mesh; int i, j; if(height == 1.f) glBindTexture(GL_TEXTURE_2D, MAIN__texid[FLOOR_TEX_ID]); else glBindTexture(GL_TEXTURE_2D, MAIN__texid[CEIL_TEX_ID]); // ************ // Compute fade // ************ // mesh->color = vec3(.5f, .5f, .5f); mesh->color = vec3(.0f, .0f, .0f); if(height == 1.f) { float fade; if(tile->frame_visited < 1) { fade = 0.f; } else { int frames = CurrentFrame - tile->frame_visited; if(frames > 120) fade = .166f; else fade = .166f + .633f*(float)(120-frames)/120.f; } mesh->color = vec3(fade, fade, fade); } // *************************** // Adjust tri-strip parameters // *************************** int index_i[5] = {0, 2, 3, 4, 6}; int index_j[5] = {0, 14, 21, 28, 42}; int index_n[4] = {0, 1, 2, 3}; int count_n[4] = {10, 10, 10, 10}; if(IsWall (tile, 0)) index_j[0] += 7; if(IsWall (tile, 2)) index_j[4] -= 7; if(IsWall (tile, 3)) index_i[0] += 1; if(IsWall (tile, 1)) index_i[4] -= 1; if(IsCorner(tile, 0)) count_n[0] -= 2, index_n[0] += 2; if(IsCorner(tile, 1)) count_n[0] -= 2; if(IsCorner(tile, 3)) count_n[3] -= 2, index_n[3] += 2; if(IsCorner(tile, 2)) count_n[3] -= 2; // ***************** // Render tri-strips // ***************** vertex_t v[13]; vec2 *v_src = mesh->v + index_j[0]; vec2 *t_src = MESH__T + index_j[0]; for(i = 0; i < 13; i++) { v[i].c = mesh->color; } for(i = 0; i < 5; i++) { int idx = index_i[i]; v[2*i].v = v_src[idx]; v[2*i].t = t_src[idx]; v[2*i].v.z = height; } for(j = 1; j < 5; j++) { v_src = mesh->v + index_j[j]; t_src = MESH__T + index_j[j]; for(i = 0; i < 5; i++) { int idx = index_i[i]; v[2*i+j].v = v_src[idx]; v[2*i+j].t = t_src[idx]; v[2*i+j].v.z = height; } RenderTriStrip(v + index_n[j-1], count_n[j-1]); } // ********************** // Render corner polygons // ********************** static int corner_index_table[] = { 16, 2, 14, 1, 7, 18, 20, 4, 13, 5, 32, 46, 34, 47, 41, 30, 28, 44, 35, 43}; for(j = 0; j < 4; j++) { if(!IsCorner(tile, j)) continue; int *corner_index = corner_index_table + 5*j; for(i = 0; i < 5; i++) { int idx = corner_index[i]; v[i].v = mesh->v[idx]; v[i].t = MESH__T[idx]; v[i].v.z = height; } RenderTriStrip(v, 5); } } static void DrawWall(tile_t *tile, int k, float height) { mesh_t *mesh = tile->mesh; int i; glBindTexture(GL_TEXTURE_2D, MAIN__texid[WALL_TEX_ID]); // if(!IntersectCS(LimR, tc->vin[k], tc->vin[k+4]) && // !IntersectCS(LimR, tc->v[k], tc->v[(k+1)&3]) ) // { // return; // } static char outer_index_table[] = { 0,2,3,4,6,20,27,34,48,46,45,44,42,28,21,14,0}; static char inner_index_table[] = { 7,9,10,11,13,5,19,26,33,47,41,39,38,37,35,43,29,22,15,1}; static char index_adjust_table[] = { 8,12,40,36,8}; static float texcoord_table[] = { 0.f, .2500f, .5000f, .7500f, 1.f, 0.f, .2857f, .5714f, .8571f, 1.f, 0.f, .1429f, .4286f, .7143f, 1.f, 0.f, .1666f, .5000f, .8333f, 1.f}; vertex_t v[10]; char *outer_index = outer_index_table + k*4; char inner_index[5]; float *texcoord = texcoord_table; memcpy(inner_index, inner_index_table + k*5, 5); if(IsWall(tile, (k-1)&3)) { inner_index[0] = index_adjust_table[k]; texcoord += 10; } if(IsWall(tile, (k+1)&3)) { inner_index[4] = index_adjust_table[k+1]; texcoord += 5; } for(i = 0; i < 5; i++) { vertex_t *vrt = v + 2*i; vrt->v = mesh->v[outer_index[i]]; vrt->t = vec2(0.f, texcoord_table[i]*2.f); vrt->c = vec3(.5f, .5f, .5f); vrt->v.z = height; } for(i = 0; i < 5; i++) { vertex_t *vrt = v + 2*i + 1; vrt->v = mesh->v[inner_index[i]]; vrt->t = vec2(.66f, texcoord[i]*2.f); vrt->c = mesh->color; } RenderTriStrip(v, 10); } static void DrawCorner(tile_t *tile, int k, float height) { mesh_t *mesh = tile->mesh; glBindTexture(GL_TEXTURE_2D, MAIN__texid[CORNER_TEX_ID]); vertex_t v[3]; static int corner_index_table[12] = {0,7,1,6,5,13,48,41,47,42,43,35}; int *corner_index = corner_index_table + 3*k; v[0].v = mesh->v[corner_index[0]]; v[1].v = mesh->v[corner_index[1]]; v[2].v = mesh->v[corner_index[2]]; v[0].t = vec2(0.f, 0.f); v[1].t = vec2(.66f, 0.f); v[2].t = vec2(.25f, .66f); v[0].c = vec3(.5f, .5f, .5f); v[1].c = mesh->color; v[2].c = mesh->color; v[0].v.z = height; RenderPoly(v, 3); } static void DrawObjects(tile_t *tile) { obj_t *obj = tile->obj; int i; // glBindTexture(GL_TEXTURE_2D, MAIN__texid[2]); glDisable(GL_TEXTURE_2D); while(obj) { vertex_t v[18]; // MAX(obj->verts) = 16 mat3 m; float theta, dt; if(obj->flags & OBJ_FLAG_GHOST) { obj = obj->next; continue; } // ************* // Expand radius // ************* if(obj->r < obj->r_max) { obj->r += .005f; if(obj->r > obj->r_max) { obj->r = obj->r_max; } } // *********** // Draw object // *********** m = tile->mesh->m * obj->m_inv; theta = 0.f; dt = 6.2831853f / (float)obj->verts; v[0].v = HProject(vec2(m.x.z, m.y.z) / m.z.z); v[0].c = vec3(1.f, 1.f, 1.f); v[0].v.z = .9f; for(i = 0; i < obj->verts; i++, theta += dt) { float s = (float)sin(theta); float c = (float)cos(theta); vec2 tmp = m * (vec2(c, s) * obj->r); s = (1.f + s) * .5f; c = (1.f - s); v[i+1].v = HProject(tmp); v[i+1].c = obj->color1*s + obj->color2*c; } v[i+1] = v[1]; // 3Dfx Glide //grCullMode(GR_CULL_NEGATIVE); RenderTriFan(v, i+2); // *********** // Next object // *********** obj = obj->next; } glEnable(GL_TEXTURE_2D); } static void VisitTile(tile_t *tile) { mesh_t *mesh = tile->mesh; int k; tile->frame_rendered = CurrentFrame; // ************************ // Compute outside vertices // ************************ // POTENTIAL BUG: Backface culling uses v_outer - since v_outer // is not shared between tiles, traversal may fail in rare cases vec2 v[4]; v[0] = mesh->m*MESH__V[0]; v[1] = mesh->m*MESH__V[6]; v[2] = mesh->m*MESH__V[48]; v[3] = mesh->m*MESH__V[42]; for(k = 0; k < 4; k++) { // *************************************** // Reject if out-of-view, or already drawn // *************************************** tile_t *next = tile->next[k]; if(!next || next->frame_rendered == CurrentFrame) continue; if(!IntersectCS(LimR, v[k], v[(k+1)&3])) continue; // **************************** // Reject if backward traversal // **************************** #if BACKFACE_REJECT vec2 n(v[(k+1)&3].y - v[k].y, v[k].x - v[(k+1)&3].x); float t = n*v[k]; if(t > 0.f || (t == 0.f && tile > next)) continue; #endif // **************** // Update next mesh // **************** mesh_t *mesh2 = next->mesh = &MeshList[MeshCount++]; int i = (FindIndex(tile, next) - k + 2)&3; mesh2->m = mesh->m*MESH__M[4*i + k]; mesh2->tile = next; UpdateMesh(mesh2); // *************************** // Recurse to neighboring tile // *************************** VisitTile(next); } } static void PlaceObj(obj_t *obj, tile_t *tile) { obj->next = tile->obj; obj->tile = tile; tile->obj = obj; } static void UpdateObj(obj_t *obj, mat3 &m) { if(obj->flags & OBJ_FLAG_MOVING) { obj->m = mat3::horthogonalized(m); while(CollideObjNode(obj)); obj->m_inv = obj->m.inverse(); } } static int CollideObjNode(obj_t *obj) { // ******************************** // Returns 1 if changed - should be // called repeatedly until return 0 // ******************************** static char outer_index_table[] = {0, 6, 48, 42}; static char inner_index_table[] = {7, 5, 41, 43, 13, 47, 35, 1}; int k; if(~obj->flags & OBJ_FLAG_GHOST) { // ****************** // Collide with walls // ****************** for(k = 0; k < 4; k++) { if(!IsWall(obj->tile, k)) continue; vec2 a = obj->m*MESH__V[inner_index_table[k]]; vec2 b = obj->m*MESH__V[inner_index_table[k+4]]; vec2 n(b.y - a.y, a.x - b.x); float d = n*a; if(d*d < (n*n)*(obj->r*obj->r)) { d /= n.len(); vec2 a2 = a + n*(obj->r + d); vec2 b2 = b + n*(obj->r + d); obj->m = mat3::htransline(a2, b2, a, b)*obj->m; return 1; } } // ******************** // Collide with corners // ******************** for(k = 0; k < 4; k++) { if(!IsCorner(obj->tile, k)) continue; vec2 a = obj->m*MESH__V[inner_index_table[k]]; vec2 b = obj->m*MESH__V[inner_index_table[((k-1)&3)+4]]; vec2 n(b.y - a.y, a.x - b.x); float d = n*a; if(IntersectCS(obj->r, a, b)) { d /= n.len(); vec2 a2 = a + n*(obj->r + d); vec2 b2 = b + n*(obj->r + d); obj->m = mat3::htransline(a2, b2, a, b)*obj->m; return 1; } } } // ********************** // Traverse between tiles // ********************** for(k = 0; k < 4; k++) { if(obj->flags & OBJ_FLAG_GHOST) { if(IsWall(obj->tile, k)) continue; } vec2 a = obj->m*MESH__V[outer_index_table[k]]; vec2 b = obj->m*MESH__V[outer_index_table[(k+1)&3]]; if(a.x*b.y > a.y*b.x) { tile_t *next = obj->tile->next[k]; if(!next) continue; // ****************** // Update linked list // ****************** if(obj->tile->obj == obj) { obj->tile->obj = obj->next; } else { obj_t *o2; for(o2 = obj->tile->obj; o2; o2 = o2->next) { if(o2->next == obj) break; } o2->next = obj->next; } obj->next = next->obj; next->obj = obj; // **************** // Update transform // **************** int i = (FindIndex(obj->tile, next) - k + 2)&3; obj->m = obj->m*MESH__M[4*i + k]; obj->tile = next; return 1; } } return 0; } /* 3Dfx Glide static int GetSwapSync(void) { static long *swap_history = NULL; static long num_entires; #if RENDER if(!swap_history) { grGet(GR_NUM_SWAP_HISTORY_BUFFER, 4, &num_entires); swap_history = (long*)malloc(sizeof(long) * num_entires); // test swap_history != NULL } grGet(GR_SWAP_HISTORY, 4*num_entires, swap_history); return swap_history[0] + 1; #else return 1; #endif } */ static int cmpfn(const void *a, const void *b) { mesh_t *mesh_a = *((mesh_t**)a); mesh_t *mesh_b = *((mesh_t**)b); float dist_a = mesh_a->v[24]*mesh_a->v[24]; float dist_b = mesh_b->v[24]*mesh_b->v[24]; if(dist_a < dist_b) return +1; else if(dist_a > dist_b) return -1; else return 0; } static void DrawScene(obj_t *obj) { mesh_t *mesh; mesh_t *tmp_meshlist[MAX_ONSCREEN_TILES]; int i, k; mesh = obj->tile->mesh = &MeshList[0]; mesh->m = obj->m; mesh->tile = obj->tile; UpdateMesh(mesh); MeshCount = 1; VisitTile(obj->tile); // recursively visit tiles for(i = 0; i < MeshCount; i++) { tmp_meshlist[i] = &MeshList[i]; } qsort(tmp_meshlist, MeshCount, sizeof(mesh_t*), cmpfn); // ******* // Layer 1 // ******* for(i = 0; i < MeshCount; i++) { tile_t *tile = tmp_meshlist[i]->tile; if(IsFloor(tile)) { DrawFloor(tile, 1.f); } } // ******* // Layer 2 // ******* for(i = 0; i < MeshCount; i++) { tile_t *tile = tmp_meshlist[i]->tile; if(IsFloor(tile)) { for(k = 0; k < 4; k++) { if(IsWall(tile, k)) { DrawWall(tile, k, .85f); } if(IsCorner(tile, k)) { DrawCorner(tile, k, .85f); } } DrawObjects(tile); } } // ******* // Layer 3 // ******* for(i = 0; i < MeshCount; i++) { tile_t *tile = tmp_meshlist[i]->tile; if(!IsFloor(tile)) { DrawFloor(tile, .85f); } } } // ************************************************************************************** // ************************************************************************************** // *** Private Initialization Functions // ************************************************************************************** // ************************************************************************************** static void SubdivideEdge(vec2 v[], int skip) { v[skip*3] = vec2::hmidpoint(v[0], v[skip*6]); v[skip*2] = vec2::hmidpoint(v[0], v[skip*3]); v[skip*1] = vec2::hmidpoint(v[0], v[skip*2]); v[skip*4] = vec2::hmidpoint(v[skip*6], v[skip*3]); v[skip*5] = vec2::hmidpoint(v[skip*6], v[skip*4]); } static void CalcMTV(mat3 m[16], vec2 t[49], vec2 v[49]) { int i, j; // ***************************************** // Compute matrices used in tiling traversal // ***************************************** float x1 = TileLength*2.f; float x2 = TileLength*TileLength; m[0] = mat3(1.f+x2, 0.f, -x1, 0.f, 1.f-x2, 0.f, -x1, 0.f, 1.f+x2); m[1] = mat3(1.f-x2, 0.f, 0.f, 0.f, 1.f+x2, +x1, 0.f, +x1, 1.f+x2); m[2] = mat3(1.f+x2, 0.f, +x1, 0.f, 1.f-x2, 0.f, +x1, 0.f, 1.f+x2); m[3] = mat3(1.f-x2, 0.f, 0.f, 0.f, 1.f+x2, -x1, 0.f, -x1, 1.f+x2); for(j = 0; j < 12; j += 4) { for(i = 0; i < 4; i++) { m[i+j+4] = mat3(m[i+j].x.y, -m[i+j].x.x, m[i+j].x.z, m[i+j].y.y, -m[i+j].y.x, m[i+j].y.z, m[i+j].z.y, -m[i+j].z.x, m[i+j].z.z); } } // ********************** // Compute texture coords // ********************** static float tcomp[7] = {0.f, .125f, .25f, .5f, .75f, .875f, 1.f}; for(j = 0; j < 7; j++) { for(i = 0; i < 7; i++) { t[7*j+i] = vec2(tcomp[i], tcomp[j]); } } // *********************************** // Compute untransformed tile vertices // *********************************** // // 6--13--20------27------34--41--48 // | | | | | | | // 5--12--19------26------33--40--47 // | | | | | | | // 4--11--18------25------32--39--46 // | | | | | | | // | | | | | | | // | | | | | | | // | | | | | | | // 3--10--17------24------31--38--45 // | | | | | | | // | | | | | | | // | | | | | | | // | | | | | | | // 2---9--16------23------30--37--44 // | | | | | | | // 1---8--15------22------29--36--43 // | | | | | | | // 0---7--14------21------28--35--42 v[0] = vec2(-TileLength, -TileLength); v[6] = vec2(-TileLength, +TileLength); v[42] = vec2(+TileLength, -TileLength); v[48] = vec2(+TileLength, +TileLength); SubdivideEdge(v+0, 7); SubdivideEdge(v+6, 7); SubdivideEdge(v+0, 1); SubdivideEdge(v+42, 1); for(i = 7; i < 42; i += 7) { SubdivideEdge(v + i, 1); } } // ************************************************************************************** // ************************************************************************************** // *** Public Functions // ************************************************************************************** // ************************************************************************************** static int IsNeighborFree(tile_t *tile) { int k; for(k = 0; k < 4; k++) { tile_t *next = tile->next[k]; if(next && IsFree(next)) return 1; } return 0; } void HyperTile_Init(int size) { int i, k; CalcMTV(MESH__M, MESH__T, MESH__V); // *************** // Generate tiling // *************** int total; AddTile(NULL); for(i = total = 1; i < size+4; i++) { int j, count = TileCount; for(j = 0; j < count; j++) { tile_t *tile = &TileList[j]; for(k = 0; k < 4; k++) { if(!tile->next[k]) { tile_t *next = AddTile(tile); tile->next[k] = next; CurlLeft(next); CurlRight(next); // total++; if(i >= size) ClearFree(next); else total++; } } } } // ************* // Generate maze // ************* int count; int max = total / 2; tile_t *tile, *next, *path[1000]; int pathlen = 0; int pathcount; tile = &TileList[0]; ClearFree(tile); for(count = 1; count < max;) { // ************************************************ // Find a visited tile with a non-visited neighbor: // First, try to branch off previous path // ************************************************ // ************************************** // If branch fails, find some other point // ************************************** do { static int j = 0; do { j++; if(j == total) j = 0; tile = &TileList[j]; } while(IsFree(tile)); } while(!IsNeighborFree(tile)); // ************** // Construct path // ************** pathlen = 0; pathcount = rand() % 128 + 1; for(; count < max && pathlen < pathcount; count++) { if(rand() % 20 == 0) i++; // change direction for(k = 0; k < 4; k++) { next = tile->next[(i+k)&3]; if(next && IsFree(next)) break; } if(k == 4) break; // end of path i = (i+k)&3; path[pathlen++] = next; ClearWall(tile, i); i = FindIndex(tile, next); ClearWall(next, i); ClearFree(next); tile = next; i = (i+2)&3; } } // ****************************** // Remove "dangling" border tiles // ****************************** int removed = 0; if(1) for(i = 0; i < TileCount; i++) { tile = &TileList[i]; int b = 0; for(k = 0; k < 4; k++) { if(!tile->next[k]) b++; else next = tile->next[k]; } if(b == 3) { SetFree(tile); b = FindIndex(tile, next); next->next[b] = NULL; SetWall(next, b); removed++; } } // *********** // Count walls // *********** int wallcount = 0; for(i = 0; i < TileCount; i++) { tile = &TileList[i]; if(IsFree(tile)) continue; for(k = 0; k < 4; k++) { if(tile->next[k] && IsWall(tile, k)) { wallcount++; } } } wallcount /= 2; // **************************************** // Remove some more walls to make it harder // **************************************** if(1) for(i = 0; i < 1; i++) { do { do { tile = &TileList[rand() % TileCount]; } while(IsFree(tile)); for(k = 0; k < 4; k++) { next = tile->next[k]; if(next && IsWall(tile, k)) break; } } while(k == 4); ClearWall(tile, k); ClearWall(next, FindIndex(tile, next)); } // **************** // Set corner flags // **************** for(i = 0; i < TileCount; i++) { tile = &TileList[i]; if(IsFree(tile)) continue; for(k = 0; k < 4; k++) { if(!IsWall(tile, k) && !IsWall(tile, (k-1)&3)) { tile_t *tile2 = tile; int k2 = k; do { if(IsWall(tile2, k2)) { SetCorner(tile, k); break; } next = tile2->next[k2]; k2 = (FindIndex(tile2, next) + 1)&3; tile2 = next; } while(tile2 != tile); } } } // ************************ // Set non-floor tile flags // ************************ removed = 0; if(1) for(i = 0; i < TileCount; i++) { tile = &TileList[i]; if(IsWall(tile, 0) && IsWall(tile, 1) && IsWall(tile, 2) && IsWall(tile, 3) ) { ClearWall(tile, 0); ClearWall(tile, 1); ClearWall(tile, 2); ClearWall(tile, 3); ClearFloor(tile); removed++; } } TileCount -= removed; } /* long HyperTile_InitHW(long window) { // ***************** // Create a fog mask // ***************** short *fogmask; int x, y; int area = SCREEN_RES_X*SCREEN_RES_Y; fogmask = (short*)malloc(sizeof(short)*area); for(y = 0; y < SCREEN_RES_Y; y++) { for(x = 0; x < SCREEN_RES_X; x++) { vec2 v = vec2((float)(x-SCREEN_RES_X/2), (float)(y-SCREEN_RES_Y/2)); v /= (float)(SCREEN_RES_Y/2); float fog = 1.f - (float)pow(v*v, 3.f); short fogi = (short)(fog*255.f); if(fogi < 0) fogi = 0; if(fogi > 255) fogi = 255; // fogi = 255; // no fog if(v*v > 1.f) fogi = 0; fogmask[x + y*SCREEN_RES_X] = fogi; } } // ************************************** // Initialize 3Dfx Glide rendering system // ************************************** long context = 1; #if RENDER grGlideInit(); grSstSelect(0); context = (long)grSstWinOpen( window, GR_RESOLUTION_800x600, GR_REFRESH_60Hz, GR_COLORFORMAT_RGBA, GR_ORIGIN_LOWER_LEFT, 2, 1); if(!context) return 0; // ************************************* // Configure Glide to receive alpha mask // ************************************* grCoordinateSpace(GR_WINDOW_COORDS); grViewport(0, 0, SCREEN_RES_X, SCREEN_RES_Y); grVertexLayout(GR_PARAM_XY, 0, GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_W, 8, GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_A, 12, GR_PARAM_ENABLE); grDepthBufferMode(GR_DEPTHBUFFER_DISABLE); grDepthMask(FXFALSE); grColorMask(FXTRUE, FXTRUE); grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaBlendFunction( GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO); // ***************************** // Copy fog mask to alpha buffer // ***************************** for(y = 0; y < SCREEN_RES_Y; y++) { for(x = 0; x < SCREEN_RES_X; x++) { struct vtmp_t { float x, y, z, a; }; vtmp_t v; v.x = (float)x; v.y = (float)y; v.z = 1.f; v.a = (float)fogmask[x + y*SCREEN_RES_X]; RenderPoint(&v); } } // ***************************** // Configure Glide for rendering // ***************************** grCoordinateSpace(GR_CLIP_COORDS); grVertexLayout(GR_PARAM_A, -1, GR_PARAM_DISABLE); grVertexLayout(GR_PARAM_RGB, 12, GR_PARAM_ENABLE); grVertexLayout(GR_PARAM_ST0, 24, GR_PARAM_ENABLE); grViewport( (SCREEN_RES_X-SCREEN_RES_Y)/2, 0, SCREEN_RES_Y,SCREEN_RES_Y); grTexClampMode( GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP); grTexFilterMode( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); grTexMipMapMode( GR_TMU0, GR_MIPMAP_NEAREST_DITHER, FXFALSE); grEnable(GR_ALLOW_MIPMAP_DITHER); // slow, but we'll use it for now grTexCombine( GR_TMU0, GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE); grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_LOCAL, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); grAlphaBlendFunction( GR_BLEND_DST_ALPHA, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); grColorMask(FXTRUE, FXFALSE); Render_LoadTexture("STONE01.3df"); #endif return (long)context; } */ void HyperTile_Draw(mat3 &m, float scale, float morph, int drop) { static obj_t player; static obj_t ghost; static int inited = 1; // ******************* // Place player object // ******************* if(inited) { inited = 0; player.flags = OBJ_FLAG_PLAYER | OBJ_FLAG_MOVING | OBJ_FLAG_CAMERA; player.m.identity(); player.m_inv = player.m; player.r = .2f; player.r_max = .2f; player.next = NULL; player.color1 = vec3(0.f, 1.f, 0.f); player.color2 = vec3(0.f, 0.f, 1.f); player.verts = 16; ghost = player; ghost.flags = OBJ_FLAG_GHOST | OBJ_FLAG_MOVING | OBJ_FLAG_CAMERA; PlaceObj(&player, TileList); PlaceObj(&ghost, TileList); } // *************************** // Place dropped object marker // *************************** if(drop && ObjectCount < MAX_WORLD_OBJECTS) { obj_t *obj = &ObjectList[ObjectCount++]; obj->flags = 0; obj->m = player.m; obj->m_inv = player.m_inv; obj->r = 0.f; obj->r_max = vec3::random().x * .1f + .1f; obj->next = NULL; obj->color1 = vec3::random().normalized() * .5f; obj->color2 = vec3::random().normalized(); obj->verts = (rand() % 5) + 3; PlaceObj(obj, player.tile); } // ********************************* // Update scaling and visible radius // ********************************* float q = scale*scale + morph*morph; ProjectionScale = scale; ProjectionMorph = morph; LimR = (scale + morph*(float)sqrt(q - 1.f)) / q; // *********************************** // Update player transform and physics // *********************************** // NOTE: Updating player object initializes the first // tile for rendering. No subsequent objects should be // updated between updating the player and drawing // the tiling. if(player.tile->frame_visited < 1) { player.tile->frame_visited = CurrentFrame; TILES_HIT++; } // ******************* // Draw "outside area" // ******************* if(0) { vertex_t v[4]; v[0].v = vec2(-1.f, -1.f); v[1].v = vec2(+1.f, -1.f); v[2].v = vec2(+1.f, +1.f); v[3].v = vec2(-1.f, +1.f); v[0].c = v[1].c = v[2].c = v[3].c = vec3(.7f, 1.f, .2f); #if RENDER /* 3Dfx Glide grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); */ #endif RenderPoly(v, 4); } // ********************** // Draw tiles and objects // ********************** CurrentFrame++; #if RENDER /* 3Dfx Glide grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_TEXTURE, FXFALSE); */ float tec[] = {1.f, 1.f, 1.f, 1.f}; glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, tec); #endif DrawScene(&ghost); // 3Dfx Glide //int sync = GetSwapSync(); int sync = 1; while(sync--) { UpdateObj(&player, m*player.m); #if 1 if(player.tile == ghost.tile) // if(1) { mat3 target = ghost.tile->mesh->m * player.tile->mesh->m.inverse() * player.m; target /= target.z.z; ghost.m /= ghost.m.z.z; UpdateObj(&ghost, ghost.m*.95f + target*.05f); } else { vec2 target = player.m_inv * vec2(0.f, 0.f); target = player.tile->mesh->m * target; target *= -.05f; UpdateObj(&ghost, mat3::htranslate(target)*ghost.m); // float theta1, theta2; // vec2 trans1, trans2; // mat3::hdecompose(theta1, trans1, ghost.m); // mat3::hdecompose(theta2, trans2, player.m); // theta1 = .98f*theta1 + .02f*theta2; // trans1 = trans1*.98f + trans2*.02f; // UpdateObj(&ghost, mat3::htranslate(trans1)*mat3::rotZ(theta1)); } #else ghost.m = player.m; ghost.tile = player.tile; #endif } // Draw FOG MASK (OpenGL) if(1) { glDisable(GL_DEPTH_TEST); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(1.f, 1.f, 1.f); glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_COLOR); glBindTexture(GL_TEXTURE_2D, MAIN__texid[0]); glBegin(GL_POLYGON); glTexCoord2f(-.15f, -.15f); glVertex3f(-1.f, -1.f, 0.4f); glTexCoord2f(1.15f, -.15f); glVertex3f( 1.f, -1.f, 0.4f); glTexCoord2f(1.15f, 1.15f); glVertex3f( 1.f, 1.f, 0.4f); glTexCoord2f(-.15f, 1.15f); glVertex3f(-1.f, 1.f, 0.4f); glEnd(); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); } // ***************** // Draw progress bar // ***************** if(1) { vertex_t v[4]; v[0].v = vec3(-1.f, -.94f,1.1f); v[1].v = vec3(+1.f, -.94f,1.1f); v[2].v = vec3(+1.f, -1.f, 1.1f); v[3].v = vec3(-1.f, -1.f, 1.1f); v[0].c = v[1].c = v[2].c = v[3].c = vec3(0.f, 0.f, .5f); #if RENDER /* 3Dfx Glide grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE); */ #endif glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); RenderPoly(v, 4); if(TileCount-2 == TILES_HIT) { v[0].c = v[1].c = v[2].c = v[3].c = vec3::random(); } else { v[0].c = v[1].c = v[2].c = v[3].c = vec3(0.f, 0.f, 1.f); } v[1].v.x = v[2].v.x = -1.f + 2.f*(float)TILES_HIT/(float)(TileCount-2); RenderPoly(v, 4); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); #if RENDER /* 3Dfx Glide grAlphaBlendFunction( GR_BLEND_DST_ALPHA, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO); */ #endif } #if RENDER /* 3Dfx Glide grBufferSwap(1); */ #endif } // ************************************************************************************** // ************************************************************************************** // *** Main Program and GLUT Stuff // ************************************************************************************** // ************************************************************************************** static void GLUT__Display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); MAIN__RenderScene(); MAIN__TrackFPS(); { static vec2 vel(0.f, 0.f); static float scale = 1.4f; // 1.4 = 33tiles, 1.2 = 54tiles, 1.1 = 105tiles static float morph = 1.0f; static float maxvl = .0650f; static float accel = .0030f; static int drop_counter = 0; int drop = 0; if(GetAsyncKeyState(VK_SPACE) & 0x8000) { if(drop_counter > 15) { drop = 1; drop_counter = 0; } } drop_counter++; float m_old = morph; vel *= .9f; if(GetAsyncKeyState(VK_NUMPAD4) & 0x8000) vel.x += accel; if(GetAsyncKeyState(VK_NUMPAD6) & 0x8000) vel.x -= accel; if(GetAsyncKeyState(VK_NUMPAD2) & 0x8000) vel.y += accel; if(GetAsyncKeyState(VK_NUMPAD8) & 0x8000) vel.y -= accel; if(GetAsyncKeyState(VK_UP) & 0x8000) scale += .01f; if(GetAsyncKeyState(VK_DOWN) & 0x8000) scale -= .01f; if(GetAsyncKeyState(VK_LEFT) & 0x8000) morph += .01f; if(GetAsyncKeyState(VK_RIGHT) & 0x8000) morph -= .01f; if(morph < 0.00f) morph = 0.00f; if(morph > 1.00f) morph = 1.00f; if(morph != m_old) { scale *= 1.f + morph*(float)sqrt(.75f); scale /= 1.f + m_old*(float)sqrt(.75f); } if(scale < 1.02f) scale = 1.02f; if(scale > 2.00f) scale = 2.00f; if(vel.len() > maxvl) vel *= maxvl / vel.len(); HyperTile_Draw(mat3::htranslate(vel), scale, morph, drop); } glFlush(); glutSwapBuffers(); } static void GLUT__Reshape(int width, int height) { int offset_x = 0; int offset_y = 0; if(width > height) { offset_x = (width - height)/2; width = height; } else { offset_y = (height - width)/2; height = width; } // float aspect = (float)height / (float)width; float aspect = 1.0f; glViewport(offset_x, offset_y, width, height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef(1.f, 1.f, -1.f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.f, 1.f/aspect, .001f, 100.f); glTranslatef(0.f, 0.f, -1.f); } static void GLUT__Keyboard(unsigned char key, int x, int y) { if(key == 27) MAIN__STOP = 1; // ESC } static void GLUT__Mouse(int button, int state, int x, int y) { } static void GLUT__Idle(void) { if(WAIT_FOR_CLOCK) Sleep(8); glutPostRedisplay(); } void main(int argc, char *argv[]) { fprintf(stdout, "HypEngine: Hyperbolic Maze Demo\n"); fprintf(stdout, "(c) Bernie Freidin, 1999-2000\n\n"); fprintf(stdout, "Keys:\n"); fprintf(stdout, " Numeric keypad to move (NumLock ON)\n"); fprintf(stdout, " Arrow keys to zoom in/out and adjust view\n"); fprintf(stdout, " SPACE to drop an object\n"); fprintf(stdout, " ESCAPE to quit\n\n"); fprintf(stdout, "Tips:\n"); fprintf(stdout, " Zoom in and adjust view RIGHT for faster framerate\n"); fprintf(stdout, " When maze is fully explored, status bar flashes\n"); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(640, 480); glutInitWindowPosition(40, 40); glutCreateWindow(argv[0]); glutDisplayFunc(GLUT__Display); glutReshapeFunc(GLUT__Reshape); glutKeyboardFunc(GLUT__Keyboard); glutMouseFunc(GLUT__Mouse); glutIdleFunc(GLUT__Idle); const unsigned char *ext = glGetString(GL_EXTENSIONS); glClearColor(0.f, 0.f, 0.f, 1.0f); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glGenTextures(MAIN__texcount, MAIN__texid); for(int i = 0; i < MAIN__texcount; i++) { glBindTexture(GL_TEXTURE_2D, MAIN__texid[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); if(i > 0) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); MAIN__LoadTGA(MAIN__texnames[i-1]); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); MAIN__LoadAlphaMask(512); } } HyperTile_Init(7); // 7 // 3Dfx Glide //context = HyperTile_InitHW((long)hwnd); //if(!context) return; glutMainLoop(); } /* COMPUTING "TileLength"... hdist[v1_,v2_] = (1-v1.v2)/Sqrt[(1-v1.v1)(1-v2.v2)]; p0 = {0,0}; p1 = a{1,0}; p2 = a{Cos[2Pi/5],Sin[2Pi/5]}; p3 = b{Cos[1Pi/5],Sin[1Pi/5]}; Solve[{ hdist[p0,p3] - hdist[p1,p2] == 0, hdist[p0,p1] - hdist[p1,p3] == 0}, {a, b}] :a is the Euclidean length along an edge :b is the Euclidean length along a diagonal (assuming the square's corner is resting at 0,0) */
This page © Bernie Freidin, 2000.