00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <string.h>
00036
00037 #include "stratagus.h"
00038 #include "video.h"
00039 #include "map.h"
00040 #include "minimap.h"
00041 #include "unittype.h"
00042 #include "player.h"
00043 #include "unit.h"
00044 #include "ui.h"
00045 #include "editor.h"
00046 #include "patch.h"
00047 #include "patch_type.h"
00048
00049
00050
00051
00052
00053 #define MINIMAP_FAC (16 * 3)
00054
00056 #define ATTACK_RED_DURATION (1 * CYCLES_PER_SECOND)
00058 #define ATTACK_BLINK_DURATION (7 * CYCLES_PER_SECOND)
00059
00060 #define SCALE_PRECISION 100
00061
00062
00063
00064
00065
00066
00067 static GLuint MinimapTexture;
00068 static unsigned char *MinimapSurfaceGL;
00069 static unsigned char *MinimapTerrainSurfaceGL;
00070 static int MinimapTextureWidth;
00071 static int MinimapTextureHeight;
00072 static SDL_Surface *MinimapSurface;
00073 static SDL_Surface *MinimapTerrainSurface;
00074
00075 static int *Minimap2MapX;
00076 static int *Minimap2MapY;
00077 static int Map2MinimapX[MaxMapWidth];
00078 static int Map2MinimapY[MaxMapHeight];
00079
00080
00081
00082
00083 static int MinimapScaleX;
00084 static int MinimapScaleY;
00085
00086 #define MAX_MINIMAP_EVENTS 8
00087
00088 struct MinimapEvent {
00089 int X;
00090 int Y;
00091 int Size;
00092 } MinimapEvents[MAX_MINIMAP_EVENTS];
00093 int NumMinimapEvents;
00094
00095
00096
00097
00098
00099
00103 static void CreateMinimapTexture(void)
00104 {
00105 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00106 glGenTextures(1, &MinimapTexture);
00107 glBindTexture(GL_TEXTURE_2D, MinimapTexture);
00108 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00109 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00112 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MinimapTextureWidth,
00113 MinimapTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
00114 MinimapSurfaceGL);
00115 }
00116
00120 void CMinimap::Create(void)
00121 {
00122 int n;
00123 int maxSize = std::max(Map.Info.MapWidth, Map.Info.MapHeight);
00124
00125 MinimapScaleX = (W * MINIMAP_FAC + maxSize - 1) / maxSize;
00126 MinimapScaleY = (H * MINIMAP_FAC + maxSize - 1) / maxSize;
00127
00128 XOffset = (W - (Map.Info.MapWidth * MinimapScaleX) / MINIMAP_FAC + 1) / 2;
00129 YOffset = (H - (Map.Info.MapHeight * MinimapScaleY) / MINIMAP_FAC + 1) / 2;
00130
00131
00132
00133
00134 Minimap2MapX = new int[W];
00135 memset(Minimap2MapX, 0, W * sizeof(int));
00136 Minimap2MapY = new int[H];
00137 memset(Minimap2MapY, 0, H * sizeof(int));
00138 for (n = XOffset; n < W - XOffset; ++n) {
00139 Minimap2MapX[n] = ((n - XOffset) * MINIMAP_FAC) / MinimapScaleX;
00140 }
00141 for (n = YOffset; n < H - YOffset; ++n) {
00142 Minimap2MapY[n] = (((n - YOffset) * MINIMAP_FAC) / MinimapScaleY);
00143 }
00144 for (n = 0; n < Map.Info.MapWidth; ++n) {
00145 Map2MinimapX[n] = (n * MinimapScaleX) / MINIMAP_FAC;
00146 }
00147 for (n = 0; n < Map.Info.MapHeight; ++n) {
00148 Map2MinimapY[n] = (n * MinimapScaleY) / MINIMAP_FAC;
00149 }
00150
00151 if (!UseOpenGL) {
00152 SDL_PixelFormat *f = TheScreen->format;
00153 MinimapTerrainSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
00154 W, H, f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask);
00155 MinimapSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
00156 W, H, f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask);
00157 } else {
00158 for (MinimapTextureWidth = 1; MinimapTextureWidth < W; MinimapTextureWidth <<= 1) {
00159 }
00160 for (MinimapTextureHeight = 1; MinimapTextureHeight < H; MinimapTextureHeight <<= 1) {
00161 }
00162 MinimapTerrainSurfaceGL = new unsigned char[MinimapTextureWidth * MinimapTextureHeight * 4];
00163 MinimapSurfaceGL = new unsigned char[MinimapTextureWidth * MinimapTextureHeight * 4];
00164 memset(MinimapSurfaceGL, 0, MinimapTextureWidth * MinimapTextureHeight * 4);
00165 CreateMinimapTexture();
00166 }
00167
00168 UpdateTerrain();
00169
00170 NumMinimapEvents = 0;
00171 }
00172
00176 void CMinimap::FreeOpenGL()
00177 {
00178 glDeleteTextures(1, &MinimapTexture);
00179 }
00180
00184 void CMinimap::Reload()
00185 {
00186 CreateMinimapTexture();
00187 }
00188
00192 CColor GetColor(CPatch *patch, int xoffset, int yoffset, int mx, int my, int scalex, int scaley)
00193 {
00194
00195
00196
00197 int x = (xoffset * TileSizeX + 7 + ((mx * SCALE_PRECISION) % scalex) / SCALE_PRECISION * 8);
00198 int y = (yoffset * TileSizeY + 6 + ((my * SCALE_PRECISION) % scaley) / SCALE_PRECISION * 8);
00199
00200 Uint8 r, g, b, a;
00201 SDL_Surface *s = patch->getType()->getGraphic()->Surface;
00202 SDL_PixelFormat *f = s->format;
00203
00204
00205
00206
00207 Uint8 *pixel = &((Uint8 *)s->pixels)[x * f->BytesPerPixel + y * s->pitch];
00208 switch (f->BytesPerPixel) {
00209 case 1:
00210 SDL_GetRGBA(*pixel, f, &r, &g, &b, &a);
00211 break;
00212 case 2:
00213 SDL_GetRGBA(*(Uint16 *)pixel, f, &r, &g, &b, &a);
00214 break;
00215 case 3:
00216 r = pixel[f->Rshift >> 3];
00217 g = pixel[f->Gshift >> 3];
00218 b = pixel[f->Bshift >> 3];
00219 a = 0;
00220 break;
00221 case 4:
00222 SDL_GetRGBA(*(Uint32 *)pixel, f, &r, &g, &b, &a);
00223 break;
00224 }
00225
00226 return CColor(r, g, b, a);
00227 }
00228
00232 void SetMinimapTerrainPixel(int x, int y, CColor color)
00233 {
00234 if (!UseOpenGL) {
00235 int bpp = MinimapTerrainSurface->format->BytesPerPixel;
00236 Uint8 *p = &((Uint8 *)MinimapTerrainSurface->pixels)[x * bpp + y * MinimapTerrainSurface->pitch];
00237 Uint32 c = Video.MapRGBA(MinimapTerrainSurface->format, color.R, color.G, color.B, color.A);
00238 if (bpp == 2) {
00239 *(Uint16 *)p = c;
00240 } else {
00241 *(Uint32 *)p = c;
00242 }
00243 } else {
00244 *(Uint32 *)&(MinimapTerrainSurfaceGL[(x + y * MinimapTextureWidth) * 4]) = Video.MapRGBA(0, color.R, color.G, color.B, color.A);
00245 }
00246 }
00247
00251 void CMinimap::UpdateTerrain()
00252 {
00253 int scalex = MinimapScaleX * SCALE_PRECISION / MINIMAP_FAC;
00254 if (scalex == 0) {
00255 scalex = 1;
00256 }
00257 int scaley = MinimapScaleY * SCALE_PRECISION / MINIMAP_FAC;
00258 if (scaley == 0) {
00259 scaley = 1;
00260 }
00261
00262 if (!UseOpenGL) {
00263 SDL_LockSurface(MinimapTerrainSurface);
00264 }
00265
00266 for (int my = YOffset; my < H - YOffset; ++my) {
00267 for (int mx = XOffset; mx < W - XOffset; ++mx) {
00268 CPatch *patch;
00269 int xoffset, yoffset;
00270 CColor color = ColorBlack;
00271
00272 patch = Map.PatchManager.getPatch(Minimap2MapX[mx], Minimap2MapY[my], &xoffset, &yoffset);
00273 if (patch) {
00274 color = GetColor(patch, xoffset, yoffset, mx, my, scalex, scaley);
00275 }
00276 SetMinimapTerrainPixel(mx, my, color);
00277 }
00278 }
00279
00280 if (!UseOpenGL) {
00281 SDL_UnlockSurface(MinimapTerrainSurface);
00282 }
00283 }
00284
00288 static void ClearMinimap()
00289 {
00290 if (!UseOpenGL) {
00291 SDL_FillRect(MinimapSurface, NULL, SDL_MapRGB(MinimapSurface->format, 0, 0, 0));
00292 } else {
00293 memset(MinimapSurfaceGL, 0, MinimapTextureWidth * MinimapTextureHeight * 4);
00294 }
00295 }
00296
00300 static void CopyMinimapTerrain()
00301 {
00302 if (!UseOpenGL) {
00303 SDL_BlitSurface(MinimapTerrainSurface, NULL, MinimapSurface, NULL);
00304 } else {
00305 memcpy(MinimapSurfaceGL, MinimapTerrainSurfaceGL, MinimapTextureWidth * MinimapTextureHeight * 4);
00306 }
00307 }
00308
00312 static void SetMinimapPixel(int x, int y, Uint32 color)
00313 {
00314 if (!UseOpenGL) {
00315 int bpp = MinimapSurface->format->BytesPerPixel;
00316 Uint8 *p = &((Uint8 *)MinimapSurface->pixels)[x * bpp + y * MinimapSurface->pitch];
00317 if (bpp == 2) {
00318 *(Uint16 *)p = color;
00319 } else {
00320 *(Uint32 *)p = color;
00321 }
00322 } else {
00323 *(Uint32 *)&(MinimapSurfaceGL[(x + y * MinimapTextureWidth) * 4]) = color;
00324 }
00325 }
00326
00330 static void DrawUnitOn(CUnit *unit, bool red_phase)
00331 {
00332 const CUnitType *type;
00333 int mx, my;
00334 int w, h;
00335 int origh;
00336 Uint32 color;
00337
00338 if (Editor.Running || ReplayRevealMap || unit->IsVisible(ThisPlayer)) {
00339 type = unit->Type;
00340 } else {
00341 type = unit->Seen.Type;
00342
00343
00344 if (!type) {
00345 type = unit->Type;
00346 }
00347 }
00348
00349
00350
00351
00352 if (unit->Player->Index == PlayerNumNeutral) {
00353 color = Video.MapRGB(TheScreen->format,
00354 type->NeutralMinimapColorRGB.r,
00355 type->NeutralMinimapColorRGB.g,
00356 type->NeutralMinimapColorRGB.b);
00357 } else if (unit->Player == ThisPlayer && !Editor.Running) {
00358 if (unit->Attacked && unit->Attacked + ATTACK_BLINK_DURATION > GameCycle &&
00359 (red_phase || unit->Attacked + ATTACK_RED_DURATION > GameCycle)) {
00360 color = ColorRed;
00361 } else if (UI.Minimap.ShowSelected && unit->Selected) {
00362 color = ColorWhite;
00363 } else {
00364 color = ColorGreen;
00365 }
00366 } else {
00367 color = unit->Player->Color;
00368 }
00369
00370
00371
00372
00373 mx = 1 + UI.Minimap.XOffset + Map2MinimapX[unit->X];
00374 my = 1 + UI.Minimap.YOffset + Map2MinimapY[unit->Y];
00375
00376 w = Map2MinimapX[type->TileWidth];
00377 if (mx + w >= UI.Minimap.W) {
00378 w = UI.Minimap.W - mx;
00379 }
00380
00381 h = Map2MinimapY[type->TileHeight];
00382 if (my + h >= UI.Minimap.H) {
00383 h = UI.Minimap.H - my;
00384 }
00385
00386
00387
00388
00389 origh = h;
00390 while (w-- >= 0) {
00391 while (h-- >= 0) {
00392 SetMinimapPixel(mx + w, my + h, color);
00393 }
00394 h = origh;
00395 }
00396 }
00397
00401 void CMinimap::Update()
00402 {
00403 static bool red_phase = false;
00404 int mx, my;
00405 int visiontype;
00406
00407
00408 if (red_phase != (bool)((FrameCounter / FRAMES_PER_SECOND) & 1)) {
00409 red_phase = !red_phase;
00410 }
00411
00412
00413 if (!Transparent) {
00414 ClearMinimap();
00415 }
00416
00417
00418 if (WithTerrain) {
00419 CopyMinimapTerrain();
00420 }
00421
00422 if (!UseOpenGL) {
00423 SDL_LockSurface(MinimapSurface);
00424 SDL_LockSurface(MinimapTerrainSurface);
00425 }
00426
00427
00428 for (my = 0; my < H; ++my) {
00429 for (mx = 0; mx < W; ++mx) {
00430 if (!ReplayRevealMap) {
00431 visiontype = Map.IsTileVisible(ThisPlayer, Minimap2MapX[mx], Minimap2MapY[my]);
00432
00433
00434 if (visiontype == 0) {
00435 SetMinimapPixel(mx, my, ColorBlack);
00436 } else if (visiontype == 1 && ((mx & 1) != (my & 1))) {
00437
00438 SetMinimapPixel(mx, my, ColorBlack);
00439 }
00440 }
00441 }
00442 }
00443
00444 if (!UseOpenGL) {
00445 SDL_UnlockSurface(MinimapTerrainSurface);
00446 }
00447
00448
00449
00450
00451 for (int n = 0; n < NumUnits; ++n) {
00452 if (Units[n]->IsVisibleOnMinimap()) {
00453 DrawUnitOn(Units[n], red_phase);
00454 }
00455 }
00456
00457 if (!UseOpenGL) {
00458 SDL_UnlockSurface(MinimapSurface);
00459 }
00460 }
00461
00465 static void DrawEvents()
00466 {
00467 for (int i = 0; i < NumMinimapEvents; ++i) {
00468 Video.DrawTransCircleClip(ColorWhite,
00469 MinimapEvents[i].X, MinimapEvents[i].Y,
00470 MinimapEvents[i].Size, 192);
00471
00472
00473 MinimapEvents[i].Size -= 1;
00474
00475
00476 if (MinimapEvents[i].Size < 2) {
00477 MinimapEvents[i] = MinimapEvents[--NumMinimapEvents];
00478 --i;
00479 }
00480 }
00481 }
00482
00486 void CMinimap::Draw(int vx, int vy)
00487 {
00488 if (!UseOpenGL) {
00489 SDL_Rect drect = {X, Y, 0, 0};
00490 SDL_BlitSurface(MinimapSurface, NULL, TheScreen, &drect);
00491 } else {
00492 glBindTexture(GL_TEXTURE_2D, MinimapTexture);
00493 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MinimapTextureWidth, MinimapTextureHeight,
00494 GL_RGBA, GL_UNSIGNED_BYTE, MinimapSurfaceGL);
00495
00496 glBegin(GL_QUADS);
00497 glTexCoord2f(0.0f, 0.0f);
00498 glVertex2i(X, Y);
00499 glTexCoord2f(0.0f, (float)H / MinimapTextureHeight);
00500 glVertex2i(X, Y + H);
00501 glTexCoord2f((float)W / MinimapTextureWidth, (float)H / MinimapTextureHeight);
00502 glVertex2i(X + W, Y + H);
00503 glTexCoord2f((float)W / MinimapTextureWidth, 0.0f);
00504 glVertex2i(X + W, Y);
00505 glEnd();
00506 }
00507
00508 DrawEvents();
00509 }
00510
00511
00519 int CMinimap::Screen2MapX(int x)
00520 {
00521 int tx = (((x - X - XOffset) * MINIMAP_FAC) / MinimapScaleX);
00522 tx = std::max(tx, 0);
00523 tx = std::min(tx, Map.Info.MapWidth - 1);
00524 return tx;
00525 }
00526
00534 int CMinimap::Screen2MapY(int y)
00535 {
00536 int ty = (((y - Y - YOffset) * MINIMAP_FAC) / MinimapScaleY);
00537 ty = std::max(ty, 0);
00538 ty = std::min(ty, Map.Info.MapHeight - 1);
00539 return ty;
00540 }
00541
00545 void CMinimap::Destroy()
00546 {
00547 if (!UseOpenGL) {
00548 SDL_FreeSurface(MinimapTerrainSurface);
00549 MinimapTerrainSurface = NULL;
00550 } else {
00551 delete[] MinimapTerrainSurfaceGL;
00552 MinimapTerrainSurfaceGL = NULL;
00553 }
00554 if (!UseOpenGL) {
00555 if (MinimapSurface) {
00556 SDL_FreeSurface(MinimapSurface);
00557 MinimapSurface = NULL;
00558 }
00559 } else {
00560 if (MinimapSurfaceGL) {
00561 glDeleteTextures(1, &MinimapTexture);
00562 delete[] MinimapSurfaceGL;
00563 MinimapSurfaceGL = NULL;
00564 }
00565 }
00566 delete[] Minimap2MapX;
00567 Minimap2MapX = NULL;
00568 delete[] Minimap2MapY;
00569 Minimap2MapY = NULL;
00570 }
00571
00578 void CMinimap::DrawCursor(int vx, int vy)
00579 {
00580
00581 int x = X + XOffset + (vx * MinimapScaleX) / MINIMAP_FAC;
00582 int y = Y + YOffset + (vy * MinimapScaleY) / MINIMAP_FAC;
00583 int w = (UI.SelectedViewport->MapWidth * MinimapScaleX) / MINIMAP_FAC;
00584 int h = (UI.SelectedViewport->MapHeight * MinimapScaleY) / MINIMAP_FAC;
00585
00586
00587 Video.DrawTransRectangle(UI.ViewportCursorColor, x, y, w, h, 128);
00588 }
00589
00596 void CMinimap::AddEvent(int x, int y)
00597 {
00598 if (NumMinimapEvents == MAX_MINIMAP_EVENTS) {
00599 return;
00600 }
00601
00602 MinimapEvent *minimapEvent = &MinimapEvents[NumMinimapEvents++];
00603
00604 minimapEvent->X = X + XOffset + (x * MinimapScaleX) / MINIMAP_FAC;
00605 minimapEvent->Y = Y + YOffset + (y * MinimapScaleY) / MINIMAP_FAC;
00606 minimapEvent->Size = (W < H) ? W / 3 : H / 3;
00607 }
00608