#ifdef GLEW #include #endif #include "mapviewer.h" #include #ifdef GLX #include "gui/glx.h" #else #include "gui/glut.h" #endif using namespace std; /* * GLView */ void CGLView::UpdateScene(int ms) { static int ClockTimer = 0;; if (Game.UseTime()) { ClockTimer += ms; if (ClockTimer >= Game.GetMinuteLength()) { Clock.AdvanceOneMinute(); ClockTimer = 0; } } Sky.UpdateSun(); Sky.UpdateLight(); } void CGLView::RenderScene() { if (ViewMode == 0) RenderMap(); else RenderClump(); } void CGLView::RenderClump() { int w, h; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); w = GLView.getWidth(); h = GLView.getHeight(); glLoadIdentity(); glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(Camera.GetFOV(), (GLfloat)w/(GLfloat)h, 1.0f, 200.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Camera.Look(); /* Render */ Viewer.Draw(); SwapBuffers(); } void CGLView::RenderMap() { int w, h; static int Frame = 0;; static int StartTime = clock(); int i; GLfloat FarClp; w = GLView.getWidth(); h = GLView.getHeight(); FarClp = Sky.GetFarClp(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Sky.Clear(); if (GLView.DoStereo()) { for (i = 0; i < 2; i++) { if (i == 0) glViewport(0, 0, (GLsizei)w/2, (GLsizei)h); else glViewport((GLsizei)w/2, 0, (GLsizei)w/2, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(Camera.GetFOV(), (GLfloat)w/2/(GLfloat)h, 1.0f, FarClp); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (i == 0) Camera.LookRightEye(); else Camera.LookLeftEye(); RenderMapViewport(); } } else { glLoadIdentity(); glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(Camera.GetFOV(), (GLfloat)w/(GLfloat)h, 1.0f, FarClp); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Camera.Look(); RenderMapViewport(); } SwapBuffers(); Frame++; if ((clock() - StartTime) >= CLOCKS_PER_SEC) { cout << Frame << " FPS\n"; Frame = 0; StartTime = clock(); } } void CGLView::RenderMapViewport() { int w, h; w = GLView.getWidth(); h = GLView.getHeight(); glBindTexture(GL_TEXTURE_2D, 0); glColor4ub(255, 255, 255, 255); glEnable(GL_LIGHTING); /* 3D Stuff */ Sky.SetLightModel(AMBIENT_ONLY); Sky.Draw(); Sky.DrawSunCorona(); glClear(GL_DEPTH_BUFFER_BIT); World.Draw(0); if ((Game.GetVersion() & GAMESANANDREAS) == 0) Water.Draw(); World.Draw(1); Sky.SetLightModel(AMBIENT_AND_DIFFUSE); glDisable(GL_LIGHTING); /* 2D Stuff */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, w, h, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); if ((Game.GetVersion() & GAMEIII) != 0 && GLView.UseTint()) Sky.DrawTint(); if (GLView.DoRadar() && ((Game.GetVersion() & GAMESANANDREAS) == 0)) DrawRadar(); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } void CGLView::DrawRadar() { int i, j, n; int bottom, top, left, right; int tilesize; int size; char TxdName[24]; char TexName[24]; GLfloat lim[4]; GLfloat Cpos[3]; GLfloat ang; GLfloat PositionRatio; GLfloat Distance; if (!GLView.UseTextures()) return; if (GLView.DoStereo()) return; Game.GetWorldLimits(lim); size = 128; size = getHeight() / 4; bottom = getHeight() - size/3; top = bottom - size; left = size/3; right = left + size; Camera.GetPosition(&Cpos[0], &Cpos[1], &Cpos[2]); Distance = size; glViewport(left, size/4, size, size); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, size, 0, size, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); /* Set up stencil */ glClearStencil(0); glEnable(GL_STENCIL_TEST); glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_NEVER, 0x0, 0x0); glStencilOp(GL_INCR, GL_INCR, GL_INCR); glColor3f(1.0f, 1.0f, 1.0f); glTranslatef(size/2, size/2, 0); glBegin(GL_TRIANGLES); for (ang = 0; ang < 2*M_PI; ang+=M_PI/16) { GLfloat r = size/2-4; glVertex2f(0, 0); glVertex2f(cos(ang)*r, sin(ang)*r); glVertex2f(cos(ang+M_PI/16)*r, sin(ang+M_PI/16)*r); } glEnd(); glTranslatef(-size/2, -size/2, 0); /* move back */ glStencilFunc(GL_EQUAL, 0x1, 0x1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); /* Draw map */ tilesize = size; PositionRatio = ((GLfloat)(lim[2] - lim[0])/sqrt((float) nRadarFiles)) / (GLfloat)tilesize; glPushMatrix(); glTranslatef(tilesize/2, tilesize/2, 0); glRotatef(-Camera.GetYaw()*180/M_PI, 0, 0, 1); glTranslatef(Cpos[1]/PositionRatio, -Cpos[0]/PositionRatio, 0); glTranslatef(-sqrt((float) nRadarFiles)*tilesize/2, -sqrt((float) nRadarFiles)*tilesize/2, 0); glEnable(GL_BLEND); glColor4f(1, 1, 1, 1); n = 0; for (i = 0; i < sqrt((float) nRadarFiles); i++) for (j = 0; j < sqrt((float) nRadarFiles); j++, n++) { sprintf(TxdName, "RADAR%02d", n); sprintf(TexName, "radar%02d", n); BindTextureFromTxd(TexName, TxdName); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBegin(GL_QUADS); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f); glVertex2f(i*tilesize, j*tilesize); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f); glVertex2f((i+1)*tilesize, j*tilesize); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f); glVertex2f((i+1)*tilesize, (j+1)*tilesize); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f); glVertex2f(i*tilesize, (j+1)*tilesize); glEnd(); } glPopMatrix(); glDisable(GL_STENCIL_TEST); /* Draw border */ BindTextureFromTxd("radardisc", "HUD"); glBegin(GL_POLYGON); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f); glVertex2f(0, size); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f); glVertex2f(size, size); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f); glVertex2f(size, 0); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f); glVertex2f(0, 0); glEnd(); /* Draw arrow */ glColor3f(1, 1, 1); glBindTexture(GL_TEXTURE_2D, 0); // BindTextureFromTxd("radar_center", "HUD"); glPushMatrix(); glTranslatef(size/2, size/2, 0); glBegin(GL_QUADS); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f); glVertex2f(-5, -5); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f); glVertex2f(-5, 5); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f); glVertex2f(5, 5); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f); glVertex2f(5, -5); glEnd(); glPopMatrix(); glDisable(GL_BLEND); } #pragma pack(push) #pragma pack(1) struct TgaHeader { unsigned char Offset; unsigned char ColorType; unsigned char ImageType; unsigned short PaletteStart; unsigned short PaletteLen; unsigned char PalBits; unsigned short XOrigin, YOrigin; unsigned short Width, Height; unsigned char BPP; unsigned char Orientation; }; #pragma pack(pop) void CGLView::MakeScreenshot() { int i; int width, height; GLubyte *data; FILE *tga; struct TgaHeader tgahdr; width = getWidth(); height = getHeight(); data = new GLubyte[width*height*3]; glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); if ((tga = fopen("screen.tga", "wb")) == NULL) { delete[] data; exiterror("Couldn't write to file","screen.tga"); } tgahdr.Offset = 0; tgahdr.ColorType = 0; tgahdr.ImageType = 2; tgahdr.PaletteStart = 0; tgahdr.PaletteLen = 0; tgahdr.PalBits = 0; tgahdr.XOrigin = 0; tgahdr.YOrigin = 0; tgahdr.Width = width; tgahdr.Height = height; tgahdr.BPP = 0x20; tgahdr.Orientation = 0x08; fwrite(&tgahdr, 18, 1, tga); for (i = 0; i < width*height; i++) { putc(data[i*3+2], tga); putc(data[i*3+1], tga); putc(data[i*3], tga); putc(255, tga); } fclose(tga); delete[] data; } void CGLView::Init() { int w, h; // GLfloat lgtamb[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat lgtamb[] = { 0.0f, 0.5f, 0.5f, 1.0f }; GLfloat lgtdif[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat lgtpos[] = { 5.0f, 5.0f, 10.0f, 1.0f }; w = GLView.getWidth(); h = GLView.getHeight(); if (useGLEW) { GLenum err; if ((err = glewInit()) != GLEW_OK) exiterror("Could not initialize GLEW", ""); } glClearDepth(1.0); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(Camera.GetFOV(), (GLfloat) w/(GLfloat)h, 1.0f, 1000); glMatrixMode(GL_MODELVIEW); /* Set up lighting */ glEnable(GL_LIGHTING); // glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lgtamb); glLightfv(GL_LIGHT0, GL_POSITION, lgtpos); glLightfv(GL_LIGHT0, GL_AMBIENT, lgtamb); glLightfv(GL_LIGHT0, GL_DIFFUSE, lgtdif); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); /* Set up texture units */ glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); /* Set up texture generation for reflection maps */ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glActiveTexture(GL_TEXTURE0); useTextures = true; useVertexColors = true; doWire = false; useFog = true; useTint = true; doStereo = false; doRadar = false; doCulling = true; } void CGLView::SetnRadarFiles(int n) { nRadarFiles = n; }; void CGLView::SetFog(bool b) { useFog = b; } void CGLView::ToggleFog() { useFog = !useFog; } bool CGLView::UseFog() { return useFog; } void CGLView::SetTextures(bool b) { useTextures = b; } void CGLView::ToggleTextures() { useTextures = !useTextures; } bool CGLView::UseTextures() { return useTextures; } void CGLView::SetVertexColors(bool b) { useVertexColors = b; } void CGLView::ToggleVertexColors() { useVertexColors = !useVertexColors; } bool CGLView::UseVertexColors() { return useVertexColors; } void CGLView::SetTint(bool b) { useTint = b; } void CGLView::ToggleTint() { useTint = !useTint; } bool CGLView::UseTint() { return useTint; } void CGLView::SetStereo(bool b) { doStereo = b; } void CGLView::ToggleStereo() { doStereo = !doStereo; } bool CGLView::DoStereo() { return doStereo; } void CGLView::SetRadar(bool b) { doRadar = b; } void CGLView::ToggleRadar() { doRadar = !doRadar; } bool CGLView::DoRadar() { return doRadar; } void CGLView::SetCulling(bool b) { doCulling = b; } void CGLView::ToggleCulling() { doCulling = !doCulling; } bool CGLView::DoCulling() { return doCulling; } void CGLView::ToggleWire() { doWire = !doWire; if (doWire) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } void TransformItem(Instance *Inst) { RwReal *quat; RwReal x2, y2, z2, xy, xz, yz, wx, wy, wz; GLfloat matrix[16]; quat = Inst->Rotation; x2 = quat[0] * quat[0]; y2 = quat[1] * quat[1]; z2 = quat[2] * quat[2]; xy = quat[0] * quat[1]; xz = quat[0] * quat[2]; yz = quat[1] * quat[2]; wx = quat[3] * quat[0]; wy = quat[3] * quat[1]; wz = quat[3] * quat[2]; matrix[0] = 1.0f - 2.0f * (y2 + z2); matrix[1] = 2.0f * (xy - wz); matrix[2] = 2.0f * (xz + wy); matrix[3] = 0.0f; matrix[4] = 2.0f * (xy + wz); matrix[5] = 1.0f - 2.0f * (x2 + z2); matrix[6] = 2.0f * (yz - wx); matrix[7] = 0.0f; matrix[8] = 2.0f * (xz - wy); matrix[9] = 2.0f * (yz + wx); matrix[10] = 1.0f - 2.0f * (x2 + y2); matrix[11] = 0.0f; matrix[12] = Inst->PositionV[0]; matrix[13] = Inst->PositionV[1]; matrix[14] = Inst->PositionV[2]; matrix[15] = 1.0f; glMultMatrixf(matrix); } bool isCulled(Instance *inst) { GLfloat Pos[3]; Pos[0] = inst->PositionV[0] + inst->Obj->BSphere[0]; Pos[1] = inst->PositionV[1] + inst->Obj->BSphere[1]; Pos[2] = inst->PositionV[2] + inst->Obj->BSphere[2]; return !Camera.isSphereInFrustum(Pos, inst->Obj->BSphere[3]); } bool isVisible(CWorldObj *curobj) { int TimeHour; TimeHour = Clock.GetHour(); if (curobj->TimeOn < curobj->TimeOff) { /* Day object */ if (TimeHour < curobj->TimeOn || TimeHour >= curobj->TimeOff) return false; else return true; } else { /* Night object */ if (TimeHour < curobj->TimeOff || TimeHour >= curobj->TimeOn) return true; else return false; } } void MixColors(RwUInt8 *result, RwUInt8 *col1, RwUInt8 *col2, int ratio1, int full) { int ratio2; ratio2 = full-ratio1; result[0] = (col1[0]*ratio1 + col2[0]*ratio2)/full; result[1] = (col1[1]*ratio1 + col2[1]*ratio2)/full; result[2] = (col1[2]*ratio1 + col2[2]*ratio2)/full; result[3] = (col1[3]*ratio1 + col2[3]*ratio2)/full; } bool BindTexture(const char *texname) { bool retval; RwTexDictionary *Dict; RwTexture *rastertex; glBindTexture(GL_TEXTURE_2D, 0); if (strcmp(texname, "missing") == 0) return false; Dict = RwTexDictionaryGetCurrent(); if (Dict == NULL) return false; rastertex = RwTexDictionaryFindNamedTexture(Dict, texname); if (rastertex != NULL) { glBindTexture(GL_TEXTURE_2D, rastertex->TexID); return rastertex->HasAlpha; } else { RwTexDictionarySetCurrent(Dict->Parent); retval = BindTexture(texname); RwTexDictionarySetCurrent(Dict); return retval; } } bool BindTextureFromTxd(const char *TexName, const char *TxdName) { RwTexDictionary *Dict; DirEntry *Entry; glBindTexture(GL_TEXTURE_2D, 0); Entry = Directory.GetEntry(TxdName, ".TXD"); if (Entry == NULL) return false; if (Entry->Data == NULL) { Dict = FileLoader.LoadTexDict(Entry); Entry->Data = Dict; } else { Dict = (RwTexDictionary *) Entry->Data; } RwTexDictionarySetCurrent(Dict); return BindTexture(TexName); } void DrawSprite(const char *DictName, const char *TexName, bool hasAlpha) { if (GLView.UseTextures()) BindTextureFromTxd(TexName, DictName); if (hasAlpha){ glEnable(GL_BLEND); // glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); glBlendFunc(GL_ONE, GL_ONE); } else { glDisable(GL_BLEND); } // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBegin(GL_QUADS); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f); glVertex3f(-1, 0, -1); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f); glVertex3f(-1, 0, 1); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f); glVertex3f(1, 0, 1); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f); glVertex3f(1, 0, -1); glEnd(); /* revert changes */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }