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 <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039 #include "stratagus.h"
00040
00041 #include <string>
00042 #include <map>
00043 #include <list>
00044
00045 #include "video.h"
00046 #include "player.h"
00047 #include "intern_video.h"
00048 #include "iocompat.h"
00049 #include "iolib.h"
00050
00051
00052
00053
00054
00055 static int HashCount;
00056
00057 static std::map<std::string, CGraphic *> GraphicHash;
00058
00059 static std::list<CGraphic *> Graphics;
00060
00061
00062
00063
00064
00071 void CGraphic::DrawClip(int x, int y) const
00072 {
00073 int oldx = x;
00074 int oldy = y;
00075 int w = Width;
00076 int h = Height;
00077 CLIP_RECTANGLE(x, y, w, h);
00078 DrawSub(x - oldx, y - oldy, w, h, x, y);
00079 }
00080
00091 void CGraphic::DrawSub(int gx, int gy, int w, int h, int x, int y) const
00092 {
00093 if (!UseOpenGL) {
00094 SDL_Rect srect = {gx, gy, w, h};
00095 SDL_Rect drect = {x, y, 0, 0};
00096
00097 SDL_BlitSurface(Surface, &srect, TheScreen, &drect);
00098 } else {
00099 DrawTexture(this, Textures, gx, gy, gx + w, gy + h, x, y, 0);
00100 }
00101 }
00102
00113 void CGraphic::DrawSubClip(int gx, int gy, int w, int h, int x, int y) const
00114 {
00115 int oldx = x;
00116 int oldy = y;
00117 CLIP_RECTANGLE(x, y, w, h);
00118 DrawSub(gx + x - oldx, gy + y - oldy, w, h, x, y);
00119 }
00120
00132 void CGraphic::DrawSubTrans(int gx, int gy, int w, int h, int x, int y,
00133 unsigned char alpha) const
00134 {
00135 if (!UseOpenGL) {
00136 int oldalpha = Surface->format->alpha;
00137 SDL_SetAlpha(Surface, SDL_SRCALPHA, alpha);
00138 DrawSub(gx, gy, w, h, x, y);
00139 SDL_SetAlpha(Surface, SDL_SRCALPHA, oldalpha);
00140 } else {
00141 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00142 glColor4ub(255, 255, 255, alpha);
00143 DrawSub(gx, gy, w, h, x, y);
00144 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00145 }
00146 }
00147
00159 void CGraphic::DrawSubClipTrans(int gx, int gy, int w, int h, int x, int y,
00160 unsigned char alpha) const
00161 {
00162 int oldx = x;
00163 int oldy = y;
00164 CLIP_RECTANGLE(x, y, w, h);
00165 DrawSubTrans(gx + x - oldx, gy + y - oldy, w, h, x, y, alpha);
00166 }
00167
00175 void CGraphic::DrawFrame(unsigned frame, int x, int y) const
00176 {
00177 if (!UseOpenGL) {
00178 DrawSub((frame % (Surface->w / Width)) * Width,
00179 (frame / (Surface->w / Width)) * Height,
00180 Width, Height, x, y);
00181 } else {
00182 int sx, sy, ex, ey, n;
00183
00184 n = GraphicWidth / Width;
00185 sx = (frame % n) * Width;
00186 ex = sx + Width;
00187 sy = (frame / n) * Height;
00188 ey = sy + Height;
00189 DrawTexture(this, Textures, sx, sy, ex, ey, x, y, 0);
00190 }
00191 }
00192
00193 void CGraphic::DoDrawFrameClip(GLuint *textures,
00194 unsigned frame, int x, int y) const
00195 {
00196 int ox;
00197 int oy;
00198 int skip;
00199 int w;
00200 int h;
00201 int sx, sy, ex, ey, n;
00202
00203 n = GraphicWidth / Width;
00204 sx = (frame % n) * Width;
00205 ex = sx + Width;
00206 sy = (frame / n) * Height;
00207 ey = sy + Height;
00208
00209 w = Width;
00210 h = Height;
00211 CLIP_RECTANGLE_OFS(x, y, w, h, ox, oy, skip);
00212
00213 DrawTexture(this, textures, sx + ox, sy + oy, sx + ox + w, sy + oy + h, x, y, 0);
00214 }
00215
00223 void CGraphic::DrawFrameClip(unsigned frame, int x, int y) const
00224 {
00225 if (!UseOpenGL) {
00226 DrawSubClip((frame % (Surface->w / Width)) * Width,
00227 (frame / (Surface->w / Width)) * Height,
00228 Width, Height, x, y);
00229 } else {
00230 DoDrawFrameClip(Textures, frame, x, y);
00231 }
00232 }
00233
00234 void CGraphic::DrawFrameTrans(unsigned frame, int x, int y, int alpha) const
00235 {
00236 if (!UseOpenGL) {
00237 DrawSubTrans((frame % (Surface->w / Width)) * Width,
00238 (frame / (Surface->w / Width)) * Height,
00239 Width, Height, x, y, alpha);
00240 } else {
00241 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00242 glColor4ub(255, 255, 255, alpha);
00243 DrawFrame(frame, x, y);
00244 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00245 }
00246 }
00247
00248 void CGraphic::DrawFrameClipTrans(unsigned frame, int x, int y, int alpha) const
00249 {
00250 if (!UseOpenGL) {
00251 DrawSubClipTrans((frame % (Surface->w / Width)) * Width,
00252 (frame / (Surface->w / Width)) * Height,
00253 Width, Height, x, y, alpha);
00254 } else {
00255 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00256 glColor4ub(255, 255, 255, alpha);
00257 DrawFrameClip(frame, x, y);
00258 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00259 }
00260 }
00261
00270 void CPlayerColorGraphic::DrawPlayerColorFrameClip(int player, unsigned frame,
00271 int x, int y)
00272 {
00273 if (!UseOpenGL) {
00274 GraphicPlayerPixels(&Players[player], this);
00275 DrawFrameClip(frame, x, y);
00276 } else {
00277 if (!PlayerColorTextures[player]) {
00278 MakePlayerColorTexture(this, player);
00279 }
00280 DoDrawFrameClip(PlayerColorTextures[player], frame, x, y);
00281 }
00282 }
00283
00284
00285
00293 void CGraphic::DrawFrameX(unsigned frame, int x, int y) const
00294 {
00295 if (!UseOpenGL) {
00296 SDL_Rect srect;
00297 SDL_Rect drect;
00298
00299 srect.x = (SurfaceFlip->w - (frame % (SurfaceFlip->w /
00300 Width)) * Width) - Width;
00301 srect.y = (frame / (SurfaceFlip->w / Width)) * Height;
00302 srect.w = Width;
00303 srect.h = Height;
00304
00305 drect.x = x;
00306 drect.y = y;
00307
00308 SDL_BlitSurface(SurfaceFlip, &srect, TheScreen, &drect);
00309 } else {
00310 int sx, sy, ex, ey, n;
00311
00312 n = GraphicWidth / Width;
00313 sx = (frame % n) * Width;
00314 ex = sx + Width;
00315 sy = (frame / n) * Height;
00316 ey = sy + Height;
00317 DrawTexture(this, Textures, sx, sy, ex, ey, x, y, 1);
00318 }
00319 }
00320
00321 void CGraphic::DoDrawFrameClipX(GLuint *textures, unsigned frame,
00322 int x, int y) const
00323 {
00324 int ox;
00325 int oy;
00326 int skip;
00327 int w;
00328 int h;
00329 int sx, sy, ex, ey, n;
00330
00331 n = GraphicWidth / Width;
00332 sx = (frame % n) * Width;
00333 ex = sx + Width;
00334 sy = (frame / n) * Height;
00335 ey = sy + Height;
00336
00337 w = Width;
00338 h = Height;
00339 CLIP_RECTANGLE_OFS(x, y, w, h, ox, oy, skip);
00340
00341 if (w < Width) {
00342 if (ox == 0) {
00343 ox += Width - w;
00344 } else {
00345 ox = 0;
00346 }
00347 }
00348
00349 DrawTexture(this, textures, sx + ox, sy + oy, sx + ox + w, sy + oy + h, x, y, 1);
00350 }
00351
00359 void CGraphic::DrawFrameClipX(unsigned frame, int x, int y) const
00360 {
00361 if (!UseOpenGL) {
00362 SDL_Rect srect;
00363 SDL_Rect drect;
00364 int oldx;
00365 int oldy;
00366
00367 srect.x = (SurfaceFlip->w - (frame % (SurfaceFlip->w /
00368 Width)) * Width) - Width;
00369 srect.y = (frame / (SurfaceFlip->w / Width)) * Height;
00370 srect.w = Width;
00371 srect.h = Height;
00372
00373 oldx = x;
00374 oldy = y;
00375 CLIP_RECTANGLE(x, y, srect.w, srect.h);
00376 srect.x += x - oldx;
00377 srect.y += y - oldy;
00378
00379 drect.x = x;
00380 drect.y = y;
00381
00382 SDL_BlitSurface(SurfaceFlip, &srect, TheScreen, &drect);
00383 } else {
00384 DoDrawFrameClipX(Textures, frame, x, y);
00385 }
00386 }
00387
00388 void CGraphic::DrawFrameTransX(unsigned frame, int x, int y, int alpha) const
00389 {
00390 if (!UseOpenGL) {
00391 SDL_Rect srect;
00392 SDL_Rect drect;
00393 int oldalpha;
00394
00395 srect.x = (SurfaceFlip->w - (frame % (SurfaceFlip->w /
00396 Width)) * Width) - Width;
00397 srect.y = (frame / (SurfaceFlip->w / Width)) * Height;
00398 srect.w = Width;
00399 srect.h = Height;
00400
00401 drect.x = x;
00402 drect.y = y;
00403
00404 oldalpha = Surface->format->alpha;
00405 SDL_SetAlpha(Surface, SDL_SRCALPHA, alpha);
00406 SDL_BlitSurface(SurfaceFlip, &srect, TheScreen, &drect);
00407 SDL_SetAlpha(Surface, SDL_SRCALPHA, oldalpha);
00408 } else {
00409 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00410 glColor4ub(255, 255, 255, alpha);
00411 DrawFrameX(frame, x, y);
00412 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00413 }
00414 }
00415
00416 void CGraphic::DrawFrameClipTransX(unsigned frame, int x, int y, int alpha) const
00417 {
00418 if (!UseOpenGL) {
00419 SDL_Rect srect;
00420 SDL_Rect drect;
00421 int oldx;
00422 int oldy;
00423 int oldalpha;
00424
00425 srect.x = (SurfaceFlip->w - (frame % (SurfaceFlip->w /
00426 Width)) * Width) - Width;
00427 srect.y = (frame / (SurfaceFlip->w / Width)) * Height;
00428 srect.w = Width;
00429 srect.h = Height;
00430
00431 oldx = x;
00432 oldy = y;
00433 CLIP_RECTANGLE(x, y, srect.w, srect.h);
00434 srect.x += x - oldx;
00435 srect.y += y - oldy;
00436
00437 drect.x = x;
00438 drect.y = y;
00439
00440 oldalpha = Surface->format->alpha;
00441 SDL_SetAlpha(Surface, SDL_SRCALPHA, alpha);
00442 SDL_BlitSurface(SurfaceFlip, &srect, TheScreen, &drect);
00443 SDL_SetAlpha(Surface, SDL_SRCALPHA, oldalpha);
00444 } else {
00445 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00446 glColor4ub(255, 255, 255, alpha);
00447 DrawFrameClipX(frame, x, y);
00448 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00449 }
00450 }
00451
00460 void CPlayerColorGraphic::DrawPlayerColorFrameClipX(int player, unsigned frame,
00461 int x, int y)
00462 {
00463 if (!UseOpenGL) {
00464 GraphicPlayerPixels(&Players[player], this);
00465 DrawFrameClipX(frame, x, y);
00466 } else {
00467 if (!PlayerColorTextures[player]) {
00468 MakePlayerColorTexture(this, player);
00469 }
00470 DoDrawFrameClipX(PlayerColorTextures[player], frame, x, y);
00471 }
00472 }
00473
00474
00475
00476
00477
00487 CGraphic *CGraphic::New(const std::string &file, int w, int h)
00488 {
00489 if (file.empty()) {
00490 return new CGraphic;
00491 }
00492
00493 CGraphic *g = GraphicHash[file];
00494 if (!g) {
00495 g = new CGraphic;
00496 if (!g) {
00497 fprintf(stderr, "Out of memory\n");
00498 ExitFatal(-1);
00499 }
00500
00501 g->File = file;
00502 g->HashFile = g->File;
00503 g->Width = w;
00504 g->Height = h;
00505 GraphicHash[g->HashFile] = g;
00506 } else {
00507 ++g->Refs;
00508 Assert((w == 0 || g->Width == w) && (g->Height == h || h == 0));
00509 }
00510
00511 return g;
00512 }
00513
00523 CPlayerColorGraphic *CPlayerColorGraphic::New(const std::string &file, int w, int h)
00524 {
00525 if (file.empty()) {
00526 return new CPlayerColorGraphic;
00527 }
00528
00529 CPlayerColorGraphic *g = dynamic_cast<CPlayerColorGraphic *>(GraphicHash[file]);
00530 if (!g) {
00531 g = new CPlayerColorGraphic;
00532 if (!g) {
00533 fprintf(stderr, "Out of memory\n");
00534 ExitFatal(-1);
00535 }
00536
00537 g->File = file;
00538 g->HashFile = g->File;
00539 g->Width = w;
00540 g->Height = h;
00541 GraphicHash[g->HashFile] = g;
00542 } else {
00543 ++g->Refs;
00544 Assert((w == 0 || g->Width == w) && (g->Height == h || h == 0));
00545 }
00546
00547 return g;
00548 }
00549
00559 CGraphic *CGraphic::ForceNew(const std::string &file, int w, int h)
00560 {
00561 CGraphic *g = new CGraphic;
00562 if (!g) {
00563 fprintf(stderr, "Out of memory\n");
00564 ExitFatal(-1);
00565 }
00566 g->File = file;
00567 int bufSize = file.size() + 32;
00568 char *hashfile = new char[bufSize];
00569 sprintf_s(hashfile, bufSize, "%s%d", file.c_str(), HashCount++);
00570 g->HashFile = hashfile;
00571 delete[] hashfile;
00572 g->Width = w;
00573 g->Height = h;
00574 GraphicHash[g->HashFile] = g;
00575
00576 return g;
00577 }
00578
00582 CGraphic *CGraphic::Clone() const
00583 {
00584 CGraphic *g = CGraphic::ForceNew(this->File, this->Width, this->Height);
00585
00586 if (this->IsLoaded()) {
00587 g->Load();
00588 }
00589
00590 return g;
00591 }
00592
00603 CPlayerColorGraphic *CPlayerColorGraphic::ForceNew(const std::string &file, int w, int h)
00604 {
00605 CPlayerColorGraphic *g = new CPlayerColorGraphic;
00606 if (!g) {
00607 fprintf(stderr, "Out of memory\n");
00608 ExitFatal(-1);
00609 }
00610 g->File = file;
00611 size_t bufSize = file.size() + 32;
00612 char *hashfile = new char[bufSize];
00613 sprintf_s(hashfile, bufSize, "%s%d", file.c_str(), HashCount++);
00614 g->HashFile = hashfile;
00615 delete[] hashfile;
00616 g->Width = w;
00617 g->Height = h;
00618 GraphicHash[g->HashFile] = g;
00619
00620 return g;
00621 }
00622
00626 void CGraphic::Load()
00627 {
00628 if (Surface) {
00629 return;
00630 }
00631
00632
00633 if (LoadGraphicPNG(this) == -1) {
00634 fprintf(stderr, "Can't load the graphic `%s'\n", File.c_str());
00635 ExitFatal(-1);
00636 }
00637
00638 if (!Width) {
00639 Width = GraphicWidth;
00640 }
00641 if (!Height) {
00642 Height = GraphicHeight;
00643 }
00644
00645 Assert(Width <= GraphicWidth && Height <= GraphicHeight);
00646
00647 if ((GraphicWidth / Width) * Width != GraphicWidth ||
00648 (GraphicHeight / Height) * Height != GraphicHeight) {
00649 fprintf(stderr, "Invalid graphic (width, height) %s\n", File.c_str());
00650 fprintf(stderr, "Expected: (%d,%d) Found: (%d,%d)\n",
00651 Width, Height, GraphicWidth, GraphicHeight);
00652 ExitFatal(-1);
00653 }
00654
00655 NumFrames = GraphicWidth / Width * GraphicHeight / Height;
00656
00657 if (UseOpenGL) {
00658 MakeTexture(this);
00659 Graphics.push_back(this);
00660 }
00661 }
00662
00668 static void FreeSurface(SDL_Surface **surface)
00669 {
00670 if (!*surface) {
00671 return;
00672 }
00673
00674 unsigned char *pixels = NULL;
00675
00676 if ((*surface)->flags & SDL_PREALLOC) {
00677 pixels = (unsigned char *)(*surface)->pixels;
00678 }
00679
00680 SDL_FreeSurface(*surface);
00681 delete[] pixels;
00682 *surface = NULL;
00683 }
00684
00690 void CGraphic::Free(CGraphic *g)
00691 {
00692 if (!g) {
00693 return;
00694 }
00695
00696 Assert(g->Refs);
00697
00698 --g->Refs;
00699 if (!g->Refs) {
00700
00701 if (UseOpenGL) {
00702 if (g->Textures) {
00703 glDeleteTextures(g->NumTextures, g->Textures);
00704 delete[] g->Textures;
00705 }
00706 CPlayerColorGraphic *cg = dynamic_cast<CPlayerColorGraphic *>(g);
00707 if (cg) {
00708 for (int i = 0; i < PlayerMax; ++i) {
00709 if (cg->PlayerColorTextures[i]) {
00710 glDeleteTextures(cg->NumTextures, cg->PlayerColorTextures[i]);
00711 delete[] cg->PlayerColorTextures[i];
00712 }
00713 }
00714 }
00715
00716 Graphics.remove(g);
00717 }
00718
00719 FreeSurface(&g->Surface);
00720 FreeSurface(&g->SurfaceFlip);
00721
00722 if (!g->HashFile.empty()) {
00723 GraphicHash.erase(g->HashFile);
00724 }
00725 delete g;
00726 }
00727 }
00728
00732 void FreeOpenGLGraphics()
00733 {
00734 std::list<CGraphic *>::iterator i;
00735 for (i = Graphics.begin(); i != Graphics.end(); ++i) {
00736 if ((*i)->Textures) {
00737 glDeleteTextures((*i)->NumTextures, (*i)->Textures);
00738 }
00739 CPlayerColorGraphic *cg = dynamic_cast<CPlayerColorGraphic *>(*i);
00740 if (cg) {
00741 for (int j = 0; j < PlayerMax; ++j) {
00742 if (cg->PlayerColorTextures[j]) {
00743 glDeleteTextures(cg->NumTextures, cg->PlayerColorTextures[j]);
00744 }
00745 }
00746 }
00747 }
00748 }
00749
00753 void ReloadGraphics()
00754 {
00755 std::list<CGraphic *>::iterator i;
00756 for (i = Graphics.begin(); i != Graphics.end(); ++i) {
00757 if ((*i)->Textures) {
00758 delete[] (*i)->Textures;
00759 (*i)->Textures = NULL;
00760 MakeTexture(*i);
00761 }
00762 CPlayerColorGraphic *cg = dynamic_cast<CPlayerColorGraphic *>(*i);
00763 if (cg) {
00764 for (int j = 0; j < PlayerMax; ++j) {
00765 if (cg->PlayerColorTextures[j]) {
00766 delete[] cg->PlayerColorTextures[j];
00767 cg->PlayerColorTextures[j] = NULL;
00768 MakePlayerColorTexture(cg, j);
00769 }
00770 }
00771 }
00772 }
00773 }
00774
00778 void CGraphic::Flip()
00779 {
00780 if (UseOpenGL) {
00781 return;
00782 }
00783
00784 int i;
00785 int j;
00786 SDL_Surface *s;
00787
00788 if (SurfaceFlip) {
00789 return;
00790 }
00791
00792 s = SurfaceFlip = SDL_ConvertSurface(Surface, Surface->format, SDL_SWSURFACE);
00793 if (Surface->flags & SDL_SRCCOLORKEY) {
00794 SDL_SetColorKey(SurfaceFlip, SDL_SRCCOLORKEY | SDL_RLEACCEL,
00795 Surface->format->colorkey);
00796 }
00797
00798 SDL_LockSurface(Surface);
00799 SDL_LockSurface(s);
00800 switch (s->format->BytesPerPixel) {
00801 case 1:
00802 for (i = 0; i < s->h; ++i) {
00803 for (j = 0; j < s->w; ++j) {
00804 ((char *)s->pixels)[j + i * s->pitch] =
00805 ((char *)Surface->pixels)[s->w - j - 1 + i * Surface->pitch];
00806 }
00807 }
00808 break;
00809 case 3:
00810 for (i = 0; i < s->h; ++i) {
00811 for (j = 0; j < s->w; ++j) {
00812 memcpy(&((char *)s->pixels)[j + i * s->pitch],
00813 &((char *)Surface->pixels)[(s->w - j - 1) * 3 + i * Surface->pitch], 3);
00814 }
00815 }
00816 break;
00817 case 4:
00818 for (i = 0; i < s->h; ++i) {
00819 for (j = 0; j < s->w; ++j) {
00820 *(Uint32 *)&((char *)s->pixels)[j * 4 + i * s->pitch] =
00821 *(Uint32 *)&((char *)Surface->pixels)[(s->w - j - 1) * 4 + i * Surface->pitch];
00822 }
00823 }
00824 break;
00825 }
00826 SDL_UnlockSurface(Surface);
00827 SDL_UnlockSurface(s);
00828 }
00829
00833 void CGraphic::UseDisplayFormat()
00834 {
00835 if (UseOpenGL) {
00836 return;
00837 }
00838
00839 SDL_Surface *s;
00840
00841 s = Surface;
00842 if (s->format->Amask != 0) {
00843 Surface = SDL_DisplayFormatAlpha(s);
00844 } else {
00845 Surface = SDL_DisplayFormat(s);
00846 }
00847 SDL_FreeSurface(s);
00848
00849 if (SurfaceFlip) {
00850 s = SurfaceFlip;
00851 if (s->format->Amask != 0) {
00852 SurfaceFlip = SDL_DisplayFormatAlpha(s);
00853 } else {
00854 SurfaceFlip = SDL_DisplayFormat(s);
00855 }
00856 SDL_FreeSurface(s);
00857 }
00858 }
00859
00863 static int PowerOf2(int x)
00864 {
00865 int i;
00866 for (i = 1; i < x; i <<= 1) ;
00867 return i;
00868 }
00869
00879 static void MakeTextures2(CGraphic *g, GLuint texture, CUnitColors *colors,
00880 int ow, int oh)
00881 {
00882 int h;
00883 int w;
00884 unsigned char *tex;
00885 unsigned char *tp;
00886 const unsigned char *sp;
00887 int fl;
00888 Uint32 ckey;
00889 int useckey;
00890 int bpp;
00891 unsigned char alpha;
00892 Uint32 b;
00893 Uint32 c;
00894 Uint32 pc;
00895 SDL_PixelFormat *f;
00896 int maxw;
00897 int maxh;
00898
00899 fl = g->GraphicWidth / g->Width;
00900 useckey = g->Surface->flags & SDL_SRCCOLORKEY;
00901 f = g->Surface->format;
00902 bpp = f->BytesPerPixel;
00903 ckey = f->colorkey;
00904
00905 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00906 maxw = std::min(g->GraphicWidth - ow, GLMaxTextureSize);
00907 maxh = std::min(g->GraphicHeight - oh, GLMaxTextureSize);
00908 w = PowerOf2(maxw);
00909 h = PowerOf2(maxh);
00910 tex = new unsigned char[w * h * 4];
00911 memset(tex, 0, w * h * 4);
00912 if (g->Surface->flags & SDL_SRCALPHA) {
00913 alpha = f->alpha;
00914 } else {
00915 alpha = 0xff;
00916 }
00917
00918 SDL_LockSurface(g->Surface);
00919 glBindTexture(GL_TEXTURE_2D, texture);
00920 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00921 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00922 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00923 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00924 for (int i = 0; i < maxh; ++i) {
00925 sp = (const unsigned char *)g->Surface->pixels + ow * bpp +
00926 (oh + i) * g->Surface->pitch;
00927 tp = tex + i * w * 4;
00928 for (int j = 0; j < maxw; ++j) {
00929 if (bpp == 1) {
00930 if (useckey && *sp == ckey) {
00931 tp[3] = 0;
00932 } else {
00933 SDL_Color p = f->palette->colors[*sp];
00934 tp[0] = p.r;
00935 tp[1] = p.g;
00936 tp[2] = p.b;
00937 tp[3] = alpha;
00938 }
00939 if (colors) {
00940 for (int z = 0; z < PlayerColorIndexCount; ++z) {
00941 if (*sp == PlayerColorIndexStart + z) {
00942 SDL_Color p = colors->Colors[z];
00943 tp[0] = p.r;
00944 tp[1] = p.g;
00945 tp[2] = p.b;
00946 tp[3] = 0xff;
00947 break;
00948 }
00949 }
00950 }
00951 ++sp;
00952 } else {
00953 if (bpp == 4) {
00954 c = *(Uint32 *)sp;
00955 } else {
00956 c = (sp[f->Rshift >> 3] << f->Rshift) |
00957 (sp[f->Gshift >> 3] << f->Gshift) |
00958 (sp[f->Bshift >> 3] << f->Bshift);
00959 c |= ((alpha | (alpha << 8) | (alpha << 16) | (alpha << 24)) ^
00960 (f->Rmask | f->Gmask | f->Bmask));
00961 }
00962 *(Uint32 *)tp = c;
00963 if (colors) {
00964 b = (c & f->Bmask) >> f->Bshift;
00965 if (b && ((c & f->Rmask) >> f->Rshift) == 0 &&
00966 ((c & f->Gmask) >> f->Gshift) == b) {
00967 pc = ((colors->Colors[0].r * b / 255) << f->Rshift) |
00968 ((colors->Colors[0].g * b / 255) << f->Gshift) |
00969 ((colors->Colors[0].b * b / 255) << f->Bshift);
00970 if (bpp == 4) {
00971 pc |= (c & f->Amask);
00972 } else {
00973 pc |= (0xFFFFFFFF ^ (f->Rmask | f->Gmask | f->Bmask));
00974 }
00975 *(Uint32 *)tp = pc;
00976 }
00977 }
00978 sp += bpp;
00979 }
00980 tp += 4;
00981 }
00982 }
00983
00984 GLint internalformat = GL_RGBA;
00985 if (GLTextureCompressionSupported && UseGLTextureCompression) {
00986 internalformat = GL_COMPRESSED_RGBA;
00987 }
00988
00989 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
00990
00991 #ifdef DEBUG
00992 int x;
00993 if ((x = glGetError())) {
00994 DebugPrint("glTexImage2D(%x)\n" _C_ x);
00995 }
00996 #endif
00997 SDL_UnlockSurface(g->Surface);
00998 delete[] tex;
00999 }
01000
01008 static void MakeTextures(CGraphic *g, int player, CUnitColors *colors)
01009 {
01010 int i;
01011 int tw;
01012 int th;
01013 GLuint *textures;
01014
01015 tw = (g->GraphicWidth - 1) / GLMaxTextureSize + 1;
01016 th = (g->GraphicHeight - 1) / GLMaxTextureSize + 1;
01017
01018 i = g->GraphicWidth % GLMaxTextureSize;
01019 if (i == 0) {
01020 i = GLMaxTextureSize;
01021 }
01022 g->TextureWidth = (GLfloat)i / PowerOf2(i);
01023 i = g->GraphicHeight % GLMaxTextureSize;
01024 if (i == 0) {
01025 i = GLMaxTextureSize;
01026 }
01027 g->TextureHeight = (GLfloat)i / PowerOf2(i);
01028
01029 g->NumTextures = tw * th;
01030 if (g->NumTextures > 1) {
01031 tw = tw;
01032 }
01033 CPlayerColorGraphic *cg = dynamic_cast<CPlayerColorGraphic *>(g);
01034 if (!colors || !cg) {
01035 textures = g->Textures = new GLuint[g->NumTextures];
01036 glGenTextures(g->NumTextures, g->Textures);
01037 } else {
01038 textures = cg->PlayerColorTextures[player] = new GLuint[cg->NumTextures];
01039 glGenTextures(cg->NumTextures, cg->PlayerColorTextures[player]);
01040 }
01041
01042 for (int j = 0; j < th; ++j) {
01043 for (i = 0; i < tw; ++i) {
01044 MakeTextures2(g, textures[j * tw + i], colors, GLMaxTextureSize * i, GLMaxTextureSize * j);
01045 }
01046 }
01047 }
01048
01054 void MakeTexture(CGraphic *g)
01055 {
01056 if (g->Textures) {
01057 return;
01058 }
01059
01060 MakeTextures(g, 0, NULL);
01061 }
01062
01069 void MakePlayerColorTexture(CPlayerColorGraphic *g, int player)
01070 {
01071 if (g->PlayerColorTextures[player]) {
01072 return;
01073 }
01074
01075 MakeTextures(g, player, &Players[player].UnitColors);
01076 }
01077
01084 void CGraphic::Resize(int w, int h)
01085 {
01086 int i;
01087 int j;
01088 unsigned char *data;
01089 unsigned char *pixels;
01090 int x;
01091 int bpp;
01092
01093 Assert(Surface);
01094
01095 if (GraphicWidth == w && GraphicHeight == h) {
01096 return;
01097 }
01098
01099
01100
01101 if (Resized) {
01102 FreeSurface(&Surface);
01103 FreeSurface(&SurfaceFlip);
01104
01105 this->Width = this->Height = 0;
01106 this->Load();
01107
01108 Resized = false;
01109 if (GraphicWidth == w && GraphicHeight == h) {
01110 return;
01111 }
01112 }
01113
01114 Resized = true;
01115
01116 bpp = Surface->format->BytesPerPixel;
01117 if (bpp == 1) {
01118 SDL_Color pal[256];
01119 Uint32 ckey;
01120 int useckey;
01121
01122 SDL_LockSurface(Surface);
01123
01124 pixels = (unsigned char *)Surface->pixels;
01125 data = new unsigned char[w * h];
01126 x = 0;
01127
01128 for (i = 0; i < h; ++i) {
01129 for (j = 0; j < w; ++j) {
01130 data[x] = pixels[(i * Height / h) * Surface->pitch + j * Width / w];
01131 ++x;
01132 }
01133 }
01134
01135 SDL_UnlockSurface(Surface);
01136 memcpy(pal, Surface->format->palette->colors, sizeof(SDL_Color) * 256);
01137 useckey = Surface->flags & SDL_SRCCOLORKEY;
01138 ckey = Surface->format->colorkey;
01139 SDL_FreeSurface(Surface);
01140
01141 Surface = SDL_CreateRGBSurfaceFrom(data, w, h, 8, w, 0, 0, 0, 0);
01142 SDL_SetPalette(Surface, SDL_LOGPAL | SDL_PHYSPAL, pal, 0, 256);
01143 if (useckey) {
01144 SDL_SetColorKey(Surface, SDL_SRCCOLORKEY | SDL_RLEACCEL, ckey);
01145 }
01146 } else {
01147 int ix, iy;
01148 float fx, fy, fz;
01149 unsigned char *p1, *p2, *p3, *p4;
01150
01151 SDL_LockSurface(Surface);
01152
01153 pixels = (unsigned char *)Surface->pixels;
01154 data = new unsigned char[w * h * bpp];
01155 x = 0;
01156
01157 for (i = 0; i < h; ++i) {
01158 fy = (float)i * Height / h;
01159 iy = (int)fy;
01160 fy -= iy;
01161 for (j = 0; j < w; ++j) {
01162 fx = (float)j * Width / w;
01163 ix = (int)fx;
01164 fx -= ix;
01165 fz = (fx + fy) / 2;
01166
01167 p1 = &pixels[iy * Surface->pitch + ix * bpp];
01168 p2 = (iy != Surface->h - 1) ?
01169 &pixels[(iy + 1) * Surface->pitch + ix * bpp] :
01170 p1;
01171 p3 = (ix != Surface->w - 1) ?
01172 &pixels[iy * Surface->pitch + (ix + 1) * bpp] :
01173 p1;
01174 p4 = (iy != Surface->h - 1 && ix != Surface->w - 1) ?
01175 &pixels[(iy + 1) * Surface->pitch + (ix + 1) * bpp] :
01176 p1;
01177
01178 data[x * bpp + 0] = static_cast<unsigned char>(
01179 (p1[0] * (1 - fy) + p2[0] * fy +
01180 p1[0] * (1 - fx) + p3[0] * fx +
01181 p1[0] * (1 - fz) + p4[0] * fz) / 3.0 + .5);
01182 data[x * bpp + 1] = static_cast<unsigned char>(
01183 (p1[1] * (1 - fy) + p2[1] * fy +
01184 p1[1] * (1 - fx) + p3[1] * fx +
01185 p1[1] * (1 - fz) + p4[1] * fz) / 3.0 + .5);
01186 data[x * bpp + 2] = static_cast<unsigned char>(
01187 (p1[2] * (1 - fy) + p2[2] * fy +
01188 p1[2] * (1 - fx) + p3[2] * fx +
01189 p1[2] * (1 - fz) + p4[2] * fz) / 3.0 + .5);
01190 if (bpp == 4) {
01191 data[x * bpp + 3] = static_cast<unsigned char>(
01192 (p1[3] * (1 - fy) + p2[3] * fy +
01193 p1[3] * (1 - fx) + p3[3] * fx +
01194 p1[3] * (1 - fz) + p4[3] * fz) / 3.0 + .5);
01195 }
01196 ++x;
01197 }
01198 }
01199
01200 int Rmask = Surface->format->Rmask;
01201 int Gmask = Surface->format->Gmask;
01202 int Bmask = Surface->format->Bmask;
01203 int Amask = Surface->format->Amask;
01204
01205 SDL_UnlockSurface(Surface);
01206 SDL_FreeSurface(Surface);
01207
01208 Surface = SDL_CreateRGBSurfaceFrom(data, w, h, 8 * bpp, w * bpp,
01209 Rmask, Gmask, Bmask, Amask);
01210 }
01211
01212 Width = GraphicWidth = w;
01213 Height = GraphicHeight = h;
01214
01215 if (UseOpenGL) {
01216 glDeleteTextures(NumTextures, Textures);
01217 delete[] Textures;
01218 Textures = NULL;
01219 MakeTexture(this);
01220 }
01221 }
01222
01231 bool CGraphic::TransparentPixel(int x, int y)
01232 {
01233 unsigned char *p;
01234 int bpp;
01235 bool ret;
01236
01237 bpp = Surface->format->BytesPerPixel;
01238 if ((bpp == 1 && !(Surface->flags & SDL_SRCCOLORKEY)) || bpp == 3) {
01239 return false;
01240 }
01241
01242 ret = 0;
01243 SDL_LockSurface(Surface);
01244 p = (unsigned char *)Surface->pixels + y * Surface->pitch + x * bpp;
01245 if (bpp == 1) {
01246 if (*p == Surface->format->colorkey) {
01247 ret = true;
01248 }
01249 } else {
01250 if (p[Surface->format->Ashift >> 3] == 255) {
01251 ret = true;
01252 }
01253 }
01254 SDL_UnlockSurface(Surface);
01255
01256 return ret;
01257 }
01258
01264 void CGraphic::MakeShadow()
01265 {
01266 SDL_Color colors[256];
01267
01268
01269 memset(colors, 0, sizeof(colors));
01270
01271 SDL_SetPalette(Surface, SDL_LOGPAL | SDL_PHYSPAL, colors, 0, 256);
01272 SDL_SetAlpha(Surface, SDL_SRCALPHA | SDL_RLEACCEL, 128);
01273
01274 if (!UseOpenGL) {
01275 if (SurfaceFlip) {
01276 SDL_SetPalette(SurfaceFlip, SDL_LOGPAL | SDL_PHYSPAL, colors, 0, 256);
01277 SDL_SetAlpha(SurfaceFlip, SDL_SRCALPHA | SDL_RLEACCEL, 128);
01278 }
01279 }
01280 if (UseOpenGL) {
01281 if (Textures) {
01282 glDeleteTextures(NumTextures, Textures);
01283 delete[] Textures;
01284 Textures = NULL;
01285 }
01286 MakeTexture(this);
01287 }
01288 }
01289
01290 #ifdef DEBUG
01291 void FreeGraphics()
01292 {
01293 std::map<std::string, CGraphic *>::iterator i;
01294 while (!GraphicHash.empty()) {
01295 i = GraphicHash.begin();
01296 CGraphic::Free((*i).second);
01297 }
01298 }
01299 #endif
01300