src/tron/cockpit/cMap.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 #include "cockpit/cMap.h"
00028 #include "cockpit/cCockpit.h"
00029 #include "nConfig.h"
00030 #include "tCoord.h"
00031 
00032 #ifndef DEDICATED
00033 
00034 #include "rRender.h"
00035 #include "rScreen.h"
00036 #include "gWinZone.h"
00037 #include "eRectangle.h"
00038 #include "ePlayer.h"
00039 #include "eTimer.h"
00040 
00041 #include "rViewport.h"
00042 #include "eGrid.h"
00043 #include "eCamera.h"
00044 #include "gCycle.h"
00045 
00046 #endif
00047 
00048 #include <vector>
00049 
00050 static bool stc_forbidHudMap = false;
00051 // TODO find out why this is throwing an error: “Two tConfItems with the same name FORBID_HUD_MAP!”
00052 // Z-Man: hmm, it doesn't throw an error for me.
00053 static nSettingItem<bool> fcs("FORBID_HUD_MAP", stc_forbidHudMap);
00054 extern std::vector<tCoord> se_rimWallRubberBand;
00055 
00056 #ifndef DEDICATED
00057 
00058 extern std::deque<gZone *> sg_Zones;
00059 
00060 namespace cWidget {
00061 
00062 void Map::ClipperRect::Begin(Map &map, tCoord const &e1, tCoord const &e2) {
00063     // set clipping frame in map coordinates
00064     GLdouble pl0[4] = {1.0, 0.0, 0.0, -e1.x };
00065     GLdouble pl1[4] = {-1.0, 0.0, 0.0, e2.x };
00066     GLdouble pl2[4] = {0.0, 1.0, 0.0, -e1.y };
00067     GLdouble pl3[4] = {0.0, -1.0, 0.0, e2.y };
00068     glClipPlane(GL_CLIP_PLANE0, pl0);
00069     glEnable(GL_CLIP_PLANE0);
00070     glClipPlane(GL_CLIP_PLANE1, pl1);
00071     glEnable(GL_CLIP_PLANE1);
00072     glClipPlane(GL_CLIP_PLANE2, pl2);
00073     glEnable(GL_CLIP_PLANE2);
00074     glClipPlane(GL_CLIP_PLANE3, pl3);
00075     glEnable(GL_CLIP_PLANE3);
00076     // Add frame ...
00077     map.m_foreground.BeginDraw();
00078     glBegin(GL_LINE_STRIP);
00079     //TODO: this should use a function of the rGradient.
00080     map.m_foreground.DrawPoint(e1);
00081     map.m_foreground.DrawPoint(tCoord(e2.x, e1.y));
00082     map.m_foreground.DrawPoint(e2);
00083     map.m_foreground.DrawPoint(tCoord(e1.x, e2.y));
00084     map.m_foreground.DrawPoint(e1);
00085     glEnd();
00086     map.m_background.SetGradientEdges(e1, e2);
00087     map.m_background.DrawRect(e1, e2);
00088 }
00089 
00090 void Map::ClipperRect::End() {
00091     glDisable(GL_CLIP_PLANE0);
00092     glDisable(GL_CLIP_PLANE1);
00093     glDisable(GL_CLIP_PLANE2);
00094     glDisable(GL_CLIP_PLANE3);
00095 }
00096 
00097 Map::ClipperCircle::ClipperCircle() {
00098     glGetIntegerv(GL_MAX_CLIP_PLANES, (GLint *)(&m_edges));
00099     if(m_edges > 20) {
00100         m_edges = 20;
00101     }
00102 }
00103 //the visible area is on the "left side" of the line, if you go from u to v
00104 void Map::ClipperCircle::Clip(int i, tCoord const &u, tCoord const &v) {
00105     //glBegin(GL_LINES);
00106     //Color(1,0,0);
00107     //Vertex(u.x, u.y);
00108     //Color(0,1,0);
00109     //Vertex(v.x, v.y);
00110     //glEnd();
00111     if(u.x == v.x) {
00112         GLdouble factor = (u.y>v.y) ? 1 : -1;
00113         GLdouble pl[4] = {factor*1.0, 0.0, 0.0, -factor*v.x };
00114         glClipPlane(GL_CLIP_PLANE0+i, pl);
00115         glEnable(GL_CLIP_PLANE0+i);
00116     } else {
00117         GLdouble factor = (u.x<v.x) ? -1 : 1;
00118         GLdouble a = (v.y-u.y)/(v.x-u.x);
00119         GLdouble pl[4] = {
00120                              factor*-a,
00121                              factor,
00122                              0.,
00123                              factor*-(u.y-a*u.x)
00124                          };
00125         glClipPlane(GL_CLIP_PLANE0+i, pl);
00126         glEnable(GL_CLIP_PLANE0+i);
00127     }
00128 }
00129 void Map::ClipperCircle::Begin(Map &map, tCoord const &e1, tCoord const &e2) {
00130     tCoord centre = .5*(e1+e2);
00131     tCoord ab = .5*(e2-e1);
00132     ab.x = fabs(ab.x); ab.y = fabs(ab.y);
00133     float stepsize=M_PI*2/m_edges;
00134 
00135         map.m_background.BeginDraw();
00136         map.m_background.SetGradientEdges(centre - ab, centre + ab);
00137         glBegin(GL_POLYGON);
00138     for(int i = 0; i < m_edges; ++i) {
00139         float t = (i+1)*stepsize;
00140         tCoord next(centre.x+ab.x*cos(t), centre.y-ab.y*sin(t));
00141         map.m_background.DrawPoint(next);
00142     }
00143         glEnd();
00144         glDisable(GL_TEXTURE_2D);
00145     tCoord last = centre + tCoord(ab.x, 0);
00146         map.m_foreground.SetGradientEdges(centre - ab, centre + ab);
00147         map.m_foreground.BeginDraw();
00148     for(int i = 0; i < m_edges; ++i) {
00149         float t = (i+1)*stepsize;
00150         tCoord next(centre.x+ab.x*cos(t), centre.y-ab.y*sin(t));
00151                 glBegin(GL_LINES);
00152         glVertex2f(next.x, next.y);
00153         glVertex2f(last.x, last.y);
00154         map.m_foreground.DrawPoint(next);
00155         map.m_foreground.DrawPoint(last);
00156                 glEnd();
00157         Clip(i, last, next);
00158         last = next;
00159     }
00160         glDisable(GL_TEXTURE_2D);
00161 }
00162 void Map::ClipperCircle::End() {
00163     for(int i = 0; i < m_edges; ++i) {
00164         glDisable(GL_CLIP_PLANE0 + i); //according to the documentation you're allowed to do that
00165     }
00166 }
00167 
00168 bool Map::Process(tXmlParser::node cur) {
00169     if (
00170         WithCoordinates ::Process(cur) ||
00171         WithForeground ::Process(cur) ||
00172         WithBackground ::Process(cur))
00173         return true;
00174     if(cur.IsOfType("MapModes")) {
00175         int toggleKey;
00176         cur.GetProp("toggleKey", toggleKey);
00177         if(toggleKey > 0) {
00178             m_toggleKey = toggleKey;
00179             m_Cockpit->AddEventHandler(toggleKey, this);
00180         }
00181         for(cur = cur.GetFirstChild(); cur; ++cur) {
00182             if(cur.IsOfType("MapMode")) {
00183                 m_modes.push_back(Mode(cur));
00184                 if(m_modes.size() == 1) {
00185                     Apply(m_modes[0]); // apply the first mode and get rid of the defaults
00186                 }
00187             }
00188         }
00189         return true;
00190     }
00191     DisplayError(cur);
00192     return false;
00193 }
00194 Map::Mode::Mode(tXmlParser::node cur) {
00195     cur.GetProp("zoomFactor", m_zoom);
00196     tString mode = cur.GetProp("mode");
00197     if(mode == "closestZone") m_mode = MODE_ZONE;
00198     else if(mode == "cycle") m_mode = MODE_CYCLE;
00199     else m_mode = MODE_STD;
00200 
00201     tString rotation = cur.GetProp("rotation");
00202     if(rotation == "fixed") m_rotation = ROTATION_FIXED;
00203     else if(rotation == "cycle") m_rotation = ROTATION_CYCLE;
00204     else if(rotation == "camera") m_rotation = ROTATION_CAMERA;
00205     else m_rotation = ROTATION_SPAWN;
00206 
00207     tString clipper = cur.GetProp("clipMode");
00208     if(clipper == "ellipse") {
00209         m_clipper = ClipperCircle::create;
00210     } else {
00211         m_clipper = ClipperRect::create;
00212     }
00213 }
00214 void Map::Apply(Mode const &mode) {
00215     m_mode = mode.m_mode;
00216     m_rotation = mode.m_rotation;
00217     m_zoom = mode.m_zoom;
00218     m_clipper.reset((*mode.m_clipper)());
00219 }
00220 void Map::HandleEvent(bool state, int id) {
00221     if(id == m_toggleKey) {
00222         if(state) {
00223             ToggleMode();
00224         }
00225     } else {
00226         Base::HandleEvent(state, id);
00227     }
00228 }
00229 
00230 void Map::Render() {
00231     // I haven't checked possible initial matrix state, so init to identity and modelview
00232     if(stc_forbidHudMap) return; // the server doesn't want us to do that
00233     glMatrixMode(GL_PROJECTION);
00234     glLoadIdentity();
00235     glMatrixMode(GL_MODELVIEW);
00236     glLoadIdentity();
00237     glDisable(GL_TEXTURE_2D);
00238     glDisable(GL_LIGHTING);
00239     glDisable(GL_LINE_SMOOTH);
00240     glHint (GL_LINE_SMOOTH_HINT, GL_FASTEST);
00241     DrawMap(true, true,
00242             5.5, 0.,
00243             m_position.x-m_size.x, m_position.y-m_size.y, 2.*m_size.x, 2.*m_size.y,
00244             sr_screenWidth*m_size.x, sr_screenWidth*m_size.y, .5, .5);
00245 }
00246 void Map::DrawMap(bool rimWalls, bool cycleWalls,
00247                   double cycleSize, double border,
00248                   double x, double y, double w, double h,
00249                   double rw, double rh, double ix, double iy) {
00250     double pl_CurSpeed, min_dist2, dist2, rad, zoom = 1;
00251     tCoord pl_CurPos, rotate; // rotate will hold the cos and sin of the rotation to apply
00252     cCockpit* cp = m_Cockpit;
00253     if(!rimWalls && !cycleWalls) return;
00254     const eRectangle &bounds = eWallRim::GetBounds();
00255     double lx = bounds.GetLow().x - border, hx = bounds.GetHigh().x + border;
00256     double ly = bounds.GetLow().y - border, hy = bounds.GetHigh().y + border;
00257     double mw = hx - lx, mh = hy - ly;
00258     double xpos, ypos, xscale, yscale;
00259     double xrat = (rw * mh) / (rh * mw);
00260     double yrat = (rh * mw) / (rw * mh);
00261     // set scale and position
00262     if(xrat > yrat) {
00263         xscale = (w * rh) / (mh * rw);
00264         yscale = h / mh;
00265     } else {
00266         xscale = w / mw;
00267         yscale = (h * rw) / (mw * rh);
00268     }
00269     rotate.x = 1; // no rotation
00270     rotate.y = 0;
00271 
00272     //do the rotation
00273     switch(m_rotation) {
00274     case ROTATION_SPAWN:
00275     if(!cp->GetFocusCycle()) { break; }
00276         rotate = cp->GetFocusCycle()->SpawnDirection().Turn(0,-1);
00277         break;
00278     case ROTATION_CYCLE:
00279     if(!cp->GetFocusCycle()) { break; }
00280         rotate = cp->GetFocusCycle()->Direction().Turn(0,-1);
00281         break;
00282     case ROTATION_CAMERA:
00283         {
00284             ePlayer const *player = cp->GetPlayer();
00285             if(!player) break;
00286             eCamera const *cam = player->cam;
00287             if(cam) {
00288                 rotate = cam->CameraDir().Turn(0,-1);
00289             } else {
00290                 rotate = tCoord(1, 0);
00291             }
00292         }
00293         break;
00294     default:
00295         rotate = tCoord(1, 0);
00296         break;
00297     }
00298 
00299     // manage mode
00300     switch (m_mode) {
00301     case MODE_ZONE:
00302     if(!cp->GetFocusCycle()) { break; }
00303         pl_CurPos = cp->GetFocusCycle()->Position();
00304         min_dist2 = (mw*mw+mh*mh)*1000;
00305         rad = 0;
00306         for(std::deque<gZone *>::const_iterator i = sg_Zones.begin(); i != sg_Zones.end(); ++i) {
00307             tASSERT(*i);
00308             tCoord const &position = (*i)->GetPosition();
00309             const float radius = (*i)->GetRadius();
00310             dist2 = (position-pl_CurPos).Norm();
00311             if (dist2<min_dist2) {
00312                 min_dist2 = dist2;
00313                 m_centre = position;
00314                 rad = radius;
00315             }
00316         }
00317         rad = (rad<15)?15:rad;
00318         zoom = (w>h)?h/(yscale*m_zoom*rad):w/(xscale*m_zoom*rad);
00319         zoom = (zoom<1)?1:zoom;
00320         // check if at least 1 zone was found, if not, toggle to mode 2 ...
00321         if (rad==0) {
00322             m_mode = MODE_CYCLE;
00323         } else {
00324             break;
00325         }
00326     case MODE_CYCLE:
00327     if(!cp->GetFocusCycle()) { break; }
00328         m_centre = cp->GetFocusCycle()->Position();
00329         pl_CurSpeed = cp->GetFocusCycle()->Speed();
00330         zoom = (w>h)?h/(yscale*m_zoom*pl_CurSpeed):w/(xscale*m_zoom*pl_CurSpeed);
00331         zoom = (zoom<1)?1:zoom;
00332         break;
00333     default :
00334         zoom = 1;
00335         m_centre.x = lx + mw / 2;
00336         m_centre.y = ly + mh / 2;
00337         break;
00338     }
00339     xscale *=zoom;
00340     yscale *=zoom;
00341     xpos = x - m_centre.x * xscale + w / 2;
00342     ypos = y - m_centre.y * yscale + h / 2;
00343     if(m_mode != MODE_STD) {
00344         m_clipper->Begin(*this, tCoord(x,y), tCoord(x+w, y+h));
00345     }
00346     // set projection matrix
00347     glPushMatrix();
00348     glTranslatef(xpos, ypos, 0);
00349     glScalef(xscale, yscale, 1);
00350     // translate and rotate
00351     GLfloat r[16] = {
00352           rotate.x,  -rotate.y, 0, 0,
00353           rotate.y,   rotate.x, 0, 0,
00354                  0,          0, 1, 0,
00355         m_centre.x, m_centre.y, 0, 1};
00356     glMultMatrixf(r);
00357     glTranslatef(-m_centre.x,-m_centre.y,0);
00358     if(rimWalls)
00359         DrawRimWalls(se_rimWalls);
00360     if(cycleWalls) {
00361         DrawWalls(sg_netPlayerWallsGridded);
00362         DrawWalls(sg_netPlayerWalls);
00363     }
00364     DrawObjects(tCoord((cycleSize * w) / (rw * xscale), (cycleSize * h) / (rh * yscale)));
00365     glPopMatrix();
00366     if(m_mode != MODE_STD) {
00367         m_clipper->End();
00368     }
00369 }
00370 
00371 void Map::DrawRimWalls( tList<eWallRim> &list ) {
00372     if(sr_alphaBlend && m_mode == MODE_STD) {
00373         const eRectangle &bounds = eWallRim::GetBounds();
00374         const tCoord dims = bounds.GetHigh() - bounds.GetLow();
00375         const float max = fmax(dims.x, dims.y); // make sure we get a square
00376         m_background.SetGradientEdges(bounds.GetLow(), tCoord(bounds.GetLow().x + max, bounds.GetLow().y + max));
00377         m_background.BeginDraw();
00378         glBegin(GL_POLYGON);
00379         for(std::vector<tCoord>::iterator iter = se_rimWallRubberBand.begin(); iter != se_rimWallRubberBand.end(); ++iter) {
00380             m_background.DrawPoint(*iter);
00381         }
00382         m_background.DrawPoint(se_rimWallRubberBand.front());
00383         glEnd();
00384     }
00385     glDisable(GL_TEXTURE_2D);
00386     glColor4f(1, 1, 1, .5);
00387     glBegin(GL_LINES);
00388     {
00389         for (int i=list.Len()-1; i >= 0; --i)
00390         {
00391             eWallRim *wall = list[i];
00392             eCoord begin = wall->EndPoint(0), end = wall->EndPoint(1);
00393             glVertex2f(begin.x, begin.y);
00394             glVertex2f(end.x, end.y);
00395         }
00396 
00397 
00398     }
00399     glEnd();
00400 }
00401 
00402 void Map::DrawWalls(tList<gNetPlayerWall> &list) {
00403     unsigned i, len=list.Len();
00404     double currentTime = se_GameTime();
00405     bool limitedLength = gCycle::WallsLength() > 0;
00406     double wallsStayUpDelay = gCycle::WallsStayUpDelay();
00407     glBegin(GL_LINES);
00408     for(i=0; i<len; i++) {
00409         gNetPlayerWall *wall = list[i];
00410         gCycle *cycle = wall->Cycle();
00411         if(!cycle) continue;
00412         double wallsLength = cycle->ThisWallsLength();
00413         double alpha = 1;
00414         if(!cycle->Alive() && wallsStayUpDelay >= 0) {
00415             alpha -= 2 * (currentTime - cycle->DeathTime() - wallsStayUpDelay);
00416             if(alpha <= 0) continue;
00417         }
00418         glColor4f(cycle->color_.r, cycle->color_.g, cycle->color_.b, alpha);
00419         double cycleDist = cycle->GetDistance();
00420         double minDist = limitedLength && cycleDist > wallsLength ? cycleDist - wallsLength : 0;
00421         const eCoord &begPos = wall->EndPoint(0), &endPos = wall->EndPoint(1);
00422         tArray<gPlayerWallCoord> &coords = wall->Coords();
00423         double begDist = wall->BegPos();
00424         double lenDist = wall->EndPos() - begDist;
00425         unsigned j, numcoords = coords.Len();
00426         if(numcoords < 2) continue;
00427         bool prevDangerous = coords[0].IsDangerous;
00428         double prevDist = coords[0].Pos;
00429         if(prevDist < minDist) prevDist = minDist;
00430         prevDist = (prevDist - begDist) / lenDist;
00431         for(j=1; j<numcoords; j++) {
00432             bool curDangerous = coords[j].IsDangerous;
00433             double curDist = coords[j].Pos;
00434             if(curDist < minDist) curDist = minDist;
00435             curDist = (curDist - begDist) / lenDist;
00436             if(prevDangerous) {
00437                 glVertex2f(begPos.x + prevDist * (endPos.x - begPos.x), begPos.y + prevDist * (endPos.y - begPos.y));
00438                 glVertex2f(begPos.x +  curDist * (endPos.x - begPos.x), begPos.y +  curDist * (endPos.y - begPos.y));
00439             }
00440             prevDangerous = curDangerous;
00441             prevDist = curDist;
00442         }
00443     }
00444     glEnd();
00445 }
00446 
00447 void Map::DrawObjects(tCoord scale) {
00448     tList<eGameObject> const &gameObjects = eGrid::CurrentGrid()->GameObjects();
00449     size_t len = gameObjects.Len();
00450     for(size_t i = 0; i < len; ++i) {
00451         eGameObject const *obj = gameObjects(i);
00452         tASSERT(obj);
00453         obj->Render2D(scale);
00454     }
00455 }
00456 
00457 void Map::ToggleMode(void) {
00458     if(m_modes.empty()) return;
00459     m_currentMode = (m_currentMode+1) % m_modes.size();
00460     Apply(m_modes[m_currentMode]);
00461 }
00462 
00463 Map::Map():
00464         m_mode(MODE_STD),
00465         m_zoom(3),
00466         m_rotation(ROTATION_SPAWN),
00467         m_toggleKey(0),
00468         m_clipper(new ClipperRect()),
00469         m_currentMode(0)
00470 {}
00471 
00472 }
00473 #endif

Generated on Sat Mar 15 22:56:05 2008 for Armagetron Advanced by  doxygen 1.5.4