diff -r 31570b766315 -r ed5a6478e710 hedgewars/uRenderUtils.pas --- a/hedgewars/uRenderUtils.pas Tue Nov 10 18:16:35 2015 +0100 +++ b/hedgewars/uRenderUtils.pas Tue Nov 10 20:43:13 2015 +0100 @@ -1,6 +1,6 @@ (* * Hedgewars, a free turn based strategy game - * Copyright (c) 2004-2013 Andrey Korotaev + * Copyright (c) 2004-2015 Andrey Korotaev * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *) {$INCLUDE "options.inc"} @@ -68,7 +68,7 @@ r.y:= rect^.y + 2; r.w:= rect^.w - 2; r.h:= rect^.h - 4; - SDL_FillRect(Surface, @r, FillColor) + SDL_FillRect(Surface, @r, FillColor); end; (* function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect; @@ -77,13 +77,13 @@ end;*) function WriteInRoundRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring; maxLength: LongWord): TSDL_Rect; -var w, h: LongInt; +var w, h: Longword; tmpsurf: PSDL_Surface; clr: TSDL_Color; finalRect, textRect: TSDL_Rect; begin - TTF_SizeUTF8(Fontz[Font].Handle, Str2PChar(s), @w, @h); - if (maxLength <> 0) and (w > maxLength) then w := maxLength; + TTF_SizeUTF8(Fontz[Font].Handle, PChar(s), @w, @h); + if (maxLength > 0) and (w > maxLength) then w := maxLength; finalRect.x:= X; finalRect.y:= Y; finalRect.w:= w + cFontBorder * 2 + 4; @@ -96,7 +96,7 @@ clr.r:= (Color shr 16) and $FF; clr.g:= (Color shr 8) and $FF; clr.b:= Color and $FF; - tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(s), clr); + tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, PChar(s), clr); finalRect.x:= X + cFontBorder + 2; finalRect.y:= Y + cFontBorder; SDLTry(tmpsurf <> nil, 'TTF_RenderUTF8_Blended', true); @@ -115,6 +115,7 @@ pixels: PLongWordArray; begin TryDo(Surface^.format^.BytesPerPixel = 4, 'flipSurface failed, expecting 32 bit surface', true); + SDL_LockSurface(Surface); pixels:= Surface^.pixels; if Vertical then for y := 0 to (Surface^.h div 2) - 1 do @@ -136,6 +137,7 @@ pixels^[i]:= pixels^[j]; pixels^[j]:= tmpPixel; end; + SDL_UnlockSurface(Surface); end; procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline; @@ -150,6 +152,10 @@ begin maxDest:= (dest^.pitch div 4) * dest^.h; maxSrc:= (src^.pitch div 4) * src^.h; + + SDL_LockSurface(src); + SDL_LockSurface(dest); + srcPixels:= src^.pixels; destPixels:= dest^.pixels; @@ -165,10 +171,13 @@ r0:= (r0 * (255 - LongInt(a1)) + r1 * LongInt(a1)) div 255; g0:= (g0 * (255 - LongInt(a1)) + g1 * LongInt(a1)) div 255; b0:= (b0 * (255 - LongInt(a1)) + b1 * LongInt(a1)) div 255; - a0:= (a0 * (255 - LongInt(a1)) + a1 * LongInt(a1)) div 255; + a0:= a0 + ((255 - LongInt(a0)) * a1 div 255); destPixels^[i]:= SDL_MapRGBA(dest^.format, r0, g0, b0, a0); end; end; + + SDL_UnlockSurface(src); + SDL_UnlockSurface(dest); end; procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline; @@ -182,12 +191,12 @@ numFramesFirstCol:= SpritesData[sprite].imageHeight div SpritesData[sprite].Height; row:= Frame mod numFramesFirstCol; col:= Frame div numFramesFirstCol; - - copyToXYFromRect(SpritesData[sprite].Surface, dest, - col*SpritesData[sprite].Width, - row*SpritesData[sprite].Height, - SpritesData[sprite].Width, - spritesData[sprite].Height, + + copyToXYFromRect(SpritesData[sprite].Surface, dest, + col*SpritesData[sprite].Width, + row*SpritesData[sprite].Height, + SpritesData[sprite].Width, + spritesData[sprite].Height, x,y); end; @@ -199,13 +208,16 @@ begin //max:= (dest^.pitch div 4) * dest^.h; yMax:= dest^.pitch div 4; + + SDL_LockSurface(dest); + destPixels:= dest^.pixels; dx:= abs(x1-x0); dy:= abs(y1-y0); if x0 < x1 then sx:= 1 else sx:= -1; if y0 < y1 then sy:= 1 else sy:= -1; - err:= dx-dy; + err:= dx-dy; while(true) do begin @@ -225,7 +237,8 @@ err:= err + dx; y0:=y0+sy end; - end; + end; + SDL_UnlockSurface(dest); end; procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL, apparently @@ -235,6 +248,9 @@ TryDo(src^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true); TryDo(dest^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true); + SDL_LockSurface(src); + SDL_LockSurface(dest); + srcPixels:= src^.pixels; destPixels:= dest^.pixels; @@ -246,6 +262,10 @@ destPixels^[j]:= srcPixels^[i]; inc(j) end; + + SDL_UnlockSurface(src); + SDL_UnlockSurface(dest); + end; function RenderStringTex(s: ansistring; Color: Longword; font: THWFont): PTexture; @@ -254,54 +274,116 @@ end; function RenderStringTexLim(s: ansistring; Color: Longword; font: THWFont; maxLength: LongWord): PTexture; -var w, h: LongInt; +var w, h: Longword; finalSurface: PSDL_Surface; begin - if length(s) = 0 then s:= _S' '; - font:= CheckCJKFont(s, font); - w:= 0; h:= 0; // avoid compiler hints - TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), @w, @h); - if (maxLength <> 0) and (w > maxLength) then w := maxLength; - - finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w + cFontBorder * 2 + 4, h + cFontBorder * 2, - 32, RMask, GMask, BMask, AMask); + if cOnlyStats then + begin + RenderStringTexLim:= nil; + end + else + begin + if length(s) = 0 then s:= _S' '; + font:= CheckCJKFont(s, font); + w:= 0; h:= 0; // avoid compiler hints + TTF_SizeUTF8(Fontz[font].Handle, PChar(s), @w, @h); + if (maxLength > 0) and (w > maxLength) then w := maxLength; - TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true); + finalSurface:= SDL_CreateRGBSurface(SDL_SWSURFACE, w + cFontBorder * 2 + 4, h + cFontBorder * 2, + 32, RMask, GMask, BMask, AMask); - WriteInRoundRect(finalSurface, 0, 0, Color, font, s, maxLength); + TryDo(finalSurface <> nil, 'RenderString: fail to create surface', true); + + WriteInRoundRect(finalSurface, 0, 0, Color, font, s, maxLength); - TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true); + TryDo(SDL_SetColorKey(finalSurface, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true); - RenderStringTexLim:= Surface2Tex(finalSurface, false); + RenderStringTexLim:= Surface2Tex(finalSurface, false); - SDL_FreeSurface(finalSurface); + SDL_FreeSurface(finalSurface); + end; end; +function GetNextSpeechLine(s: ansistring; ldelim: char; var startFrom: LongInt; out substr: ansistring): boolean; +var p, l, m, r: Integer; + newl, skip: boolean; + c : char; +begin + m:= Length(s); + + substr:= ''; + + SetLengthA(substr, m); + + // number of chars read + r:= 0; + + // number of chars to be written + l:= 0; + + newl:= true; + + for p:= max(1, startFrom) to m do + begin + + inc(r); + // read char from source string + c:= s[p]; + + // strip empty lines, spaces and newlines on beginnings of line + skip:= ((newl or (p = m)) and ((c = ' ') or (c = ldelim))); + + if (not skip) then + begin + newl:= (c = ldelim); + // stop if we went past the end of the line + if newl then + break; + + // copy current char to output substring + inc(l); + substr[l]:= c; + end; + + end; + + inc(startFrom, r); + + SetLengthA(substr, l); + + GetNextSpeechLine:= (l > 0); +end; function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture; -var textWidth, textHeight, x, y, w, h, i, j, pos, prevpos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt; +var textWidth, textHeight, x, y, w, h, i, j, pos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt; finalSurface, tmpsurf, rotatedEdge: PSDL_Surface; rect: TSDL_Rect; + {$IFNDEF PAS2C} chars: set of char = [#9,' ',';',':','?','!',',']; - substr: shortstring; + {$ENDIF} + substr: ansistring; edge, corner, tail: TSPrite; begin + if cOnlyStats then exit(nil); + case SpeechType of - 1: begin; - edge:= sprSpeechEdge; - corner:= sprSpeechCorner; - tail:= sprSpeechTail; - end; - 2: begin; - edge:= sprThoughtEdge; - corner:= sprThoughtCorner; - tail:= sprThoughtTail; - end; - 3: begin; - edge:= sprShoutEdge; - corner:= sprShoutCorner; - tail:= sprShoutTail; - end; + 1: begin + edge:= sprSpeechEdge; + corner:= sprSpeechCorner; + tail:= sprSpeechTail; + end; + 2: begin + edge:= sprThoughtEdge; + corner:= sprThoughtCorner; + tail:= sprThoughtTail; + end; + 3: begin + edge:= sprShoutEdge; + corner:= sprShoutCorner; + tail:= sprShoutTail; + end + else + exit(nil) end; edgeHeight:= SpritesData[edge].Height; edgeWidth:= SpritesData[edge].Width; @@ -318,7 +400,7 @@ s:= '...'; font:= CheckCJKFont(s, font); w:= 0; h:= 0; // avoid compiler hints - TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), @w, @h); + TTF_SizeUTF8(Fontz[font].Handle, PChar(s), @w, @h); if w<8 then w:= 8; j:= 0; @@ -326,28 +408,28 @@ begin w:= 0; i:= round(Sqrt(length(s)) * 2); + {$IFNDEF PAS2C} s:= WrapText(s, #1, chars, i); - pos:= 1; prevpos:= 0; line:= 0; + {$ENDIF} + pos:= 1; line:= 0; // Find the longest line for the purposes of centring the text. Font dependant. - while pos <= length(s) do + while GetNextSpeechLine(s, #1, pos, substr) do begin - if (s[pos] = #1) or (pos = length(s)) then - begin - inc(numlines); - if s[pos] <> #1 then inc(pos); - while s[prevpos+1] = ' ' do inc(prevpos); - substr:= copy(s, prevpos+1, pos-prevpos-1); - i:= 0; j:= 0; - TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(substr), @i, @j); - if i > w then - w:= i; - prevpos:= pos; - end; - inc(pos); + inc(numLines); + i:= 0; j:= 0; + TTF_SizeUTF8(Fontz[font].Handle, PChar(substr), @i, @j); + if i > w then + w:= i; end; end else numLines := 1; + if numLines < 1 then + begin + s:= '...'; + numLines:= 1; + end; + textWidth:=((w-(cornerWidth-edgeWidth)*2) div edgeWidth)*edgeWidth+edgeWidth; textHeight:=(((numlines * h + 2)-((cornerHeight-edgeWidth)*2)) div edgeWidth)*edgeWidth; @@ -433,36 +515,24 @@ j:= rect.h; SDL_FillRect(finalSurface, @rect, cWhiteColor); - pos:= 1; prevpos:= 0; line:= 0; - while pos <= length(s) do + pos:= 1; line:= 0; + while GetNextSpeechLine(s, #1, pos, substr) do begin - if (s[pos] = #1) or (pos = length(s)) then - begin - if s[pos] <> #1 then - inc(pos); - while s[prevpos+1] = ' 'do - inc(prevpos); - substr:= copy(s, prevpos+1, pos-prevpos-1); - if Length(substr) <> 0 then - begin - tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(substr), cNearBlackColorChannels); - rect.x:= edgeHeight + 1 + ((i - w) div 2); - // trying to more evenly position the text, vertically - rect.y:= edgeHeight + ((j-(numLines*h)) div 2) + line * h; - SDLTry(tmpsurf <> nil, 'TTF_RenderUTF8_Blended', true); - SDL_UpperBlit(tmpsurf, nil, finalSurface, @rect); - SDL_FreeSurface(tmpsurf); - inc(line); - prevpos:= pos; - end; - end; - inc(pos); + tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, PChar(substr), cNearBlackColorChannels); + rect.x:= edgeHeight + 1 + ((i - w) div 2); + // trying to more evenly position the text, vertically + rect.y:= edgeHeight + ((j-(numLines*h)) div 2) + line * h; + SDLTry(tmpsurf <> nil, 'TTF_Init', true); + SDL_UpperBlit(tmpsurf, nil, finalSurface, @rect); + SDL_FreeSurface(tmpsurf); + inc(line); end; RenderSpeechBubbleTex:= Surface2Tex(finalSurface, true); SDL_FreeSurface(rotatedEdge); SDL_FreeSurface(finalSurface); + end; end.