hedgewars/uRenderUtils.pas
branchsdl2transition
changeset 11362 ed5a6478e710
parent 9682 aa2431ed87b2
parent 11317 62287d4044e7
child 11507 bd9a2f1b0080
equal deleted inserted replaced
11361:31570b766315 11362:ed5a6478e710
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    12  * GNU General Public License for more details.
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17  *)
    17  *)
    18 
    18 
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uRenderUtils;
    21 unit uRenderUtils;
    66     SDL_FillRect(Surface, @r, FillColor);
    66     SDL_FillRect(Surface, @r, FillColor);
    67     r.x:= rect^.x + 1;
    67     r.x:= rect^.x + 1;
    68     r.y:= rect^.y + 2;
    68     r.y:= rect^.y + 2;
    69     r.w:= rect^.w - 2;
    69     r.w:= rect^.w - 2;
    70     r.h:= rect^.h - 4;
    70     r.h:= rect^.h - 4;
    71     SDL_FillRect(Surface, @r, FillColor)
    71     SDL_FillRect(Surface, @r, FillColor);
    72 end;
    72 end;
    73 (*
    73 (*
    74 function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
    74 function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
    75 begin
    75 begin
    76     WriteInRoundRect:= WriteInRoundRect(Surface, X, Y, Color, Font, s, 0);
    76     WriteInRoundRect:= WriteInRoundRect(Surface, X, Y, Color, Font, s, 0);
    77 end;*)
    77 end;*)
    78 
    78 
    79 function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring; maxLength: LongWord): TSDL_Rect;
    79 function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring; maxLength: LongWord): TSDL_Rect;
    80 var w, h: LongInt;
    80 var w, h: Longword;
    81     tmpsurf: PSDL_Surface;
    81     tmpsurf: PSDL_Surface;
    82     clr: TSDL_Color;
    82     clr: TSDL_Color;
    83     finalRect, textRect: TSDL_Rect;
    83     finalRect, textRect: TSDL_Rect;
    84 begin
    84 begin
    85     TTF_SizeUTF8(Fontz[Font].Handle, Str2PChar(s), @w, @h);
    85     TTF_SizeUTF8(Fontz[Font].Handle, PChar(s), @w, @h);
    86     if (maxLength <> 0) and (w > maxLength) then w := maxLength;
    86     if (maxLength > 0) and (w > maxLength) then w := maxLength;
    87     finalRect.x:= X;
    87     finalRect.x:= X;
    88     finalRect.y:= Y;
    88     finalRect.y:= Y;
    89     finalRect.w:= w + cFontBorder * 2 + 4;
    89     finalRect.w:= w + cFontBorder * 2 + 4;
    90     finalRect.h:= h + cFontBorder * 2;
    90     finalRect.h:= h + cFontBorder * 2;
    91     textRect.x:= X;
    91     textRect.x:= X;
    94     textRect.h:= h;
    94     textRect.h:= h;
    95     DrawRoundRect(@finalRect, cWhiteColor, cNearBlackColor, Surface, true);
    95     DrawRoundRect(@finalRect, cWhiteColor, cNearBlackColor, Surface, true);
    96     clr.r:= (Color shr 16) and $FF;
    96     clr.r:= (Color shr 16) and $FF;
    97     clr.g:= (Color shr 8) and $FF;
    97     clr.g:= (Color shr 8) and $FF;
    98     clr.b:= Color and $FF;
    98     clr.b:= Color and $FF;
    99     tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(s), clr);
    99     tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, PChar(s), clr);
   100     finalRect.x:= X + cFontBorder + 2;
   100     finalRect.x:= X + cFontBorder + 2;
   101     finalRect.y:= Y + cFontBorder;
   101     finalRect.y:= Y + cFontBorder;
   102     SDLTry(tmpsurf <> nil, 'TTF_RenderUTF8_Blended', true);
   102     SDLTry(tmpsurf <> nil, 'TTF_RenderUTF8_Blended', true);
   103     SDL_UpperBlit(tmpsurf, @textRect, Surface, @finalRect);
   103     SDL_UpperBlit(tmpsurf, @textRect, Surface, @finalRect);
   104     SDL_FreeSurface(tmpsurf);
   104     SDL_FreeSurface(tmpsurf);
   113 var y, x, i, j: LongInt;
   113 var y, x, i, j: LongInt;
   114     tmpPixel: Longword;
   114     tmpPixel: Longword;
   115     pixels: PLongWordArray;
   115     pixels: PLongWordArray;
   116 begin
   116 begin
   117     TryDo(Surface^.format^.BytesPerPixel = 4, 'flipSurface failed, expecting 32 bit surface', true);
   117     TryDo(Surface^.format^.BytesPerPixel = 4, 'flipSurface failed, expecting 32 bit surface', true);
       
   118     SDL_LockSurface(Surface);
   118     pixels:= Surface^.pixels;
   119     pixels:= Surface^.pixels;
   119     if Vertical then
   120     if Vertical then
   120     for y := 0 to (Surface^.h div 2) - 1 do
   121     for y := 0 to (Surface^.h div 2) - 1 do
   121         for x := 0 to Surface^.w - 1 do
   122         for x := 0 to Surface^.w - 1 do
   122             begin
   123             begin
   134             j:= y*Surface^.w + (Surface^.w - x - 1);
   135             j:= y*Surface^.w + (Surface^.w - x - 1);
   135             tmpPixel:= pixels^[i];
   136             tmpPixel:= pixels^[i];
   136             pixels^[i]:= pixels^[j];
   137             pixels^[i]:= pixels^[j];
   137             pixels^[j]:= tmpPixel;
   138             pixels^[j]:= tmpPixel;
   138             end;
   139             end;
       
   140     SDL_UnlockSurface(Surface);
   139 end;
   141 end;
   140 
   142 
   141 procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline;
   143 procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline;
   142 begin
   144 begin
   143     copyToXYFromRect(src, dest, 0, 0, src^.w, src^.h, destX, destY);
   145     copyToXYFromRect(src, dest, 0, 0, src^.w, src^.h, destX, destY);
   148     srcPixels, destPixels: PLongWordArray;
   150     srcPixels, destPixels: PLongWordArray;
   149     r0, g0, b0, a0, r1, g1, b1, a1: Byte;
   151     r0, g0, b0, a0, r1, g1, b1, a1: Byte;
   150 begin
   152 begin
   151     maxDest:= (dest^.pitch div 4) * dest^.h;
   153     maxDest:= (dest^.pitch div 4) * dest^.h;
   152     maxSrc:= (src^.pitch div 4) * src^.h;
   154     maxSrc:= (src^.pitch div 4) * src^.h;
       
   155 
       
   156     SDL_LockSurface(src);
       
   157     SDL_LockSurface(dest);
       
   158 
   153     srcPixels:= src^.pixels;
   159     srcPixels:= src^.pixels;
   154     destPixels:= dest^.pixels;
   160     destPixels:= dest^.pixels;
   155 
   161 
   156     for iX:= 0 to srcW - 1 do
   162     for iX:= 0 to srcW - 1 do
   157     for iY:= 0 to srcH - 1 do
   163     for iY:= 0 to srcH - 1 do
   163             SDL_GetRGBA(destPixels^[i], dest^.format, @r0, @g0, @b0, @a0);
   169             SDL_GetRGBA(destPixels^[i], dest^.format, @r0, @g0, @b0, @a0);
   164             SDL_GetRGBA(srcPixels^[j], src^.format, @r1, @g1, @b1, @a1);
   170             SDL_GetRGBA(srcPixels^[j], src^.format, @r1, @g1, @b1, @a1);
   165             r0:= (r0 * (255 - LongInt(a1)) + r1 * LongInt(a1)) div 255;
   171             r0:= (r0 * (255 - LongInt(a1)) + r1 * LongInt(a1)) div 255;
   166             g0:= (g0 * (255 - LongInt(a1)) + g1 * LongInt(a1)) div 255;
   172             g0:= (g0 * (255 - LongInt(a1)) + g1 * LongInt(a1)) div 255;
   167             b0:= (b0 * (255 - LongInt(a1)) + b1 * LongInt(a1)) div 255;
   173             b0:= (b0 * (255 - LongInt(a1)) + b1 * LongInt(a1)) div 255;
   168             a0:= (a0 * (255 - LongInt(a1)) + a1 * LongInt(a1)) div 255;
   174             a0:= a0 + ((255 - LongInt(a0)) * a1 div 255);
   169             destPixels^[i]:= SDL_MapRGBA(dest^.format, r0, g0, b0, a0);
   175             destPixels^[i]:= SDL_MapRGBA(dest^.format, r0, g0, b0, a0);
   170             end;
   176             end;
   171         end;
   177         end;
       
   178 
       
   179     SDL_UnlockSurface(src);
       
   180     SDL_UnlockSurface(dest);
   172 end;
   181 end;
   173 
   182 
   174 procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline;
   183 procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline;
   175 begin
   184 begin
   176     DrawSpriteFrame2Surf(sprite, dest, x, y, 0);
   185     DrawSpriteFrame2Surf(sprite, dest, x, y, 0);
   180 var numFramesFirstCol, row, col: LongInt;
   189 var numFramesFirstCol, row, col: LongInt;
   181 begin
   190 begin
   182     numFramesFirstCol:= SpritesData[sprite].imageHeight div SpritesData[sprite].Height;
   191     numFramesFirstCol:= SpritesData[sprite].imageHeight div SpritesData[sprite].Height;
   183     row:= Frame mod numFramesFirstCol;
   192     row:= Frame mod numFramesFirstCol;
   184     col:= Frame div numFramesFirstCol;
   193     col:= Frame div numFramesFirstCol;
   185     
   194 
   186     copyToXYFromRect(SpritesData[sprite].Surface, dest, 
   195     copyToXYFromRect(SpritesData[sprite].Surface, dest,
   187              col*SpritesData[sprite].Width, 
   196              col*SpritesData[sprite].Width,
   188              row*SpritesData[sprite].Height, 
   197              row*SpritesData[sprite].Height,
   189              SpritesData[sprite].Width, 
   198              SpritesData[sprite].Width,
   190              spritesData[sprite].Height, 
   199              spritesData[sprite].Height,
   191              x,y);
   200              x,y);
   192 end;
   201 end;
   193 
   202 
   194 procedure DrawLine2Surf(dest: PSDL_Surface; x0, y0,x1,y1: LongInt; r,g,b: byte);
   203 procedure DrawLine2Surf(dest: PSDL_Surface; x0, y0,x1,y1: LongInt; r,g,b: byte);
   195 var
   204 var
   197     yMax: LongInt;
   206     yMax: LongInt;
   198     destPixels: PLongwordArray;
   207     destPixels: PLongwordArray;
   199 begin
   208 begin
   200     //max:= (dest^.pitch div 4) * dest^.h;
   209     //max:= (dest^.pitch div 4) * dest^.h;
   201     yMax:= dest^.pitch div 4;
   210     yMax:= dest^.pitch div 4;
       
   211 
       
   212     SDL_LockSurface(dest);
       
   213 
   202     destPixels:= dest^.pixels;
   214     destPixels:= dest^.pixels;
   203 
   215 
   204     dx:= abs(x1-x0);
   216     dx:= abs(x1-x0);
   205     dy:= abs(y1-y0);
   217     dy:= abs(y1-y0);
   206     if x0 < x1 then sx:= 1 else sx:= -1;
   218     if x0 < x1 then sx:= 1 else sx:= -1;
   207     if y0 < y1 then sy:= 1 else sy:= -1;
   219     if y0 < y1 then sy:= 1 else sy:= -1;
   208     err:= dx-dy; 
   220     err:= dx-dy;
   209 
   221 
   210     while(true) do
   222     while(true) do
   211         begin
   223         begin
   212         destPixels^[(y0 * yMax) + x0]:= SDL_MapRGB(dest^.format, r,g,b); //But will it blend? no
   224         destPixels^[(y0 * yMax) + x0]:= SDL_MapRGB(dest^.format, r,g,b); //But will it blend? no
   213 
   225 
   223         if e2 < dx then
   235         if e2 < dx then
   224             begin
   236             begin
   225             err:= err + dx;
   237             err:= err + dx;
   226             y0:=y0+sy
   238             y0:=y0+sy
   227             end;
   239             end;
   228         end; 
   240         end;
       
   241     SDL_UnlockSurface(dest);
   229 end;
   242 end;
   230 
   243 
   231 procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL, apparently
   244 procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL, apparently
   232 var y, x, i, j: LongInt;
   245 var y, x, i, j: LongInt;
   233     srcPixels, destPixels: PLongWordArray;
   246     srcPixels, destPixels: PLongWordArray;
   234 begin
   247 begin
   235     TryDo(src^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
   248     TryDo(src^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
   236     TryDo(dest^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
   249     TryDo(dest^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true);
   237 
   250 
       
   251     SDL_LockSurface(src);
       
   252     SDL_LockSurface(dest);
       
   253 
   238     srcPixels:= src^.pixels;
   254     srcPixels:= src^.pixels;
   239     destPixels:= dest^.pixels;
   255     destPixels:= dest^.pixels;
   240 
   256 
   241     j:= 0;
   257     j:= 0;
   242     for x := 0 to src^.w - 1 do
   258     for x := 0 to src^.w - 1 do
   244             begin
   260             begin
   245             i:= (src^.h - 1 - y) * (src^.pitch div 4) + x;
   261             i:= (src^.h - 1 - y) * (src^.pitch div 4) + x;
   246             destPixels^[j]:= srcPixels^[i];
   262             destPixels^[j]:= srcPixels^[i];
   247             inc(j)
   263             inc(j)
   248             end;
   264             end;
       
   265 
       
   266     SDL_UnlockSurface(src);
       
   267     SDL_UnlockSurface(dest);
       
   268 
   249 end;
   269 end;
   250 
   270 
   251 function RenderStringTex(s: ansistring; Color: Longword; font: THWFont): PTexture;
   271 function RenderStringTex(s: ansistring; Color: Longword; font: THWFont): PTexture;
   252 begin
   272 begin
   253     RenderStringTex:= RenderStringTexLim(s, Color, font, 0);
   273     RenderStringTex:= RenderStringTexLim(s, Color, font, 0);
   254 end;
   274 end;
   255 
   275 
   256 function RenderStringTexLim(s: ansistring; Color: Longword; font: THWFont; maxLength: LongWord): PTexture;
   276 function RenderStringTexLim(s: ansistring; Color: Longword; font: THWFont; maxLength: LongWord): PTexture;
   257 var w, h: LongInt;
   277 var w, h: Longword;
   258     finalSurface: PSDL_Surface;
   278     finalSurface: PSDL_Surface;
   259 begin
   279 begin
   260     if length(s) = 0 then s:= _S' ';
   280     if cOnlyStats then
   261     font:= CheckCJKFont(s, font);
   281         begin
   262     w:= 0; h:= 0; // avoid compiler hints
   282         RenderStringTexLim:= nil;
   263     TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), @w, @h);
   283         end
   264     if (maxLength <> 0) and (w > maxLength) then w := maxLength;
   284     else
   265 
   285         begin
   266     finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w + cFontBorder * 2 + 4, h + cFontBorder * 2,
   286         if length(s) = 0 then s:= _S' ';
   267             32, RMask, GMask, BMask, AMask);
   287         font:= CheckCJKFont(s, font);
   268 
   288         w:= 0; h:= 0; // avoid compiler hints
   269     TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true);
   289         TTF_SizeUTF8(Fontz[font].Handle, PChar(s), @w, @h);
   270 
   290         if (maxLength > 0) and (w > maxLength) then w := maxLength;
   271     WriteInRoundRect(finalSurface, 0, 0, Color, font, s, maxLength);
   291 
   272 
   292         finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w + cFontBorder * 2 + 4, h + cFontBorder * 2,
   273     TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
   293                 32, RMask, GMask, BMask, AMask);
   274 
   294 
   275     RenderStringTexLim:= Surface2Tex(finalSurface, false);
   295         TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true);
   276 
   296 
   277     SDL_FreeSurface(finalSurface);
   297         WriteInRoundRect(finalSurface, 0, 0, Color, font, s, maxLength);
   278 end;
   298 
   279 
   299         TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true);
       
   300 
       
   301         RenderStringTexLim:= Surface2Tex(finalSurface, false);
       
   302 
       
   303         SDL_FreeSurface(finalSurface);
       
   304         end;
       
   305 end;
       
   306 
       
   307 function GetNextSpeechLine(s: ansistring; ldelim: char; var startFrom: LongInt; out substr: ansistring): boolean;
       
   308 var p, l, m, r: Integer;
       
   309     newl, skip: boolean;
       
   310     c         : char;
       
   311 begin
       
   312     m:= Length(s);
       
   313 
       
   314     substr:= '';
       
   315 
       
   316     SetLengthA(substr, m);
       
   317 
       
   318     // number of chars read
       
   319     r:= 0;
       
   320 
       
   321     // number of chars to be written
       
   322     l:= 0;
       
   323 
       
   324     newl:= true;
       
   325 
       
   326     for p:= max(1, startFrom) to m do
       
   327         begin
       
   328 
       
   329         inc(r);
       
   330         // read char from source string
       
   331         c:= s[p];
       
   332 
       
   333         // strip empty lines, spaces and newlines on beginnings of line
       
   334         skip:= ((newl or (p = m)) and ((c = ' ') or (c = ldelim)));
       
   335 
       
   336         if (not skip) then
       
   337             begin
       
   338             newl:= (c = ldelim);
       
   339             // stop if we went past the end of the line
       
   340             if newl then
       
   341                 break;
       
   342 
       
   343             // copy current char to output substring
       
   344             inc(l);
       
   345             substr[l]:= c;
       
   346             end;
       
   347 
       
   348         end;
       
   349 
       
   350     inc(startFrom, r);
       
   351 
       
   352     SetLengthA(substr, l);
       
   353 
       
   354     GetNextSpeechLine:= (l > 0);
       
   355 end;
   280 
   356 
   281 function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture;
   357 function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture;
   282 var textWidth, textHeight, x, y, w, h, i, j, pos, prevpos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt;
   358 var textWidth, textHeight, x, y, w, h, i, j, pos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt;
   283     finalSurface, tmpsurf, rotatedEdge: PSDL_Surface;
   359     finalSurface, tmpsurf, rotatedEdge: PSDL_Surface;
   284     rect: TSDL_Rect;
   360     rect: TSDL_Rect;
       
   361     {$IFNDEF PAS2C}
   285     chars: set of char = [#9,' ',';',':','?','!',','];
   362     chars: set of char = [#9,' ',';',':','?','!',','];
   286     substr: shortstring;
   363     {$ENDIF}
       
   364     substr: ansistring;
   287     edge, corner, tail: TSPrite;
   365     edge, corner, tail: TSPrite;
   288 begin
   366 begin
       
   367     if cOnlyStats then exit(nil);
       
   368 
   289     case SpeechType of
   369     case SpeechType of
   290         1: begin;
   370         1: begin
   291         edge:= sprSpeechEdge;
   371             edge:= sprSpeechEdge;
   292         corner:= sprSpeechCorner;
   372             corner:= sprSpeechCorner;
   293         tail:= sprSpeechTail;
   373             tail:= sprSpeechTail;
   294         end;
   374             end;
   295         2: begin;
   375         2: begin
   296         edge:= sprThoughtEdge;
   376             edge:= sprThoughtEdge;
   297         corner:= sprThoughtCorner;
   377             corner:= sprThoughtCorner;
   298         tail:= sprThoughtTail;
   378             tail:= sprThoughtTail;
   299         end;
   379             end;
   300         3: begin;
   380         3: begin
   301         edge:= sprShoutEdge;
   381             edge:= sprShoutEdge;
   302         corner:= sprShoutCorner;
   382             corner:= sprShoutCorner;
   303         tail:= sprShoutTail;
   383             tail:= sprShoutTail;
   304         end;
   384             end
       
   385         else
       
   386             exit(nil)
   305         end;
   387         end;
   306     edgeHeight:= SpritesData[edge].Height;
   388     edgeHeight:= SpritesData[edge].Height;
   307     edgeWidth:= SpritesData[edge].Width;
   389     edgeWidth:= SpritesData[edge].Width;
   308     cornerWidth:= SpritesData[corner].Width;
   390     cornerWidth:= SpritesData[corner].Width;
   309     cornerHeight:= SpritesData[corner].Height;
   391     cornerHeight:= SpritesData[corner].Height;
   316 
   398 
   317     if length(s) = 0 then
   399     if length(s) = 0 then
   318         s:= '...';
   400         s:= '...';
   319     font:= CheckCJKFont(s, font);
   401     font:= CheckCJKFont(s, font);
   320     w:= 0; h:= 0; // avoid compiler hints
   402     w:= 0; h:= 0; // avoid compiler hints
   321     TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), @w, @h);
   403     TTF_SizeUTF8(Fontz[font].Handle, PChar(s), @w, @h);
   322     if w<8 then
   404     if w<8 then
   323         w:= 8;
   405         w:= 8;
   324     j:= 0;
   406     j:= 0;
   325     if (length(s) > 20) then
   407     if (length(s) > 20) then
   326         begin
   408         begin
   327         w:= 0;
   409         w:= 0;
   328         i:= round(Sqrt(length(s)) * 2);
   410         i:= round(Sqrt(length(s)) * 2);
       
   411         {$IFNDEF PAS2C}
   329         s:= WrapText(s, #1, chars, i);
   412         s:= WrapText(s, #1, chars, i);
   330         pos:= 1; prevpos:= 0; line:= 0;
   413         {$ENDIF}
       
   414         pos:= 1; line:= 0;
   331     // Find the longest line for the purposes of centring the text.  Font dependant.
   415     // Find the longest line for the purposes of centring the text.  Font dependant.
   332         while pos <= length(s) do
   416         while GetNextSpeechLine(s, #1, pos, substr) do
   333             begin
   417             begin
   334             if (s[pos] = #1) or (pos = length(s)) then
   418             inc(numLines);
   335                 begin
   419             i:= 0; j:= 0;
   336                 inc(numlines);
   420             TTF_SizeUTF8(Fontz[font].Handle, PChar(substr), @i, @j);
   337                 if s[pos] <> #1 then inc(pos);
   421             if i > w then
   338                 while s[prevpos+1] = ' ' do inc(prevpos);
   422                 w:= i;
   339                 substr:= copy(s, prevpos+1, pos-prevpos-1);
       
   340                 i:= 0; j:= 0;
       
   341                 TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(substr), @i, @j);
       
   342                 if i > w then
       
   343                     w:= i;
       
   344                 prevpos:= pos;
       
   345                 end;
       
   346             inc(pos);
       
   347             end;
   423             end;
   348         end
   424         end
   349     else numLines := 1;
   425     else numLines := 1;
       
   426 
       
   427     if numLines < 1 then
       
   428         begin
       
   429         s:= '...';
       
   430         numLines:= 1;
       
   431         end;
   350 
   432 
   351     textWidth:=((w-(cornerWidth-edgeWidth)*2) div edgeWidth)*edgeWidth+edgeWidth;
   433     textWidth:=((w-(cornerWidth-edgeWidth)*2) div edgeWidth)*edgeWidth+edgeWidth;
   352     textHeight:=(((numlines * h + 2)-((cornerHeight-edgeWidth)*2)) div edgeWidth)*edgeWidth;
   434     textHeight:=(((numlines * h + 2)-((cornerHeight-edgeWidth)*2)) div edgeWidth)*edgeWidth;
   353 
   435 
   354     textHeight:=max(textHeight,edgeWidth);
   436     textHeight:=max(textHeight,edgeWidth);
   431     rect.h:= textHeight + cornerHeight * 2 - edgeHeight * 2;
   513     rect.h:= textHeight + cornerHeight * 2 - edgeHeight * 2;
   432     i:= rect.w;
   514     i:= rect.w;
   433     j:= rect.h;
   515     j:= rect.h;
   434     SDL_FillRect(finalSurface, @rect, cWhiteColor);
   516     SDL_FillRect(finalSurface, @rect, cWhiteColor);
   435 
   517 
   436     pos:= 1; prevpos:= 0; line:= 0;
   518     pos:= 1; line:= 0;
   437     while pos <= length(s) do
   519     while GetNextSpeechLine(s, #1, pos, substr) do
   438         begin
   520         begin
   439         if (s[pos] = #1) or (pos = length(s)) then
   521         tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, PChar(substr), cNearBlackColorChannels);
   440             begin
   522         rect.x:= edgeHeight + 1 + ((i - w) div 2);
   441             if s[pos] <> #1 then
   523         // trying to more evenly position the text, vertically
   442                 inc(pos);
   524         rect.y:= edgeHeight + ((j-(numLines*h)) div 2) + line * h;
   443             while s[prevpos+1] = ' 'do
   525         SDLTry(tmpsurf <> nil, 'TTF_Init', true);
   444                 inc(prevpos);
   526         SDL_UpperBlit(tmpsurf, nil, finalSurface, @rect);
   445             substr:= copy(s, prevpos+1, pos-prevpos-1);
   527         SDL_FreeSurface(tmpsurf);
   446             if Length(substr) <> 0 then
   528         inc(line);
   447                 begin
       
   448                 tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(substr), cNearBlackColorChannels);
       
   449                 rect.x:= edgeHeight + 1 + ((i - w) div 2);
       
   450                 // trying to more evenly position the text, vertically
       
   451                 rect.y:= edgeHeight + ((j-(numLines*h)) div 2) + line * h;
       
   452                 SDLTry(tmpsurf <> nil, 'TTF_RenderUTF8_Blended', true);
       
   453                 SDL_UpperBlit(tmpsurf, nil, finalSurface, @rect);
       
   454                 SDL_FreeSurface(tmpsurf);
       
   455                 inc(line);
       
   456                 prevpos:= pos;
       
   457                 end;
       
   458                 end;
       
   459         inc(pos);
       
   460         end;
   529         end;
   461 
   530 
   462     RenderSpeechBubbleTex:= Surface2Tex(finalSurface, true);
   531     RenderSpeechBubbleTex:= Surface2Tex(finalSurface, true);
   463 
   532 
   464     SDL_FreeSurface(rotatedEdge);
   533     SDL_FreeSurface(rotatedEdge);
   465     SDL_FreeSurface(finalSurface);
   534     SDL_FreeSurface(finalSurface);
       
   535 
   466 end;
   536 end;
   467 
   537 
   468 end.
   538 end.