hedgewars/uStore.pas
branchexperimental3D
changeset 4812 f924be23ffb4
parent 4347 0ddb100fea61
parent 4809 9c7d5f802618
child 4850 434cd1284204
equal deleted inserted replaced
4347:0ddb100fea61 4812:f924be23ffb4
    18 
    18 
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uStore;
    21 unit uStore;
    22 interface
    22 interface
    23 uses sysutils, uConsts, uTeams, SDLh, GLunit, uWorld;
    23 uses sysutils, uConsts, SDLh, GLunit, uTypes;
    24 
       
    25 
       
    26 var PixelFormat: PSDL_PixelFormat;
       
    27     SDLPrimSurface: PSDL_Surface;
       
    28     PauseTexture,
       
    29     SyncTexture,
       
    30     ConfirmTexture: PTexture;
       
    31     cScaleFactor: GLfloat;
       
    32     SupportNPOTT: Boolean;
       
    33     Step: LongInt;
       
    34     squaresize : LongInt;
       
    35     numsquares : LongInt;
       
    36     ProgrTex: PTexture;
       
    37     MissionIcons: PSDL_Surface;
       
    38     ropeIconTex: PTexture;
       
    39     rotationQt: GLfloat;
       
    40     wScreen: LongInt;
       
    41     hScreen: LongInt;
       
    42     framel, framer, depthl, depthr: GLuint;
       
    43     texl, texr: GLuint;
       
    44 
    24 
    45 procedure initModule;
    25 procedure initModule;
    46 procedure freeModule;
    26 procedure freeModule;
    47 
    27 
    48 procedure StoreLoad;
    28 procedure StoreLoad;
    49 procedure StoreRelease;
    29 procedure StoreRelease;
    50 procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
       
    51 procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
       
    52 procedure DrawSprite2(Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
       
    53 procedure DrawSpriteClipped(Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
       
    54 procedure DrawTexture(X, Y: LongInt; Texture: PTexture; Scale: GLfloat = 1.0);
       
    55 procedure DrawTextureF(Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
       
    56 procedure DrawRotatedTextureF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
       
    57 procedure DrawRotated(Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
       
    58 procedure DrawRotatedF(Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
       
    59 procedure DrawRotatedTex(Tex: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
       
    60 procedure DrawCentered(X, Top: LongInt; Source: PTexture);
       
    61 procedure DrawFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    62 procedure DrawFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    63 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
       
    64 procedure DrawLine(X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte); 
       
    65 procedure DrawFillRect(r: TSDL_Rect);
       
    66 procedure DrawCircle(X, Y, Radius: LongInt; Width: Single; r, g, b, a: Byte); 
       
    67 procedure DrawRoundRect(rect: PSDL_Rect; BorderColor, FillColor: Longword; Surface: PSDL_Surface; Clear: boolean);
       
    68 function  CheckCJKFont(s: ansistring; font: THWFont): THWFont;
       
    69 function  RenderStringTex(s: ansistring; Color: Longword; font: THWFont): PTexture;
       
    70 function  RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture;
       
    71 procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean);
       
    72 //procedure rotateSurface(Surface: PSDL_Surface);
       
    73 procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL
       
    74 procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt);
       
    75 procedure RenderHealth(var Hedgehog: THedgehog);
    30 procedure RenderHealth(var Hedgehog: THedgehog);
    76 procedure AddProgress;
    31 procedure AddProgress;
    77 procedure FinishProgress;
    32 procedure FinishProgress;
    78 function  LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
    33 function  LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
    79 procedure SetupOpenGL;
    34 procedure SetupOpenGL;
    80 procedure SetScale(f: GLfloat);
    35 procedure SetScale(f: GLfloat);
    81 function  RenderHelpWindow(caption, subcaption, description, extra: ansistring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
    36 function  RenderHelpWindow(caption, subcaption, description, extra: ansistring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
    82 procedure RenderWeaponTooltip(atype: TAmmoType);
    37 procedure RenderWeaponTooltip(atype: TAmmoType);
    83 procedure ShowWeaponTooltip(x, y: LongInt);
    38 procedure ShowWeaponTooltip(x, y: LongInt);
    84 procedure FreeWeaponTooltip;
    39 procedure FreeWeaponTooltip;
    85 procedure Tint(r, g, b, a: Byte); inline;
       
    86 procedure Tint(c: Longword); inline;
       
    87 
    40 
    88 implementation
    41 implementation
    89 uses uMisc, uConsole, uLocale, uMobile;
    42 uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands, uDebug;
    90 
    43 
    91 type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple);
    44 type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple);
    92 
    45 
    93 var HHTexture: PTexture;
    46 var MaxTextureSize: LongInt;
    94     MaxTextureSize: LongInt;
       
    95     cGPUVendor: TGPUVendor;
    47     cGPUVendor: TGPUVendor;
    96     lastTint: Longword;
       
    97 
       
    98 procedure Tint(r, g, b, a: Byte); inline;
       
    99 var nc: Longword;
       
   100 begin
       
   101 nc:= (a shl 24) or (b shl 16) or (g shl 8) or r;
       
   102 if nc = lastTint then
       
   103     exit;
       
   104 glColor4ub(r, g, b, a);
       
   105 lastTint:= nc;
       
   106 end;
       
   107 
       
   108 procedure Tint(c: Longword); inline;
       
   109 begin
       
   110 Tint(((c shr 16) and $FF), ((c shr 8) and $FF), (c and $FF), $FF);
       
   111 end;
       
   112 
       
   113 procedure DrawRoundRect(rect: PSDL_Rect; BorderColor, FillColor: Longword; Surface: PSDL_Surface; Clear: boolean);
       
   114 var r: TSDL_Rect;
       
   115 begin
       
   116 r:= rect^;
       
   117 if Clear then SDL_FillRect(Surface, @r, 0);
       
   118 
       
   119 BorderColor:= SDL_MapRGB(Surface^.format, BorderColor shr 16, BorderColor shr 8, BorderColor and $FF);
       
   120 FillColor:= SDL_MapRGB(Surface^.format, FillColor shr 16, FillColor shr 8, FillColor and $FF);
       
   121 
       
   122 r.y:= rect^.y + 1;
       
   123 r.h:= rect^.h - 2;
       
   124 SDL_FillRect(Surface, @r, BorderColor);
       
   125 r.x:= rect^.x + 1;
       
   126 r.w:= rect^.w - 2;
       
   127 r.y:= rect^.y;
       
   128 r.h:= rect^.h;
       
   129 SDL_FillRect(Surface, @r, BorderColor);
       
   130 r.x:= rect^.x + 2;
       
   131 r.y:= rect^.y + 1;
       
   132 r.w:= rect^.w - 4;
       
   133 r.h:= rect^.h - 2;
       
   134 SDL_FillRect(Surface, @r, FillColor);
       
   135 r.x:= rect^.x + 1;
       
   136 r.y:= rect^.y + 2;
       
   137 r.w:= rect^.w - 2;
       
   138 r.h:= rect^.h - 4;
       
   139 SDL_FillRect(Surface, @r, FillColor)
       
   140 end;
       
   141 
       
   142 function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
       
   143 var w, h: LongInt;
       
   144     tmpsurf: PSDL_Surface;
       
   145     clr: TSDL_Color;
       
   146     finalRect: TSDL_Rect;
       
   147 begin
       
   148 w:= 0; h:= 0; // avoid compiler hints
       
   149 TTF_SizeUTF8(Fontz[Font].Handle, Str2PChar(s), w, h);
       
   150 finalRect.x:= X;
       
   151 finalRect.y:= Y;
       
   152 finalRect.w:= w + FontBorder * 2 + 4;
       
   153 finalRect.h:= h + FontBorder * 2;
       
   154 DrawRoundRect(@finalRect, cWhiteColor, endian(cNearBlackColorChannels.value), Surface, true);
       
   155 clr.r:= (Color shr 16) and $FF;
       
   156 clr.g:= (Color shr 8) and $FF;
       
   157 clr.b:= Color and $FF;
       
   158 tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(s), clr);
       
   159 finalRect.x:= X + FontBorder + 2;
       
   160 finalRect.y:= Y + FontBorder;
       
   161 SDLTry(tmpsurf <> nil, true);
       
   162 SDL_UpperBlit(tmpsurf, nil, Surface, @finalRect);
       
   163 SDL_FreeSurface(tmpsurf);
       
   164 finalRect.x:= X;
       
   165 finalRect.y:= Y;
       
   166 finalRect.w:= w + FontBorder * 2 + 4;
       
   167 finalRect.h:= h + FontBorder * 2;
       
   168 WriteInRoundRect:= finalRect;
       
   169 end;
       
   170 
    48 
   171 function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
    49 function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
   172 var w, h: LongInt;
    50 var w, h: LongInt;
   173     tmpsurf: PSDL_Surface;
    51     tmpsurf: PSDL_Surface;
   174     clr: TSDL_Color;
    52     clr: TSDL_Color;
   240 
   118 
   241         DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true);
   119         DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true);
   242 
   120 
   243         // overwrite flag for cpu teams and keep players from using it
   121         // overwrite flag for cpu teams and keep players from using it
   244         if (Hedgehogs[0].Gear <> nil) and (Hedgehogs[0].BotLevel > 0) then
   122         if (Hedgehogs[0].Gear <> nil) and (Hedgehogs[0].BotLevel > 0) then
   245             Flag:= 'cpu'
   123             if Flag = 'hedgewars' then Flag:= 'cpu'
   246         else if Flag = 'cpu' then
   124         else if Flag = 'cpu' then
   247             Flag:= 'hedgewars';
   125             Flag:= 'hedgewars';
   248 
   126 
   249         flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone);
   127         flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone);
   250         if flagsurf = nil then
   128         if flagsurf = nil then
   394 
   272 
   395 AddProgress;
   273 AddProgress;
   396 for ii:= Low(TSprite) to High(TSprite) do
   274 for ii:= Low(TSprite) to High(TSprite) do
   397     with SpritesData[ii] do
   275     with SpritesData[ii] do
   398         // FIXME - add a sprite attribute
   276         // FIXME - add a sprite attribute
   399         if ((cReducedQuality and rqNoBackground) = 0) or (not (ii in [sprSky, sprSkyL, sprSkyR, sprHorizont, sprHorizontL, sprHorizontR, sprFlake, sprSplash, sprDroplet])) then // FIXME: hack
   277         if ((cReducedQuality and rqNoBackground) = 0) or // FIXME: should check for both rqNoBackground and rqKillFlakes
       
   278             (not (ii in [sprSky, sprSkyL, sprSkyR, sprHorizont, sprHorizontL, sprHorizontR, sprFlake, sprSplash, sprDroplet, sprSDSplash, sprSDDroplet]) or
       
   279             (((Theme = 'Snow') or (Theme = 'Christmas')) and ((ii = sprFlake) or (ii = sprSDFlake)))) then // FIXME: hack; also should checked against rqLowRes
   400         begin
   280         begin
   401             if AltPath = ptNone then
   281             if AltPath = ptNone then
   402                 if ii in [sprHorizontL, sprHorizontR, sprSkyL, sprSkyR] then // FIXME: hack
   282                 if ii in [sprHorizontL, sprHorizontR, sprSkyL, sprSkyR] then // FIXME: hack
   403                     tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent)
   283                     tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent)
   404                 else
   284                 else
   427                     Texture^.Scale:= 2
   307                     Texture^.Scale:= 2
   428                 end
   308                 end
   429                 else
   309                 else
   430                 begin
   310                 begin
   431                     Texture:= Surface2Tex(tmpsurf, false);
   311                     Texture:= Surface2Tex(tmpsurf, false);
   432                     if (ii = sprWater) and ((cReducedQuality and (rq2DWater or rqClampLess)) = 0) then // HACK: We should include some sprite attribute to define the texture wrap directions
   312                     // HACK: We should include some sprite attribute to define the texture wrap directions
       
   313                     if ((ii = sprWater) or (ii = sprSDWater)) and ((cReducedQuality and (rq2DWater or rqClampLess)) = 0) then
   433                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   314                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   434                 end;
   315                 end;
   435                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, priority);
   316                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, priority);
   436                 if saveSurf then
   317                 if saveSurf then
   437                     Surface:= tmpsurf else SDL_FreeSurface(tmpsurf)
   318                     Surface:= tmpsurf else SDL_FreeSurface(tmpsurf)
   481 {$IFDEF SDL_IMAGE_NEWER}
   362 {$IFDEF SDL_IMAGE_NEWER}
   482 IMG_Quit();
   363 IMG_Quit();
   483 {$ENDIF}
   364 {$ENDIF}
   484 end;
   365 end;
   485 
   366 
   486 procedure DrawFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
   487 begin
       
   488 DrawFromRect(X, Y, r^.w, r^.h, r, SourceTexture)
       
   489 end;
       
   490 
       
   491 procedure DrawFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
   492 var rr: TSDL_Rect;
       
   493     _l, _r, _t, _b: real;
       
   494     VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
       
   495 begin
       
   496 if (SourceTexture^.h = 0) or (SourceTexture^.w = 0) then exit;
       
   497 
       
   498 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   499 if (abs(X) > W) and ((abs(X + W / 2) - W / 2) > cScreenWidth / cScaleFactor) then
       
   500     exit;
       
   501 if (abs(Y) > H) and ((abs(Y + H / 2 - (0.5 * cScreenHeight)) - H / 2) > cScreenHeight / cScaleFactor) then
       
   502     exit;
       
   503 
       
   504 rr.x:= X;
       
   505 rr.y:= Y;
       
   506 rr.w:= W;
       
   507 rr.h:= H;
       
   508 
       
   509 _l:= r^.x / SourceTexture^.w * SourceTexture^.rx;
       
   510 _r:= (r^.x + r^.w) / SourceTexture^.w * SourceTexture^.rx;
       
   511 _t:= r^.y / SourceTexture^.h * SourceTexture^.ry;
       
   512 _b:= (r^.y + r^.h) / SourceTexture^.h * SourceTexture^.ry;
       
   513 
       
   514 glBindTexture(GL_TEXTURE_2D, SourceTexture^.id);
       
   515 
       
   516 VertexBuffer[0].X:= X;
       
   517 VertexBuffer[0].Y:= Y;
       
   518 VertexBuffer[1].X:= rr.w + X;
       
   519 VertexBuffer[1].Y:= Y;
       
   520 VertexBuffer[2].X:= rr.w + X;
       
   521 VertexBuffer[2].Y:= rr.h + Y;
       
   522 VertexBuffer[3].X:= X;
       
   523 VertexBuffer[3].Y:= rr.h + Y;
       
   524 
       
   525 TextureBuffer[0].X:= _l;
       
   526 TextureBuffer[0].Y:= _t;
       
   527 TextureBuffer[1].X:= _r;
       
   528 TextureBuffer[1].Y:= _t;
       
   529 TextureBuffer[2].X:= _r;
       
   530 TextureBuffer[2].Y:= _b;
       
   531 TextureBuffer[3].X:= _l;
       
   532 TextureBuffer[3].Y:= _b;
       
   533 
       
   534 
       
   535 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   536 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
   537 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   538 end;
       
   539 
       
   540 procedure DrawTexture(X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
       
   541 begin
       
   542 
       
   543 glPushMatrix;
       
   544 glTranslatef(X, Y, 0);
       
   545 glScalef(Scale, Scale, 1);
       
   546 
       
   547 glBindTexture(GL_TEXTURE_2D, Texture^.id);
       
   548 
       
   549 glVertexPointer(2, GL_FLOAT, 0, @Texture^.vb);
       
   550 glTexCoordPointer(2, GL_FLOAT, 0, @Texture^.tb);
       
   551 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(Texture^.vb));
       
   552 
       
   553 glPopMatrix
       
   554 end;
       
   555 
       
   556 procedure DrawTextureF(Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
       
   557 begin
       
   558     DrawRotatedTextureF(Texture, Scale, 0, 0, X, Y, Frame, Dir, w, h, 0)
       
   559 end;
       
   560 
       
   561 procedure DrawRotatedTextureF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
       
   562 var ft, fb, fl, fr: GLfloat;
       
   563     hw, nx, ny: LongInt;
       
   564     VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
       
   565 begin
       
   566 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   567 if (abs(X) > W) and ((abs(X + dir * OffsetX) - W / 2) * cScaleFactor > cScreenWidth) then
       
   568     exit;
       
   569 if (abs(Y) > H) and ((abs(Y + OffsetY - (0.5 * cScreenHeight)) - W / 2) * cScaleFactor > cScreenHeight) then
       
   570     exit;
       
   571 
       
   572 glPushMatrix;
       
   573 glTranslatef(X, Y, 0);
       
   574 
       
   575 if Dir < 0 then
       
   576    glRotatef(Angle, 0, 0, -1)
       
   577 else
       
   578    glRotatef(Angle, 0, 0,  1);
       
   579 
       
   580 glTranslatef(Dir*OffsetX, OffsetY, 0);
       
   581 glScalef(Scale, Scale, 1);
       
   582 
       
   583 // Any reason for this call? And why only in t direction, not s?
       
   584 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   585 
       
   586 if Dir < 0 then
       
   587     hw:= w div -2
       
   588 else
       
   589     hw:= w div 2;
       
   590 
       
   591 nx:= round(Texture^.w / w); // number of horizontal frames
       
   592 ny:= round(Texture^.h / h); // number of vertical frames
       
   593 
       
   594 ft:= (Frame mod ny) * Texture^.ry / ny;
       
   595 fb:= ((Frame mod ny) + 1) * Texture^.ry / ny;
       
   596 fl:= (Frame div ny) * Texture^.rx / nx;
       
   597 fr:= ((Frame div ny) + 1) * Texture^.rx / nx;
       
   598 
       
   599 glBindTexture(GL_TEXTURE_2D, Texture^.id);
       
   600 
       
   601 VertexBuffer[0].X:= -hw;
       
   602 VertexBuffer[0].Y:= w / -2;
       
   603 VertexBuffer[1].X:= hw;
       
   604 VertexBuffer[1].Y:= w / -2;
       
   605 VertexBuffer[2].X:= hw;
       
   606 VertexBuffer[2].Y:= w / 2;
       
   607 VertexBuffer[3].X:= -hw;
       
   608 VertexBuffer[3].Y:= w / 2;
       
   609 
       
   610 TextureBuffer[0].X:= fl;
       
   611 TextureBuffer[0].Y:= ft;
       
   612 TextureBuffer[1].X:= fr;
       
   613 TextureBuffer[1].Y:= ft;
       
   614 TextureBuffer[2].X:= fr;
       
   615 TextureBuffer[2].Y:= fb;
       
   616 TextureBuffer[3].X:= fl;
       
   617 TextureBuffer[3].Y:= fb;
       
   618 
       
   619 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   620 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
   621 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   622 
       
   623 glPopMatrix
       
   624 end;
       
   625 
       
   626 procedure DrawRotated(Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
       
   627 begin
       
   628     DrawRotatedTex(SpritesData[Sprite].Texture,
       
   629         SpritesData[Sprite].Width,
       
   630         SpritesData[Sprite].Height,
       
   631         X, Y, Dir, Angle)
       
   632 end;
       
   633 
       
   634 procedure DrawRotatedF(Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
       
   635 begin
       
   636 glPushMatrix;
       
   637 glTranslatef(X, Y, 0);
       
   638 
       
   639 if Dir < 0 then
       
   640    glRotatef(Angle, 0, 0, -1)
       
   641 else
       
   642    glRotatef(Angle, 0, 0,  1);
       
   643 if Dir < 0 then glScalef(-1.0, 1.0, 1.0);
       
   644 
       
   645 DrawSprite(Sprite, -SpritesData[Sprite].Width div 2, -SpritesData[Sprite].Height div 2, Frame);
       
   646 
       
   647 glPopMatrix
       
   648 end;
       
   649 
       
   650 procedure DrawRotatedTex(Tex: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
       
   651 var VertexBuffer: array [0..3] of TVertex2f;
       
   652 begin
       
   653 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   654 if (abs(X) > 2 * hw) and ((abs(X) - hw) > cScreenWidth / cScaleFactor) then
       
   655     exit;
       
   656 if (abs(Y) > 2 * hh) and ((abs(Y - 0.5 * cScreenHeight) - hh) > cScreenHeight / cScaleFactor) then
       
   657     exit;
       
   658 
       
   659 glPushMatrix;
       
   660 glTranslatef(X, Y, 0);
       
   661 
       
   662 if Dir < 0 then
       
   663    begin
       
   664    hw:= - hw;
       
   665    glRotatef(Angle, 0, 0, -1);
       
   666    end else
       
   667    glRotatef(Angle, 0, 0,  1);
       
   668 
       
   669 
       
   670 glBindTexture(GL_TEXTURE_2D, Tex^.id);
       
   671 
       
   672 VertexBuffer[0].X:= -hw;
       
   673 VertexBuffer[0].Y:= -hh;
       
   674 VertexBuffer[1].X:= hw;
       
   675 VertexBuffer[1].Y:= -hh;
       
   676 VertexBuffer[2].X:= hw;
       
   677 VertexBuffer[2].Y:= hh;
       
   678 VertexBuffer[3].X:= -hw;
       
   679 VertexBuffer[3].Y:= hh;
       
   680 
       
   681 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   682 glTexCoordPointer(2, GL_FLOAT, 0, @Tex^.tb);
       
   683 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   684 
       
   685 glPopMatrix
       
   686 end;
       
   687 
       
   688 procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
       
   689 begin
       
   690 r.y:= r.y + Height * Position;
       
   691 r.h:= Height;
       
   692 DrawFromRect(X, Y, @r, SpritesData[Sprite].Texture)
       
   693 end;
       
   694 
       
   695 procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
       
   696 var row, col, numFramesFirstCol: LongInt;
       
   697 begin
       
   698 numFramesFirstCol:= SpritesData[Sprite].imageHeight div SpritesData[Sprite].Height;
       
   699 row:= Frame mod numFramesFirstCol;
       
   700 col:= Frame div numFramesFirstCol;
       
   701 DrawSprite2 (Sprite, X, Y, col, row);
       
   702 end;
       
   703 
       
   704 procedure DrawSpriteClipped(Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
       
   705 var r: TSDL_Rect;
       
   706 begin
       
   707 r.x:= 0;
       
   708 r.y:= 0;
       
   709 r.w:= SpritesData[Sprite].Width;
       
   710 r.h:= SpritesData[Sprite].Height;
       
   711 
       
   712 if (X < LeftX) then
       
   713     r.x:= LeftX - X;
       
   714 if (Y < TopY) then
       
   715     r.y:= TopY - Y;
       
   716 
       
   717 if (Y + SpritesData[Sprite].Height > BottomY) then
       
   718     r.h:= BottomY - Y + 1;
       
   719 if (X + SpritesData[Sprite].Width > RightX) then
       
   720     r.w:= RightX - X + 1;
       
   721 
       
   722 dec(r.h, r.y);
       
   723 dec(r.w, r.x);
       
   724 
       
   725 DrawFromRect(X + r.x, Y + r.y, @r, SpritesData[Sprite].Texture)
       
   726 end;
       
   727 
       
   728 procedure DrawSprite2(Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
       
   729 var r: TSDL_Rect;
       
   730 begin
       
   731     r.x:= FrameX * SpritesData[Sprite].Width;
       
   732     r.w:= SpritesData[Sprite].Width;
       
   733     r.y:= FrameY * SpritesData[Sprite].Height;
       
   734     r.h:= SpritesData[Sprite].Height;
       
   735     DrawFromRect(X, Y, @r, SpritesData[Sprite].Texture)
       
   736 end;
       
   737 
       
   738 procedure DrawCentered(X, Top: LongInt; Source: PTexture);
       
   739 var scale: GLfloat;
       
   740 begin
       
   741     if (Source^.w + 20) > cScreenWidth then
       
   742         scale:= cScreenWidth / (Source^.w + 20)
       
   743     else
       
   744         scale:= 1.0;
       
   745     DrawTexture(X - round(Source^.w * scale) div 2, Top, Source, scale)
       
   746 end;
       
   747 
       
   748 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
       
   749 const VertexBuffer: array [0..3] of TVertex2f = (
       
   750         (x: -16; y: -16),
       
   751         (x:  16; y: -16),
       
   752         (x:  16; y:  16),
       
   753         (x: -16; y:  16));
       
   754 var l, r, t, b: real;
       
   755     TextureBuffer: array [0..3] of TVertex2f;
       
   756 begin
       
   757 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   758 if (abs(X) > 32) and ((abs(X) - 16) * cScaleFactor > cScreenWidth) then
       
   759     exit;
       
   760 if (abs(Y) > 32) and ((abs(Y - 0.5 * cScreenHeight) - 16) * cScaleFactor > cScreenHeight) then
       
   761     exit;
       
   762 
       
   763 t:= Pos * 32 / HHTexture^.h;
       
   764 b:= (Pos + 1) * 32 / HHTexture^.h;
       
   765 
       
   766 if Dir = -1 then
       
   767    begin
       
   768    l:= (Step + 1) * 32 / HHTexture^.w;
       
   769    r:= Step * 32 / HHTexture^.w
       
   770    end else
       
   771    begin
       
   772    l:= Step * 32 / HHTexture^.w;
       
   773    r:= (Step + 1) * 32 / HHTexture^.w
       
   774    end;
       
   775 
       
   776 
       
   777 glPushMatrix();
       
   778 glTranslatef(X, Y, 0);
       
   779 glRotatef(Angle, 0, 0, 1);
       
   780 
       
   781 glBindTexture(GL_TEXTURE_2D, HHTexture^.id);
       
   782 
       
   783 TextureBuffer[0].X:= l;
       
   784 TextureBuffer[0].Y:= t;
       
   785 TextureBuffer[1].X:= r;
       
   786 TextureBuffer[1].Y:= t;
       
   787 TextureBuffer[2].X:= r;
       
   788 TextureBuffer[2].Y:= b;
       
   789 TextureBuffer[3].X:= l;
       
   790 TextureBuffer[3].Y:= b;
       
   791 
       
   792 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   793 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
   794 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   795 
       
   796 glPopMatrix
       
   797 end;
       
   798 
       
   799 procedure DrawLine(X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
       
   800 var VertexBuffer: array [0..3] of TVertex2f;
       
   801 begin
       
   802     glDisable(GL_TEXTURE_2D);
       
   803     glEnable(GL_LINE_SMOOTH);
       
   804 
       
   805     glPushMatrix;
       
   806     glTranslatef(WorldDx, WorldDy, 0);
       
   807     glLineWidth(Width);
       
   808 
       
   809     Tint(r, g, b, a);
       
   810     VertexBuffer[0].X:= X0;
       
   811     VertexBuffer[0].Y:= Y0;
       
   812     VertexBuffer[1].X:= X1;
       
   813     VertexBuffer[1].Y:= Y1;
       
   814 
       
   815     glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   816     glDrawArrays(GL_LINES, 0, Length(VertexBuffer));
       
   817     Tint($FF, $FF, $FF, $FF);
       
   818     
       
   819     glPopMatrix;
       
   820     
       
   821     glEnable(GL_TEXTURE_2D);
       
   822     glDisable(GL_LINE_SMOOTH);
       
   823 end;
       
   824 
       
   825 procedure DrawFillRect(r: TSDL_Rect);
       
   826 var VertexBuffer: array [0..3] of TVertex2f;
       
   827 begin
       
   828 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   829 if (abs(r.x) > r.w) and ((abs(r.x + r.w / 2) - r.w / 2) * cScaleFactor > cScreenWidth) then
       
   830     exit;
       
   831 if (abs(r.y) > r.h) and ((abs(r.y + r.h / 2 - (0.5 * cScreenHeight)) - r.h / 2) * cScaleFactor > cScreenHeight) then
       
   832     exit;
       
   833 
       
   834 glDisable(GL_TEXTURE_2D);
       
   835 
       
   836 Tint($00, $00, $00, $80);
       
   837 
       
   838 VertexBuffer[0].X:= r.x;
       
   839 VertexBuffer[0].Y:= r.y;
       
   840 VertexBuffer[1].X:= r.x + r.w;
       
   841 VertexBuffer[1].Y:= r.y;
       
   842 VertexBuffer[2].X:= r.x + r.w;
       
   843 VertexBuffer[2].Y:= r.y + r.h;
       
   844 VertexBuffer[3].X:= r.x;
       
   845 VertexBuffer[3].Y:= r.y + r.h;
       
   846 
       
   847 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   848 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   849 
       
   850 Tint($FF, $FF, $FF, $FF);
       
   851 glEnable(GL_TEXTURE_2D)
       
   852 end;
       
   853 
       
   854 procedure DrawCircle(X, Y, Radius: LongInt; Width: Single; r, g, b, a: Byte); 
       
   855 var
       
   856     i: LongInt;
       
   857     CircleVertex: array [0..359] of TVertex2f;
       
   858 begin
       
   859     for i := 0 to 359 do begin
       
   860         CircleVertex[i].X := X + Radius*cos(i*pi/180);
       
   861         CircleVertex[i].Y := Y + Radius*sin(i*pi/180);
       
   862     end;
       
   863     glDisable(GL_TEXTURE_2D);
       
   864     glEnable(GL_LINE_SMOOTH);
       
   865     glPushMatrix;
       
   866     glLineWidth(Width);
       
   867     Tint(r, g, b, a);
       
   868     glVertexPointer(2, GL_FLOAT, 0, @CircleVertex[0]);
       
   869     glDrawArrays(GL_LINE_LOOP, 0, 360);
       
   870     Tint($FF, $FF, $FF, $FF);
       
   871     glPopMatrix;
       
   872     glEnable(GL_TEXTURE_2D);
       
   873     glDisable(GL_LINE_SMOOTH);
       
   874 end;
       
   875 
       
   876 procedure StoreRelease;
   367 procedure StoreRelease;
   877 var ii: TSprite;
   368 var ii: TSprite;
   878 begin
   369 begin
   879     for ii:= Low(TSprite) to High(TSprite) do
   370     for ii:= Low(TSprite) to High(TSprite) do
   880     begin
   371     begin
   899     end
   390     end
   900 {$ENDIF}
   391 {$ENDIF}
   901 end;
   392 end;
   902 
   393 
   903 
   394 
   904 function CheckCJKFont(s: ansistring; font: THWFont): THWFont;
       
   905 var l, i : LongInt;
       
   906     u: WideChar;
       
   907     tmpstr: array[0..256] of WideChar;
       
   908 begin
       
   909 
       
   910 {$IFNDEF IPHONEOS}
       
   911 // remove chinese fonts for now
       
   912 if (font >= CJKfnt16) or (length(s) = 0) then
       
   913 {$ENDIF}
       
   914     exit(font);
       
   915 
       
   916 l:= Utf8ToUnicode(@tmpstr, Str2PChar(s), length(s))-1;
       
   917 i:= 0;
       
   918 while i < l do
       
   919     begin
       
   920     u:= tmpstr[i];
       
   921     if (#$2E80  <= u) and  (
       
   922                            (u <= #$2FDF )  or // CJK Radicals Supplement / Kangxi Radicals
       
   923        ((#$2FF0  <= u) and (u <= #$303F))  or // Ideographic Description Characters / CJK Radicals Supplement
       
   924        ((#$31C0  <= u) and (u <= #$31EF))  or // CJK Strokes
       
   925        ((#$3200  <= u) and (u <= #$4DBF))  or // Enclosed CJK Letters and Months / CJK Compatibility / CJK Unified Ideographs Extension A
       
   926        ((#$4E00  <= u) and (u <= #$9FFF))  or // CJK Unified Ideographs
       
   927        ((#$F900  <= u) and (u <= #$FAFF))  or // CJK Compatibility Ideographs
       
   928        ((#$FE30  <= u) and (u <= #$FE4F)))    // CJK Compatibility Forms
       
   929        then exit(THWFont( ord(font) + ((ord(High(THWFont))+1) div 2) ));
       
   930     inc(i)
       
   931     end;
       
   932 exit(font);
       
   933 (* two more to check. pascal WideChar is only 16 bit though
       
   934        ((#$20000 <= u) and (u >= #$2A6DF)) or // CJK Unified Ideographs Extension B
       
   935        ((#$2F800 <= u) and (u >= #$2FA1F)))   // CJK Compatibility Ideographs Supplement *)
       
   936 end;
       
   937 
       
   938 function  RenderStringTex(s: ansistring; Color: Longword; font: THWFont): PTexture;
       
   939 var w, h: LongInt;
       
   940     finalSurface: PSDL_Surface;
       
   941 begin
       
   942 if length(s) = 0 then s:= ' ';
       
   943 font:= CheckCJKFont(s, font);
       
   944 w:= 0; h:= 0; // avoid compiler hints
       
   945 TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), w, h);
       
   946 
       
   947 finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w + FontBorder * 2 + 4, h + FontBorder * 2,
       
   948          32, RMask, GMask, BMask, AMask);
       
   949 
       
   950 TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true);
       
   951 
       
   952 WriteInRoundRect(finalSurface, 0, 0, Color, font, s);
       
   953 
       
   954 TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
       
   955 
       
   956 RenderStringTex:= Surface2Tex(finalSurface, false);
       
   957 
       
   958 SDL_FreeSurface(finalSurface);
       
   959 end;
       
   960 
       
   961 function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture;
       
   962 var textWidth, textHeight, x, y, w, h, i, j, pos, prevpos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt;
       
   963     finalSurface, tmpsurf, rotatedEdge: PSDL_Surface;
       
   964     rect: TSDL_Rect;
       
   965     chars: TSysCharSet = [#9,' ','.',';',':','?','!',','];
       
   966     substr: shortstring;
       
   967     edge, corner, tail: TSPrite;
       
   968 begin
       
   969 
       
   970 case SpeechType of
       
   971     1: begin;
       
   972        edge:= sprSpeechEdge;
       
   973        corner:= sprSpeechCorner;
       
   974        tail:= sprSpeechTail;
       
   975        end;
       
   976     2: begin;
       
   977        edge:= sprThoughtEdge;
       
   978        corner:= sprThoughtCorner;
       
   979        tail:= sprThoughtTail;
       
   980        end;
       
   981     3: begin;
       
   982        edge:= sprShoutEdge;
       
   983        corner:= sprShoutCorner;
       
   984        tail:= sprShoutTail;
       
   985        end;
       
   986     end;
       
   987 edgeHeight:= SpritesData[edge].Height;
       
   988 edgeWidth:= SpritesData[edge].Width;
       
   989 cornerWidth:= SpritesData[corner].Width;
       
   990 cornerHeight:= SpritesData[corner].Height;
       
   991 // This one screws up WrapText
       
   992 //s:= 'This is the song that never ends.  ''cause it goes on and on my friends. Some people, started singing it not knowing what it was. And they''ll just go on singing it forever just because... This is the song that never ends...';
       
   993 // This one does not
       
   994 //s:= 'This is the song that never ends.  cause it goes on and on my friends. Some people, started singing it not knowing what it was. And they will go on singing it forever just because... This is the song that never ends... ';
       
   995 
       
   996 numLines:= 0;
       
   997 
       
   998 if length(s) = 0 then s:= '...';
       
   999 font:= CheckCJKFont(s, font);
       
  1000 w:= 0; h:= 0; // avoid compiler hints
       
  1001 TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), w, h);
       
  1002 if w<8 then w:= 8;
       
  1003 j:= 0;
       
  1004 if (length(s) > 20) then
       
  1005     begin
       
  1006     w:= 0;
       
  1007     i:= round(Sqrt(length(s)) * 2);
       
  1008     s:= WrapText(s, #1, chars, i);
       
  1009     pos:= 1; prevpos:= 0; line:= 0;
       
  1010 // Find the longest line for the purposes of centring the text.  Font dependant.
       
  1011     while pos <= length(s) do
       
  1012         begin
       
  1013         if (s[pos] = #1) or (pos = length(s)) then
       
  1014             begin
       
  1015             inc(numlines);
       
  1016             if s[pos] <> #1 then inc(pos);
       
  1017             while s[prevpos+1] = ' ' do inc(prevpos);
       
  1018             substr:= copy(s, prevpos+1, pos-prevpos-1);
       
  1019             i:= 0; j:= 0;
       
  1020             TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(substr), i, j);
       
  1021             if i > w then w:= i;
       
  1022             prevpos:= pos;
       
  1023             end;
       
  1024         inc(pos);
       
  1025         end;
       
  1026     end
       
  1027 else numLines := 1;
       
  1028 
       
  1029 textWidth:=((w-(cornerWidth-edgeWidth)*2) div edgeWidth)*edgeWidth+edgeWidth;
       
  1030 textHeight:=(((numlines * h + 2)-((cornerHeight-edgeWidth)*2)) div edgeWidth)*edgeWidth;
       
  1031 
       
  1032 textHeight:=max(textHeight,edgeWidth);
       
  1033 //textWidth:=max(textWidth,SpritesData[tail].Width);
       
  1034 rect.x:= 0;
       
  1035 rect.y:= 0;
       
  1036 rect.w:= textWidth + (cornerWidth * 2);
       
  1037 rect.h:= textHeight + cornerHeight*2 - edgeHeight + SpritesData[tail].Height;
       
  1038 //s:= inttostr(w) + ' ' + inttostr(numlines) + ' ' + inttostr(rect.x) + ' '+inttostr(rect.y) + ' ' + inttostr(rect.w) + ' ' + inttostr(rect.h);
       
  1039 
       
  1040 finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, rect.h, 32, RMask, GMask, BMask, AMask);
       
  1041 
       
  1042 TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true);
       
  1043 
       
  1044 //////////////////////////////// CORNERS ///////////////////////////////
       
  1045 copyToXY(SpritesData[corner].Surface, finalSurface, 0, 0); /////////////////// NW
       
  1046 
       
  1047 flipSurface(SpritesData[corner].Surface, true); // store all 4 versions in memory to avoid repeated flips?
       
  1048 x:= 0;
       
  1049 y:= textHeight + cornerHeight -1;
       
  1050 copyToXY(SpritesData[corner].Surface, finalSurface, x, y); /////////////////// SW
       
  1051 
       
  1052 flipSurface(SpritesData[corner].Surface, false);
       
  1053 x:= rect.w-cornerWidth-1;
       
  1054 y:= textHeight + cornerHeight -1;
       
  1055 copyToXY(SpritesData[corner].Surface, finalSurface, x, y); /////////////////// SE
       
  1056 
       
  1057 flipSurface(SpritesData[corner].Surface, true);
       
  1058 x:= rect.w-cornerWidth-1;
       
  1059 y:= 0;
       
  1060 copyToXY(SpritesData[corner].Surface, finalSurface, x, y); /////////////////// NE
       
  1061 flipSurface(SpritesData[corner].Surface, false); // restore original position
       
  1062 //////////////////////////////// END CORNERS ///////////////////////////////
       
  1063 
       
  1064 //////////////////////////////// EDGES //////////////////////////////////////
       
  1065 x:= cornerWidth;
       
  1066 y:= 0;
       
  1067 while x < rect.w-cornerWidth-1 do
       
  1068     begin
       
  1069     copyToXY(SpritesData[edge].Surface, finalSurface, x, y); ///////////////// top edge
       
  1070     inc(x,edgeWidth);
       
  1071     end;
       
  1072 flipSurface(SpritesData[edge].Surface, true);
       
  1073 x:= cornerWidth;
       
  1074 y:= textHeight + cornerHeight*2 - edgeHeight-1;
       
  1075 while x < rect.w-cornerWidth-1 do
       
  1076     begin
       
  1077     copyToXY(SpritesData[edge].Surface, finalSurface, x, y); ///////////////// bottom edge
       
  1078     inc(x,edgeWidth);
       
  1079     end;
       
  1080 flipSurface(SpritesData[edge].Surface, true); // restore original position
       
  1081 
       
  1082 rotatedEdge:= SDL_CreateRGBSurface(SDL_SWSURFACE, edgeHeight, edgeWidth, 32, RMask, GMask, BMask, AMask);
       
  1083 x:= rect.w - edgeHeight - 1;
       
  1084 y:= cornerHeight;
       
  1085 //// initially was going to rotate in place, but the SDL spec claims width/height are read only
       
  1086 copyRotatedSurface(SpritesData[edge].Surface,rotatedEdge);
       
  1087 while y < textHeight + cornerHeight do
       
  1088     begin
       
  1089     copyToXY(rotatedEdge, finalSurface, x, y);
       
  1090     inc(y,edgeWidth);
       
  1091     end;
       
  1092 flipSurface(rotatedEdge, false); // restore original position
       
  1093 x:= 0;
       
  1094 y:= cornerHeight;
       
  1095 while y < textHeight + cornerHeight do
       
  1096     begin
       
  1097     copyToXY(rotatedEdge, finalSurface, x, y);
       
  1098     inc(y,edgeWidth);
       
  1099     end;
       
  1100 //////////////////////////////// END EDGES //////////////////////////////////////
       
  1101 
       
  1102 x:= cornerWidth;
       
  1103 y:= textHeight + cornerHeight * 2 - edgeHeight - 1;
       
  1104 copyToXY(SpritesData[tail].Surface, finalSurface, x, y);
       
  1105 
       
  1106 rect.x:= edgeHeight;
       
  1107 rect.y:= edgeHeight;
       
  1108 rect.w:= rect.w - edgeHeight * 2;
       
  1109 rect.h:= textHeight + cornerHeight * 2 - edgeHeight * 2;
       
  1110 i:= rect.w;
       
  1111 j:= rect.h;
       
  1112 SDL_FillRect(finalSurface, @rect, cWhiteColor);
       
  1113 
       
  1114 pos:= 1; prevpos:= 0; line:= 0;
       
  1115 while pos <= length(s) do
       
  1116     begin
       
  1117     if (s[pos] = #1) or (pos = length(s)) then
       
  1118         begin
       
  1119         if s[pos] <> #1 then inc(pos);
       
  1120         while s[prevpos+1] = ' 'do inc(prevpos);
       
  1121         substr:= copy(s, prevpos+1, pos-prevpos-1);
       
  1122         if Length(substr) <> 0 then
       
  1123            begin
       
  1124            tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(substr), cNearBlackColorChannels);
       
  1125            rect.x:= edgeHeight + 1 + ((i - w) div 2);
       
  1126            // trying to more evenly position the text, vertically
       
  1127            rect.y:= edgeHeight + ((j-(numLines*h)) div 2) + line * h;
       
  1128            SDLTry(tmpsurf <> nil, true);
       
  1129            SDL_UpperBlit(tmpsurf, nil, finalSurface, @rect);
       
  1130            SDL_FreeSurface(tmpsurf);
       
  1131            inc(line);
       
  1132            prevpos:= pos;
       
  1133            end;
       
  1134         end;
       
  1135     inc(pos);
       
  1136     end;
       
  1137 
       
  1138 //TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
       
  1139 RenderSpeechBubbleTex:= Surface2Tex(finalSurface, true);
       
  1140 
       
  1141 SDL_FreeSurface(rotatedEdge);
       
  1142 SDL_FreeSurface(finalSurface);
       
  1143 end;
       
  1144 
       
  1145 procedure RenderHealth(var Hedgehog: THedgehog);
   395 procedure RenderHealth(var Hedgehog: THedgehog);
  1146 var s: shortstring;
   396 var s: shortstring;
  1147 begin
   397 begin
  1148     str(Hedgehog.Gear^.Health, s);
   398     str(Hedgehog.Gear^.Health, s);
  1149     if Hedgehog.HealthTagTex <> nil then
   399     if Hedgehog.HealthTagTex <> nil then
  1153 
   403 
  1154 function  LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
   404 function  LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface;
  1155 var tmpsurf: PSDL_Surface;
   405 var tmpsurf: PSDL_Surface;
  1156     s: shortstring;
   406     s: shortstring;
  1157 begin
   407 begin
  1158     WriteToConsole(msgLoading + filename + '.png [flags: ' + inttostr(imageFlags) + ']');
   408     WriteToConsole(msgLoading + filename + '.png [flags: ' + inttostr(imageFlags) + '] ');
  1159 
   409 
  1160     s:= filename + '.png';
   410     s:= filename + '.png';
  1161     tmpsurf:= IMG_Load(Str2PChar(s));
   411     tmpsurf:= IMG_Load(Str2PChar(s));
  1162 
   412 
  1163     if tmpsurf = nil then
   413     if tmpsurf = nil then
  1406     WriteLnToConsole('Freeing progress surface... ');
   656     WriteLnToConsole('Freeing progress surface... ');
  1407     FreeTexture(ProgrTex);
   657     FreeTexture(ProgrTex);
  1408     perfExt_FinishProgress();
   658     perfExt_FinishProgress();
  1409 end;
   659 end;
  1410 
   660 
  1411 procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean);
       
  1412 var y, x, i, j: LongInt;
       
  1413     tmpPixel: Longword;
       
  1414     pixels: PLongWordArray;
       
  1415 begin
       
  1416 TryDo(Surface^.format^.BytesPerPixel = 4, 'flipSurface failed, expecting 32 bit surface', true);
       
  1417 pixels:= Surface^.pixels;
       
  1418 if Vertical then
       
  1419    for y := 0 to (Surface^.h div 2) - 1 do
       
  1420        for x := 0 to Surface^.w - 1 do
       
  1421            begin
       
  1422            i:= y * Surface^.w + x;
       
  1423            j:= (Surface^.h - y - 1) * Surface^.w + x;
       
  1424            tmpPixel:= pixels^[i];
       
  1425            pixels^[i]:= pixels^[j];
       
  1426            pixels^[j]:= tmpPixel;
       
  1427            end
       
  1428 else
       
  1429    for x := 0 to (Surface^.w div 2) - 1 do
       
  1430        for y := 0 to Surface^.h -1 do
       
  1431            begin
       
  1432            i:= y*Surface^.w + x;
       
  1433            j:= y*Surface^.w + (Surface^.w - x - 1);
       
  1434            tmpPixel:= pixels^[i];
       
  1435            pixels^[i]:= pixels^[j];
       
  1436            pixels^[j]:= tmpPixel;
       
  1437            end;
       
  1438 end;
       
  1439 
       
  1440 procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt);
       
  1441 var srcX, srcY, i, j, maxDest: LongInt;
       
  1442     srcPixels, destPixels: PLongWordArray;
       
  1443     r0, g0, b0, a0, r1, g1, b1, a1: Byte;
       
  1444 begin
       
  1445 maxDest:= (dest^.pitch div 4) * dest^.h;
       
  1446 srcPixels:= src^.pixels;
       
  1447 destPixels:= dest^.pixels;
       
  1448 
       
  1449 for srcX:= 0 to src^.w - 1 do
       
  1450    for srcY:= 0 to src^.h - 1 do
       
  1451       begin
       
  1452       i:= (destY + srcY) * (dest^.pitch div 4) + destX + srcX;
       
  1453       j:= srcY * (src^.pitch div 4) + srcX;
       
  1454       if (i < maxDest) and (srcPixels^[j] and AMask <> 0) then
       
  1455          begin
       
  1456          SDL_GetRGBA(destPixels^[i], dest^.format, @r0, @g0, @b0, @a0);
       
  1457          SDL_GetRGBA(srcPixels^[j], src^.format, @r1, @g1, @b1, @a1);
       
  1458          r0:= (r0 * (255 - LongInt(a1)) + r1 * LongInt(a1)) div 255;
       
  1459          g0:= (g0 * (255 - LongInt(a1)) + g1 * LongInt(a1)) div 255;
       
  1460          b0:= (b0 * (255 - LongInt(a1)) + b1 * LongInt(a1)) div 255;
       
  1461          a0:= (a0 * (255 - LongInt(a1)) + a1 * LongInt(a1)) div 255;
       
  1462          destPixels^[i]:= SDL_MapRGBA(dest^.format, r0, g0, b0, a0);
       
  1463          end;
       
  1464       end;
       
  1465 end;
       
  1466 
       
  1467 procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL, apparently
       
  1468 var y, x, i, j: LongInt;
       
  1469     srcPixels, destPixels: PLongWordArray;
       
  1470 begin
       
  1471 TryDo(src^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
       
  1472 TryDo(dest^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
       
  1473 
       
  1474 srcPixels:= src^.pixels;
       
  1475 destPixels:= dest^.pixels;
       
  1476 
       
  1477 j:= 0;
       
  1478 for x := 0 to src^.w - 1 do
       
  1479     for y := 0 to src^.h - 1 do
       
  1480         begin
       
  1481         i:= (src^.h - 1 - y) * (src^.pitch div 4) + x;
       
  1482         destPixels^[j]:= srcPixels^[i];
       
  1483         inc(j)
       
  1484         end;
       
  1485 end;
       
  1486 
       
  1487 function RenderHelpWindow(caption, subcaption, description, extra: ansistring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
   661 function RenderHelpWindow(caption, subcaption, description, extra: ansistring; extracolor: LongInt; iconsurf: PSDL_Surface; iconrect: PSDL_Rect): PTexture;
  1488 var tmpsurf: PSDL_SURFACE;
   662 var tmpsurf: PSDL_SURFACE;
  1489     w, h, i, j: LongInt;
   663     w, h, i, j: LongInt;
  1490     font: THWFont;
   664     font: THWFont;
  1491     r, r2: TSDL_Rect;
   665     r, r2: TSDL_Rect;
  1657     exit;
   831     exit;
  1658 FreeTexture(WeaponTooltipTex);
   832 FreeTexture(WeaponTooltipTex);
  1659 WeaponTooltipTex:= nil
   833 WeaponTooltipTex:= nil
  1660 end;
   834 end;
  1661 
   835 
       
   836 procedure chFullScr(var s: shortstring);
       
   837 var flags: Longword = 0;
       
   838     ico: PSDL_Surface;
       
   839 {$IFDEF DEBUGFILE}
       
   840     buf: array[byte] of char;
       
   841 {$ENDIF}
       
   842 begin
       
   843     s:= s; // avoid compiler hint
       
   844     if Length(s) = 0 then cFullScreen:= not cFullScreen
       
   845     else cFullScreen:= s = '1';
       
   846 
       
   847 {$IFDEF DEBUGFILE}
       
   848     buf[0]:= char(0); // avoid compiler hint
       
   849     AddFileLog('Prepare to change video parameters...');
       
   850 {$ENDIF}
       
   851 
       
   852     flags:= SDL_OPENGL;// or SDL_RESIZABLE;
       
   853 
       
   854     if cFullScreen then
       
   855         flags:= flags or SDL_FULLSCREEN;
       
   856 
       
   857 {$IFDEF SDL_IMAGE_NEWER}
       
   858     WriteToConsole('Init SDL_image... ');
       
   859     SDLTry(IMG_Init(IMG_INIT_PNG) <> 0, true);
       
   860     WriteLnToConsole(msgOK);
       
   861 {$ENDIF}
       
   862     // load engine icon
       
   863 {$IFDEF DARWIN}
       
   864     ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
       
   865 {$ELSE}
       
   866     ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
       
   867 {$ENDIF}
       
   868     if ico <> nil then
       
   869     begin
       
   870         SDL_WM_SetIcon(ico, 0);
       
   871         SDL_FreeSurface(ico)
       
   872     end;
       
   873 
       
   874     // set window caption
       
   875     SDL_WM_SetCaption('Hedgewars', nil);
       
   876 
       
   877     if SDLPrimSurface <> nil then
       
   878     begin
       
   879 {$IFDEF DEBUGFILE}
       
   880         AddFileLog('Freeing old primary surface...');
       
   881 {$ENDIF}
       
   882         SDL_FreeSurface(SDLPrimSurface);
       
   883         SDLPrimSurface:= nil;
       
   884     end;
       
   885 
       
   886 {$IFDEF SDL13}
       
   887     if SDLwindow = nil then
       
   888     begin
       
   889         SDLwindow:= SDL_CreateWindow('Hedgewars', 0, 0, cScreenWidth, cScreenHeight,
       
   890                         SDL_WINDOW_OPENGL or SDL_WINDOW_SHOWN
       
   891                         {$IFDEF IPHONEOS} or SDL_WINDOW_BORDERLESS{$ENDIF});
       
   892         SDL_CreateRenderer(SDLwindow, -1, 0);
       
   893     end;
       
   894 
       
   895     SDL_SetRenderDrawColor(0, 0, 0, 255);
       
   896     SDL_RenderFill(nil);
       
   897     SDL_RenderPresent();
       
   898 {$ELSE}
       
   899     SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
       
   900     SDLTry(SDLPrimSurface <> nil, true);
       
   901     PixelFormat:= SDLPrimSurface^.format;
       
   902 {$ENDIF}
       
   903 
       
   904 {$IFDEF DEBUGFILE}
       
   905     AddFileLog('Setting up OpenGL...');
       
   906     AddFileLog('SDL video driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))));
       
   907 {$ENDIF}
       
   908     SetupOpenGL();
       
   909 end;
       
   910 
  1662 procedure initModule;
   911 procedure initModule;
  1663 begin
   912 begin
       
   913     RegisterVariable('fullscr', vtCommand, @chFullScr, true);
       
   914 
  1664     PixelFormat:= nil;
   915     PixelFormat:= nil;
  1665     SDLPrimSurface:= nil;
   916     SDLPrimSurface:= nil;
  1666 
   917 
  1667 {$IFNDEF IPHONEOS}
   918 {$IFNDEF IPHONEOS}
  1668     rotationQt:= 0;
   919     rotationQt:= 0;