1 /* -*- C++ -*-
2  *
3  *  PonscripterLabel_image.cpp - Image processing in Ponscripter
4  *
5  *  Copyright (c) 2001-2008 Ogapee (original ONScripter, of which this
6  *  is a fork).
7  *
8  *  ogapee@aqua.dti2.ne.jp
9  *
10  *  This program is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU General Public License as
12  *  published by the Free Software Foundation; either version 2 of the
13  *  License, or (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23  *  02111-1307 USA
24  */
25 
26 #include "PonscripterLabel.h"
27 #include <cstdio>
28 
29 #include "graphics_common.h"
30 
loadImage(const pstring & filename,bool * has_alpha,bool twox,bool isflipped)31 SDL_Surface *PonscripterLabel::loadImage(const pstring& filename,
32                                         bool *has_alpha, bool twox, bool isflipped)
33 {
34     if (!filename) return NULL;
35 
36     if (lastRenderEvent < RENDER_EVENT_LOAD_IMAGE) { lastRenderEvent = RENDER_EVENT_LOAD_IMAGE; }
37 
38     SDL_Surface *tmp = NULL, *tmpb = NULL;
39     int location = BaseReader::ARCHIVE_TYPE_NONE;
40 
41     CBStringList filenames = filename.split("&", 4);
42 
43     if (filenames[0][0] == '>')
44         tmp = createRectangleSurface(filenames[0]);
45     else
46         tmp = createSurfaceFromFile(filenames[0], &location);
47 
48     if (tmp == NULL) return NULL;
49 
50     bool has_colorkey = false;
51 
52     if ( has_alpha ){
53         *has_alpha = (tmp->format->Amask != 0);
54         if (!(*has_alpha) && (tmp->flags & SDL_TRUE)){
55             has_colorkey = true;
56             if (tmp->format->palette){
57                 //palette will be converted to RGBA, so don't do colorkey check
58                 has_colorkey = false;
59             }
60             *has_alpha = true;
61         }
62     }
63 
64     SDL_Surface *ret = SDL_ConvertSurface( tmp, image_surface->format, SDL_SWSURFACE );
65     SDL_FreeSurface( tmp );
66 
67     SDL_Rect subimage_rect;
68     CBStringList fileparts;
69     pstring sub_filename;
70 
71     int num_images = filenames.size();
72     if (num_images > 1) {
73         for (int x = 1; x < num_images; x++) {
74             sub_filename = filenames[x];
75             fileparts = sub_filename.split(",", 3);
76             tmp = createSurfaceFromFile(fileparts[2], &location);
77             tmpb = SDL_ConvertSurface( tmp, image_surface->format, SDL_SWSURFACE );
78             subimage_rect.x = fileparts[0];
79             subimage_rect.y = fileparts[1];
80             subimage_rect.w = tmpb->w;
81             subimage_rect.h = tmpb->h;
82             SDL_BlitScaled(tmpb, NULL, ret, &subimage_rect);
83             SDL_FreeSurface( tmp );
84             SDL_FreeSurface( tmpb );
85         }
86     }
87 
88     // Hack to detect when a PNG image is likely to have an old-style
89     // mask.  We assume that an old-style mask is intended if the
90     // image either has no alpha channel, or the alpha channel it has
91     // is completely opaque.  This behaviour can be overridden with
92     // the --force-png-alpha and --force-png-nscmask command-line
93     // options.
94     if (has_alpha && *has_alpha) {
95         if (png_mask_type == PNG_MASK_USE_NSCRIPTER)
96             *has_alpha = false;
97         else if (png_mask_type == PNG_MASK_AUTODETECT) {
98             SDL_LockSurface(ret);
99             const Uint32 aval = *(Uint32*)ret->pixels & ret->format->Amask;
100             if (aval != ret->format->Amask) goto breakalpha;
101             *has_alpha = false;
102             for (int y=0; y<ret->h; ++y) {
103                 Uint32* pixbuf = (Uint32*)((char*)ret->pixels + y * ret->pitch);
104                 for (int x=ret->w; x>0; --x, ++pixbuf) {
105                     // Resolving ambiguity per Tatu's patch, 20081118.
106                     // I note that this technically changes the meaning of the
107                     // code, since != is higher-precedence than &, but this
108                     // version is obviously what I intended when I wrote this.
109                     // Has this been broken all along?  :/  -- Haeleth
110                     if ((*pixbuf & ret->format->Amask) != aval) {
111                         *has_alpha = true;
112                         goto breakalpha;
113                     }
114                 }
115             }
116           breakalpha:
117             if (!*has_alpha && has_colorkey) {
118                 // has a colorkey, so run a match against rgb values
119                 const Uint32 aval = SDL_TRUE & ~(ret->format->Amask);
120                 if (aval == (*(Uint32*)ret->pixels & ~(ret->format->Amask)))
121                     goto breakkey;
122                 *has_alpha = false;
123                 for (int y=0; y<ret->h; ++y) {
124                     Uint32* pixbuf = (Uint32*)((char*)ret->pixels + y * ret->pitch);
125                     for (int x=ret->w; x>0; --x, ++pixbuf) {
126                         if ((*pixbuf & ~(ret->format->Amask)) == aval) {
127                             *has_alpha = true;
128                             goto breakkey;
129                         }
130                     }
131                 }
132             }
133           breakkey:
134             SDL_UnlockSurface(ret);
135         }
136     }
137 
138 
139     if (isflipped) {
140         SDL_Surface *retf = SDL_CreateRGBSurface(0, ret->w, ret->h, BPP, RMASK, GMASK, BMASK, AMASK);
141         Uint32* sourcepix;
142         Uint32* destpix;
143         for (int y=0; y<ret->h; ++y) {
144             sourcepix = (Uint32*)((char*)ret->pixels + y * ret->pitch);
145             destpix = (Uint32*)((char*)retf->pixels + (y + 1) * ret->pitch);
146             destpix--;
147             for (int x = 0; x < ret->w; x++, sourcepix++, destpix--) {
148                 *destpix = *sourcepix;
149             }
150         }
151         // swap pointer to new surface
152         SDL_FreeSurface( ret );
153         ret = retf;
154     }
155 
156     if (res_multiplier != 1) {
157         int multiplier = twox ? 1 : res_multiplier;
158         SDL_Surface *retb = SDL_CreateRGBSurface(0, ret->w * multiplier, ret->h * multiplier, BPP, RMASK, GMASK, BMASK, AMASK);
159         SDL_BlitScaled(ret, NULL, retb, NULL);
160 
161         SDL_FreeSurface( ret );
162         return retb;
163     } else {
164         return ret;
165     }
166 
167 }
168 
createRectangleSurface(const char * filename)169 SDL_Surface *PonscripterLabel::createRectangleSurface(const char* filename)
170 {
171     int c=1, w=0, h=0;
172     while (filename[c] != 0x0a && filename[c] != 0x00){
173         if (filename[c] >= '0' && filename[c] <= '9')
174             w = w*10 + filename[c]-'0';
175         if (filename[c] == ','){
176             c++;
177             break;
178         }
179         c++;
180     }
181 
182     while (filename[c] != 0x0a && filename[c] != 0x00){
183         if (filename[c] >= '0' && filename[c] <= '9')
184             h = h*10 + filename[c]-'0';
185         if (filename[c] == ','){
186             c++;
187             break;
188         }
189         c++;
190     }
191 
192     while (filename[c] == ' ' || filename[c] == '\t') c++;
193     int n=0, c2 = c;
194     while(filename[c] == '#'){
195         //rgb_t col = readColour((const char *)filename + c);
196         n++;
197         c += 7;
198         while (filename[c] == ' ' || filename[c] == '\t') c++;
199     }
200 
201     SDL_PixelFormat *fmt = image_surface->format;
202     SDL_Surface *tmp = SDL_CreateRGBSurface(0, w, h,
203                                             fmt->BitsPerPixel, fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
204 
205     c = c2;
206     for (int i=0 ; i<n ; i++){
207         rgb_t col = readColour(filename + c);
208         c += 7;
209         while (filename[c] == ' ' || filename[c] == '\t') c++;
210 
211         SDL_Rect rect;
212         rect.x = w*i/n;
213         rect.y = 0;
214         rect.w = w*(i+1)/n - rect.x;
215         if (i == n-1) rect.w = w - rect.x;
216         rect.h = h;
217         SDL_FillRect(tmp, &rect, SDL_MapRGBA( accumulation_surface->format, col.r, col.g, col.b, 0xff));
218     }
219 
220     return tmp;
221 }
222 
createSurfaceFromFile(const pstring & filename,int * location)223 SDL_Surface *PonscripterLabel::createSurfaceFromFile(const pstring& filename,
224                                                     int *location)
225 {
226     pstring alt_filename= "";
227     unsigned long length = script_h.cBR->getFileLength( filename );
228 
229     if (length == 0) {
230         alt_filename = script_h.save_path + filename;
231         alt_filename.findreplace("\\", DELIMITER);
232         FILE* fp = std::fopen(alt_filename, "rb");
233         if (fp) {
234             fseek(fp, 0, SEEK_END);
235             length = ftell(fp);
236             fclose(fp);
237         }
238     }
239 
240     if ( length == 0 ){
241         //don't complain about missing cursors
242         if ((filename != DEFAULT_LOOKBACK_NAME0) &&
243             (filename != DEFAULT_LOOKBACK_NAME1) &&
244             (filename != DEFAULT_LOOKBACK_NAME2) &&
245             (filename != DEFAULT_LOOKBACK_NAME3) &&
246             (filename != DEFAULT_CURSOR0) &&
247             (filename != DEFAULT_CURSOR1))
248             fprintf(stderr, " *** can't find file [%s] ***\n",
249                     (const char*) filename);
250         return NULL;
251     }
252     if (filelog_flag) script_h.file_log.add(filename);
253 
254     pstring dat = "";
255     if (!alt_filename) {
256         dat = script_h.cBR->getFile(filename, location);
257     }
258     else {
259         dat = script_h.cBR->getFile(alt_filename, location);
260         if ((unsigned)dat.slen != length)
261             fprintf(stderr, "Warning: error reading from %s\n",
262                     (const char*)alt_filename);
263     }
264 
265     SDL_Surface* tmp = IMG_Load_RW(rwops(dat), 1);
266     if (!tmp && file_extension(filename).caselessEqual("jpg")) {
267         fprintf(stderr, " *** force-loading a JPEG image [%s]\n",
268                 (const char*) filename);
269         SDL_RWops* src = rwops(dat);
270         tmp = IMG_LoadJPG_RW(src);
271         SDL_RWclose(src);
272     }
273 
274     if (!tmp)
275         fprintf(stderr, " *** can't load file [%s]: %s ***\n",
276                 (const char*)filename, IMG_GetError());
277 
278     return tmp;
279 }
280 
281 
282 // alphaMaskBlend
283 // dst: accumulation_surface
284 // src1: effect_src_surface
285 // src2: effect_dst_surface
alphaMaskBlend(SDL_Surface * mask_surface,int trans_mode,Uint32 mask_value,SDL_Rect * clip,SDL_Surface * src1,SDL_Surface * src2,SDL_Surface * dst)286 void PonscripterLabel::alphaMaskBlend(SDL_Surface *mask_surface, int trans_mode,
287                                       Uint32 mask_value, SDL_Rect *clip,
288                                       SDL_Surface *src1, SDL_Surface *src2,
289                                       SDL_Surface *dst)
290 {
291     SDL_Rect rect = {0, 0, screen_width, screen_height};
292 
293     if (src1 == NULL)
294         src1 = effect_src_surface;
295     if (src2 == NULL)
296         src2 = effect_dst_surface;
297     if (dst == NULL)
298         dst = accumulation_surface;
299 
300     /* ---------------------------------------- */
301     /* clipping */
302     if ( clip ){
303         if ( AnimationInfo::doClipping( &rect, clip ) ) return;
304     }
305 
306     /* ---------------------------------------- */
307 
308     SDL_LockSurface( src1 );
309     SDL_LockSurface( src2 );
310     SDL_LockSurface( dst );
311     if ( mask_surface ) SDL_LockSurface( mask_surface );
312 
313     ONSBuf *src1_buffer = (ONSBuf *)src1->pixels + src1->w * rect.y + rect.x;
314     ONSBuf *src2_buffer = (ONSBuf *)src2->pixels + src2->w * rect.y + rect.x;
315     ONSBuf *dst_buffer  = (ONSBuf *)dst->pixels + dst->w * rect.y + rect.x;
316 
317     const int rwidth = screen_width - rect.w;
318     SDL_PixelFormat *fmt = dst->format;
319     Uint32 overflow_mask = 0xffffffff;
320     if ( trans_mode != ALPHA_BLEND_FADE_MASK )
321         overflow_mask = ~fmt->Bmask;
322 
323     mask_value >>= fmt->Bloss;
324 
325     if (( trans_mode == ALPHA_BLEND_FADE_MASK || trans_mode == ALPHA_BLEND_CROSSFADE_MASK ) && mask_surface) {
326         bool accelerated_ok = sizeof(ONSBuf) == 4 && fmt->Bmask == 0xff;
327         if (accelerated_ok) {
328             bool ok = AnimationInfo::gfx.alphaMaskBlend(dst, src1, src2, mask_surface, rect, mask_value);
329             accelerated_ok &= ok;
330         }
331         if (!accelerated_ok) {
332             int mask_off_base_y = rect.y % mask_surface->h;
333             int mask_off_base_x = rect.x % mask_surface->w;
334             for ( int i=0, my=mask_off_base_y ; i<rect.h ; i++, my++ ) {
335                 if (my >= mask_surface->h) { my = 0; }
336                 ONSBuf *mask_buffer = (ONSBuf *)mask_surface->pixels + mask_surface->w * my;
337                 int offset=rect.x;
338                 for ( int j=rect.w, mx=mask_off_base_x ; j ; j--, mx++ ) {
339                     if (mx >= mask_surface->w) { mx = 0; }
340                     Uint32 mask2 = 0;
341                     Uint32 mask = *(mask_buffer + mx) & fmt->Bmask;
342                     if ( mask_value > mask ){
343                         mask2 = mask_value - mask;
344                         if ( mask2 & overflow_mask ) mask2 = fmt->Bmask;
345                     }
346     #ifndef BPP16
347                     Uint32 mask1 = mask2 ^ fmt->Bmask;
348     #endif
349                     BLEND_MASK_PIXEL();
350                     ++dst_buffer, ++src1_buffer, ++src2_buffer, ++offset;
351                 }
352                 src1_buffer += rwidth;
353                 src2_buffer += rwidth;
354                 dst_buffer  += rwidth;
355             }
356         }
357     }
358     else{ // ALPHA_BLEND_CONST
359         if (sizeof(ONSBuf) == 4) {
360             AnimationInfo::gfx.alphaMaskBlendConst(dst, src1, src2, rect, mask_value);
361         }
362         else {
363             Uint32 mask2 = mask_value & fmt->Bmask;
364 #ifndef BPP16
365             Uint32 mask1 = mask2 ^ fmt->Bmask;
366 #endif
367             for ( int i=rect.h ; i ; i-- ) {
368                 for ( int j=rect.w ; j ; j-- ){
369                     BLEND_MASK_PIXEL();
370                     ++dst_buffer, ++src1_buffer, ++src2_buffer;
371                 }
372                 src1_buffer += rwidth;
373                 src2_buffer += rwidth;
374                 dst_buffer  += rwidth;
375             }
376         }
377     }
378 
379     if ( mask_surface ) SDL_UnlockSurface( mask_surface );
380     SDL_UnlockSurface( dst );
381     SDL_UnlockSurface( src2 );
382     SDL_UnlockSurface( src1 );
383 }
384 
385 
386 // alphaBlendText
387 // dst: ONSBuf surface (accumulation_surface)
388 // txt: 8bit surface (TTF_RenderGlyph_Shaded())
alphaBlendText(SDL_Surface * dst_surface,SDL_Rect dst_rect,SDL_Surface * txt_surface,SDL_Color & color,SDL_Rect * clip,bool rotate_flag)389 void PonscripterLabel::alphaBlendText(SDL_Surface *dst_surface, SDL_Rect dst_rect,
390                                       SDL_Surface *txt_surface, SDL_Color &color,
391                                       SDL_Rect *clip, bool rotate_flag)
392 {
393     int x2=0, y2=0;
394     SDL_Rect clipped_rect;
395 
396     /* ---------------------------------------- */
397     /* 1st clipping */
398     if ( clip ){
399         if ( AnimationInfo::doClipping( &dst_rect, clip, &clipped_rect ) ) return;
400 
401         x2 += clipped_rect.x;
402         y2 += clipped_rect.y;
403     }
404 
405     /* ---------------------------------------- */
406     /* 2nd clipping */
407     SDL_Rect clip_rect = {0, 0, dst_surface->w, dst_surface->h};
408     if ( AnimationInfo::doClipping( &dst_rect, &clip_rect, &clipped_rect ) ) return;
409 
410     x2 += clipped_rect.x;
411     y2 += clipped_rect.y;
412 
413     /* ---------------------------------------- */
414 
415     SDL_LockSurface( dst_surface );
416     SDL_LockSurface( txt_surface );
417 
418 #ifdef BPP16
419     Uint32 src_color = ((color.r >> RLOSS) << RSHIFT) |
420                        ((color.g >> GLOSS) << GSHIFT) |
421                        (color.b >> BLOSS);
422     src_color = (src_color | src_color << 16) & BLENDMASK;
423 #else
424     Uint32 src_color1 = color.r << RSHIFT | color.b;
425     Uint32 src_color2 = color.g << GSHIFT;
426 #endif
427 
428     ONSBuf *dst_buffer = (ONSBuf *)dst_surface->pixels +
429                          dst_surface->w * dst_rect.y + dst_rect.x;
430 
431     if (!rotate_flag){
432         unsigned char *src_buffer = (unsigned char*)txt_surface->pixels +
433                                     txt_surface->pitch * y2 + x2;
434         for ( int i=dst_rect.h ; i>0 ; i-- ){
435             for ( int j=dst_rect.w ; j>0 ; j--, dst_buffer++, src_buffer++ ){
436                 BLEND_PIXEL8();
437             }
438             dst_buffer += dst_surface->w - dst_rect.w;
439             src_buffer += txt_surface->pitch - dst_rect.w;
440         }
441     }
442     else{
443         for ( int i=0 ; i<dst_rect.h ; i++ ){
444             unsigned char *src_buffer = (unsigned char*)txt_surface->pixels + txt_surface->pitch*(txt_surface->h - x2 - 1) + y2 + i;
445             for ( int j=dst_rect.w ; j>0 ; j--, dst_buffer++ ){
446                 BLEND_PIXEL8();
447                 src_buffer -= txt_surface->pitch;
448             }
449             dst_buffer += dst_surface->w - dst_rect.w;
450         }
451     }
452 
453     SDL_UnlockSurface( txt_surface );
454     SDL_UnlockSurface( dst_surface );
455 }
456 
457 
makeNegaSurface(SDL_Surface * surface,SDL_Rect & clip)458 void PonscripterLabel::makeNegaSurface( SDL_Surface *surface, SDL_Rect &clip )
459 {
460     SDL_LockSurface( surface );
461     ONSBuf *buf = (ONSBuf *)surface->pixels + clip.y * surface->w + clip.x;
462 
463     ONSBuf mask = surface->format->Rmask | surface->format->Gmask | surface->format->Bmask;
464     for ( int i=clip.h ; i>0 ; i-- ){
465         for ( int j=clip.w ; j>0 ; j-- )
466             *buf++ ^= mask;
467         buf += surface->w - clip.w;
468     }
469 
470     SDL_UnlockSurface( surface );
471 }
472 
473 
makeMonochromeSurface(SDL_Surface * surface,SDL_Rect & clip)474 void PonscripterLabel::makeMonochromeSurface( SDL_Surface *surface, SDL_Rect &clip )
475 {
476     SDL_LockSurface( surface );
477     ONSBuf *buffer = (ONSBuf *)surface->pixels + clip.y * surface->w + clip.x;
478 
479     for ( int i=clip.h ; i>0 ; i-- ){
480         for ( int j=clip.w ; j>0 ; j--, buffer++ ){
481             //Mion: NScr seems to use more "equal" 85/86/85 RGB blending, instead
482             // of the 77/151/28 that onscr used to have. Using 85/86/85 now,
483             // might add a parameter to "monocro" to allow choosing 77/151/28
484             MONOCRO_PIXEL();
485         }
486         buffer += surface->w - clip.w;
487     }
488 
489     SDL_UnlockSurface( surface );
490 }
491 
492 
493 void
refreshSurface(SDL_Surface * surface,SDL_Rect * clip_src,int refresh_mode)494 PonscripterLabel::refreshSurface(SDL_Surface* surface, SDL_Rect* clip_src,
495 				 int refresh_mode)
496 {
497     if (refresh_mode == REFRESH_NONE_MODE) return;
498 
499     SDL_Rect clip = { 0, 0, surface->w, surface->h };
500     if (clip_src && AnimationInfo::doClipping(&clip, clip_src)) return;
501 
502     int i, top;
503     SDL_BlitSurface( bg_info.image_surface, &clip, surface, &clip );
504 
505     if (!all_sprite_hide_flag) {
506         if (z_order < 10 && refresh_mode & REFRESH_SAYA_MODE)
507             top = 9;
508         else
509             top = z_order;
510 
511         for (i = MAX_SPRITE_NUM - 1; i > top; --i) {
512             if (sprite_info[i].image_surface && sprite_info[i].showing())
513                 drawTaggedSurface(surface, &sprite_info[i], clip);
514         }
515     }
516 
517     for (i = 0; i < 3; ++i) {
518         if (human_order[2 - i] >= 0 &&
519             tachi_info[human_order[2 - i]].image_surface)
520             drawTaggedSurface(surface, &tachi_info[human_order[2 - i]], clip);
521     }
522 
523     if (windowback_flag) {
524         if (nega_mode == 1) makeNegaSurface(surface, clip);
525         if (monocro_flag)   makeMonochromeSurface(surface, clip);
526         if (nega_mode == 2) makeNegaSurface(surface, clip);
527 
528         if (!all_sprite2_hide_flag) {
529             for (i = MAX_SPRITE2_NUM - 1; i >= 0; --i) {
530                 if (sprite2_info[i].image_surface && sprite2_info[i].showing())
531                     drawTaggedSurface(surface, &sprite2_info[i], clip);
532             }
533         }
534 
535         if (refresh_mode & REFRESH_SHADOW_MODE)
536             shadowTextDisplay(surface, clip);
537         if (refresh_mode & REFRESH_TEXT_MODE)
538             text_info.blendOnSurface(surface, 0, 0, clip);
539     }
540 
541     if (!all_sprite_hide_flag) {
542         if (refresh_mode & REFRESH_SAYA_MODE)
543             top = 10;
544         else
545             top = 0;
546         for (i = z_order; i >= top; --i) {
547             if (sprite_info[i].image_surface && sprite_info[i].showing())
548                 drawTaggedSurface(surface, &sprite_info[i], clip);
549         }
550     }
551 
552     if (!windowback_flag) {
553         //Mion - ogapee2008
554         if (!all_sprite2_hide_flag) {
555             for (i = MAX_SPRITE2_NUM - 1; i >= 0; --i) {
556                 if (sprite2_info[i].image_surface && sprite2_info[i].showing())
557                     drawTaggedSurface(surface, &sprite2_info[i], clip);
558             }
559         }
560         if (nega_mode == 1) makeNegaSurface(surface, clip);
561         if (monocro_flag)   makeMonochromeSurface(surface, clip);
562         if (nega_mode == 2) makeNegaSurface(surface, clip);
563     }
564 
565     if (!(refresh_mode & REFRESH_SAYA_MODE)) {
566         for (i = 0; i < MAX_PARAM_NUM; ++i)
567             if (bar_info[i])
568                 drawTaggedSurface(surface, bar_info[i], clip);
569         for (i = 0; i < MAX_PARAM_NUM; ++i)
570             if (prnum_info[i])
571                 drawTaggedSurface(surface, prnum_info[i], clip);
572     }
573 
574     if (!windowback_flag) {
575         if (refresh_mode & REFRESH_SHADOW_MODE)
576             shadowTextDisplay(surface, clip);
577         if (refresh_mode & REFRESH_TEXT_MODE)
578             text_info.blendOnSurface(surface, 0, 0, clip);
579     }
580 
581     if (refresh_mode & REFRESH_CURSOR_MODE && !textgosub_label) {
582         if (clickstr_state == CLICK_WAIT)
583             drawTaggedSurface(surface, &cursor_info[CURSOR_WAIT_NO], clip);
584         else if (clickstr_state == CLICK_NEWPAGE)
585             drawTaggedSurface(surface, &cursor_info[CURSOR_NEWPAGE_NO], clip);
586     }
587 
588     for (ButtonElt::iterator it = buttons.begin(); it != buttons.end(); ++it)
589         if (it->second.show_flag > 0)
590             drawTaggedSurface(surface, it->second.anim[it->second.show_flag - 1], clip);
591 }
592 
593 
refreshSprite(int sprite_no,bool active_flag,int cell_no,SDL_Rect * check_src_rect,SDL_Rect * check_dst_rect)594 void PonscripterLabel::refreshSprite(int sprite_no, bool active_flag,
595                                      int cell_no, SDL_Rect* check_src_rect,
596                                      SDL_Rect* check_dst_rect)
597 {
598     if ((sprite_info[sprite_no].image_name ||
599          ((sprite_info[sprite_no].trans_mode == AnimationInfo::TRANS_STRING) &&
600           sprite_info[sprite_no].file_name)) &&
601         ((sprite_info[sprite_no].showing() != active_flag) ||
602          (cell_no >= 0 && sprite_info[sprite_no].current_cell != cell_no) ||
603          AnimationInfo::doClipping(check_src_rect,&sprite_info[sprite_no].pos) == 0 ||
604          AnimationInfo::doClipping(check_dst_rect,&sprite_info[sprite_no].pos) == 0))
605     {
606         if (cell_no >= 0) sprite_info[sprite_no].setCell(cell_no);
607         sprite_info[sprite_no].visible(active_flag);
608         dirty_rect.add(sprite_info[sprite_no].pos);
609     }
610 }
611 
612 
createBackground()613 void PonscripterLabel::createBackground()
614 {
615     bg_info.num_of_cells = 1;
616     bg_info.trans_mode = AnimationInfo::TRANS_COPY;
617     bg_info.pos.x = 0;
618     bg_info.pos.y = 0;
619     bg_info.allocImage(screen_width,screen_height);
620 
621     if (bg_info.file_name == "white") {
622         bg_info.color.set(0xff);
623     }
624     else if (bg_info.file_name == "black") {
625         bg_info.color.set(0x00);
626     }
627     else if (bg_info.file_name[0] == '#') {
628         bg_info.color = readColour(bg_info.file_name);
629     }
630     else {
631         AnimationInfo anim;
632         anim.image_name = bg_info.file_name;
633         parseTaggedString(&anim);
634         anim.trans_mode = AnimationInfo::TRANS_COPY;
635         setupAnimationInfo(&anim);
636         bg_info.fill(0, 0, 0, 0xff);
637         if (anim.image_surface){
638             SDL_Rect src_rect = {0, 0, anim.image_surface->w, anim.image_surface->h};
639             SDL_Rect dst_rect = {0, 0, screen_width, screen_height};
640             if (screen_width >= anim.image_surface->w){
641                 dst_rect.x = (screen_width - anim.image_surface->w) / 2;
642             }
643             else{
644                 src_rect.x = (anim.image_surface->w - screen_width) / 2;
645                 src_rect.w = screen_width;
646             }
647             if (screen_height >= anim.image_surface->h){
648                 dst_rect.y = (screen_height - anim.image_surface->h) / 2;
649             }
650             else{
651                 src_rect.y = (anim.image_surface->h - screen_height) / 2;
652                 src_rect.h = screen_height;
653             }
654             bg_info.copySurface(anim.image_surface, &src_rect, &dst_rect);
655         }
656         return;
657     }
658 
659     bg_info.fill(bg_info.color, 0xff);
660 }
661