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); |
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 |
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. |