1 /* -*- C++ -*-
2  *
3  *  AnimationInfo.cpp - General image storage class of 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  *  Copyright (c) 2009-2010 "Uncle" Mion Sonozaki
11  *
12  *  UncleMion@gmail.com
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License as
16  *  published by the Free Software Foundation; either version 2 of the
17  *  License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  *  General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, see <http://www.gnu.org/licenses/>
26  *  or write to the Free Software Foundation, Inc.,
27  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29 
30 #include "AnimationInfo.h"
31 #include "BaseReader.h"
32 
33 #include "graphics_common.h"
34 
35 #include "graphics_accelerated.h"
36 
37 #include <math.h>
38 #ifndef M_PI
39 #define M_PI 3.14159265358979323846
40 #endif
41 
42 //Mion: for special graphics routine handling
43 AcceleratedGraphicsFunctions AnimationInfo::gfx;
44 
45 
AnimationInfo()46 AnimationInfo::AnimationInfo()
47 {
48     is_copy = false;
49 
50     image_surface = NULL;
51 #ifdef BPP16
52     alpha_buf     = NULL;
53 #endif
54     trans_mode    = TRANS_TOPLEFT;
55     affine_flag   = false;
56     locked        = 0;
57     reset();
58 }
59 
AnimationInfo(const AnimationInfo & anim)60 AnimationInfo::AnimationInfo(const AnimationInfo &anim)
61 {
62     //copy constructor
63     //deepcopy(anim);
64     memcpy(this, &anim, sizeof(AnimationInfo));
65     is_copy = true;
66     printf("animinfo '%s': made a copy (constr)\n", (const char*)anim.image_name);
67     fflush(stdout);
68 }
69 
70 
~AnimationInfo()71 AnimationInfo::~AnimationInfo()
72 {
73     reset();
74 }
75 
76 
operator =(const AnimationInfo & anim)77 AnimationInfo& AnimationInfo::operator =(const AnimationInfo &anim)
78 {
79     if (this != &anim){
80         memcpy(this, &anim, sizeof(AnimationInfo));
81         is_copy = true;
82     }
83     return *this;
84 }
85 
86 
deepcopy(const AnimationInfo & anim)87 void AnimationInfo::deepcopy(const AnimationInfo &anim)
88 {
89     if (this != &anim){
90         reset();
91         //copy the whole object
92         memcpy(this, &anim, sizeof(AnimationInfo));
93         if (anim.is_copy){
94             return;
95         }
96         //unset the image_surface due to danger of accidental deletion
97         image_surface = NULL;
98 #ifdef BPP16
99         alpha_buf = NULL;
100 #endif
101         //now set dynamic variables
102         //duration_list = anim.duration_list;
103         //color_list = anim.color_list;
104         image_name = anim.image_name;
105         file_name = anim.file_name;
106         mask_file_name = anim.mask_file_name;
107 
108         if (anim.image_surface) {
109             int w = anim.image_surface->w, h = anim.image_surface->h;
110             allocImage( w, h );
111             copySurface(anim.image_surface, NULL);
112 #ifdef BPP16
113             memcpy(alpha_buf, anim.alpha_buf, w*h);
114 #endif
115         }
116     }
117     locked = 0;
118 }
119 
120 
121 #ifdef _WIN32
122 #include <windows.h>
123 #define msleep Sleep
124 #else
125 #include <unistd.h>
126 #define msleep(x) usleep(x * 1000)
127 #endif
128 
reset()129 void AnimationInfo::reset()
130 {
131     // This is stupid and ugly, but it seems to work well enough.
132     // See lame excuses in header.
133     int prevent_deadlock = 0;
134     if (locked)
135         fprintf(stderr, "Resetting an AnimationInfo that's still in use! Don't worry, I noticed in time.\n");
136     while (locked) {
137         msleep(1);
138         if (++prevent_deadlock > 2000) {
139             fprintf(stderr, "AnimationInfo is deadlocked, expect trouble\n");
140             locked = 0;
141             break;
142         }
143     }
144 
145     remove();
146 
147     trans = 256;
148     orig_pos.x = orig_pos.y = 0;
149     orig_pos.w = orig_pos.h = 0;
150     pos.x = pos.y = 0;
151     pos.w = pos.h = 0;
152     abs_flag = true;
153     showing_ = false;
154     visible_ = false;
155     enabled_ = true;
156     enablemode = 0;
157 
158     scale_x = scale_y = rot = 0;
159     blending_mode = BLEND_NORMAL;
160 
161     font_size_x = font_size_y = -1;
162     font_pitch  = -1;
163 
164     mat[0][0] = 1000;
165     mat[0][1] = 0;
166     mat[1][0] = 0;
167     mat[1][1] = 1000;
168 
169 #ifndef NO_LAYER_EFFECTS
170     layer_no = -1;
171 #endif
172 }
173 
deleteImage()174 void AnimationInfo::deleteImage()
175 {
176     if (!is_copy && image_surface) SDL_FreeSurface(image_surface);
177     image_surface = NULL;
178 #ifdef BPP16
179     if (!is_copy && alpha_buf) delete[] alpha_buf;
180     alpha_buf = NULL;
181 #endif
182 }
183 
184 
remove()185 void AnimationInfo::remove()
186 {
187     image_name = "";
188     deleteImage();
189     removeTag();
190 }
191 
192 
removeTag()193 void AnimationInfo::removeTag()
194 {
195     //duration_list.clear();
196     //color_list.clear();
197 
198     file_name        = "";
199     mask_file_name   = "";
200     current_cell     = 0;
201     num_of_cells     = 0;
202     remaining_time   = 0;
203     is_animatable    = false;
204     is_single_line   = true;
205     is_tight_region  = true;
206     is_ruby_drawable = false;
207     skip_whitespace = true;
208     is_centered_text = false;
209     direction = 1;
210 
211     color.set(0);
212 }
213 
214 
215 // 0 ... restart at the end
216 // 1 ... stop at the end
217 // 2 ... reverse at the end
218 // 3 ... no animation
proceedAnimation()219 bool AnimationInfo::proceedAnimation()
220 {
221     bool is_changed = false;
222 
223     if (loop_mode != 3 && num_of_cells > 1) {
224         current_cell += direction;
225         is_changed = true;
226     }
227 
228     if (current_cell < 0) { // loop_mode must be 2
229         current_cell = 1;
230         direction = 1;
231     }
232     else if (current_cell >= num_of_cells) {
233         if (loop_mode == 0) {
234             current_cell = 0;
235         }
236         else if (loop_mode == 1) {
237             current_cell = num_of_cells - 1;
238             is_changed = false;
239         }
240         else {
241             current_cell = num_of_cells - 2;
242             direction = -1;
243         }
244     }
245 
246     remaining_time = duration_list[current_cell];
247 
248     return is_changed;
249 }
250 
251 
setCell(int cell)252 void AnimationInfo::setCell(int cell)
253 {
254     if (cell < 0) cell = 0;
255     else if (cell >= num_of_cells) cell = num_of_cells - 1;
256 
257     current_cell = cell;
258 }
259 
260 
doClipping(SDL_Rect * dst,SDL_Rect * clip,SDL_Rect * clipped)261 int AnimationInfo::doClipping(SDL_Rect* dst, SDL_Rect* clip, SDL_Rect* clipped)
262 {
263     if (clipped) clipped->x = clipped->y = 0;
264 
265     if (!dst
266         || dst->x >= clip->x + clip->w || dst->x + dst->w <= clip->x
267         || dst->y >= clip->y + clip->h || dst->y + dst->h <= clip->y)
268         return -1;
269 
270     if (dst->x < clip->x) {
271         dst->w -= clip->x - dst->x;
272         if (clipped) clipped->x = clip->x - dst->x;
273 
274         dst->x = clip->x;
275     }
276 
277     if (clip->x + clip->w < dst->x + dst->w) {
278         dst->w = clip->x + clip->w - dst->x;
279     }
280 
281     if (dst->y < clip->y) {
282         dst->h -= clip->y - dst->y;
283         if (clipped) clipped->y = clip->y - dst->y;
284 
285         dst->y = clip->y;
286     }
287 
288     if (clip->y + clip->h < dst->y + dst->h) {
289         dst->h = clip->y + clip->h - dst->y;
290     }
291 
292     if (clipped) {
293         clipped->w = dst->w;
294         clipped->h = dst->h;
295     }
296 
297     return 0;
298 }
299 
300 
findOpaquePoint(SDL_Rect * clip)301 SDL_Rect AnimationInfo::findOpaquePoint(SDL_Rect *clip)
302 //find the first opaque-enough pixel position for transbtn
303 {
304     int cell_width = image_surface->w/num_of_cells;
305     SDL_Rect cliprect = {0, 0, cell_width, image_surface->h};
306     if (clip) cliprect = *clip;
307 
308 #ifdef BPP16
309     const int psize = 1;
310     unsigned char *alphap = alpha_buf;
311 #else
312     const int psize = 4;
313     unsigned char *alphap = (unsigned char *)image_surface->pixels;
314 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
315     alphap += 3;
316 #endif
317 #endif
318 
319     SDL_Rect ret = {0, 0, 0, 0};
320 
321     for (int i=cliprect.y ; i<cliprect.h ; ++i){
322         for (int j=cliprect.x ; j<cliprect.w ; ++j){
323             int alpha = *(alphap + (image_surface->w * i + j) * psize);
324             if (alpha > TRANSBTN_CUTOFF){
325                 ret.x = j;
326                 ret.y = i;
327                 //want to break out of the for loops
328                 i = cliprect.h;
329                 break;
330             }
331         }
332     }
333     //want to find a pixel that's opaque across all cells, if possible
334     int xstart = ret.x;
335     for (int i=ret.y ; i<cliprect.h ; ++i){
336         for (int j=xstart ; j<cliprect.w ; ++j){
337             bool is_opaque = true;
338             for (int k=0 ; k<num_of_cells ; ++k){
339                 int alpha = *(alphap +
340                               ((image_surface->w * i + cell_width * k + j) *
341                                psize));
342                 if (alpha <= TRANSBTN_CUTOFF){
343                     is_opaque = false;
344                     break;
345                 }
346             }
347             if (is_opaque){
348                 ret.x = j;
349                 ret.y = i;
350                 //want to break out of the for loops
351                 i = cliprect.h;
352                 break;
353             }
354             xstart = cliprect.x;
355         }
356     }
357 
358     return ret;
359 }
360 
361 
getPixelAlpha(int x,int y)362 int AnimationInfo::getPixelAlpha(int x, int y)
363 {
364 #ifdef BPP16
365     unsigned char *alphap = alpha_buf + image_surface->w * y + x +
366                             image_surface->w*current_cell/num_of_cells;
367 #else
368     const int psize = 4;
369     const int total_width = image_surface->w * psize;
370     unsigned char *alphap = (unsigned char *)image_surface->pixels +
371                             total_width * current_cell/num_of_cells +
372                             total_width * y + x * psize;
373 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
374     alphap += 3;
375 #endif
376 #endif
377     return (int) *alphap;
378 }
379 
380 
blendOnSurface(SDL_Surface * dst_surface,int dst_x,int dst_y,SDL_Rect & clip,int alpha)381 void AnimationInfo::blendOnSurface(SDL_Surface* dst_surface, int dst_x,
382                                    int dst_y, SDL_Rect &clip, int alpha)
383 {
384     if (!image_surface || !dst_surface) return;
385 
386     SDL_Rect dst_rect = { dst_x, dst_y, pos.w, pos.h }, src_rect;
387     if (doClipping(&dst_rect, &clip, &src_rect)) return;
388 
389     /* ---------------------------------------- */
390 
391     ++locked;
392 
393     SDL_LockSurface(dst_surface);
394     SDL_LockSurface(image_surface);
395 
396 #ifdef BPP16
397     const int total_width = image_surface->pitch / 2;
398 #else
399     const int total_width = image_surface->pitch / 4;
400 #endif
401     ONSBuf* src_buffer = (ONSBuf*) image_surface->pixels +
402                          total_width * src_rect.y +
403                          image_surface->w * current_cell / num_of_cells +
404                          src_rect.x;
405     ONSBuf* dst_buffer = (ONSBuf*) dst_surface->pixels +
406                          dst_surface->w * dst_rect.y + dst_rect.x;
407 #ifdef BPP16
408     unsigned char* alphap = alpha_buf + image_surface->w * src_rect.y +
409                             image_surface->w * current_cell / num_of_cells +
410                             src_rect.x;
411 #else
412 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
413     unsigned char* alphap = (unsigned char*) src_buffer + 3;
414 #else
415     unsigned char* alphap = (unsigned char*) src_buffer;
416 #endif
417 #endif
418 
419 #ifndef BPP16
420     if (blending_mode == BLEND_NORMAL) {
421 #endif
422         if ((trans_mode == TRANS_COPY) && (alpha == 256)) {
423             ONSBuf* srcmax = (ONSBuf*)image_surface->pixels +
424                 image_surface->w * image_surface->h;
425 
426             for (int i=dst_rect.h ; i ; --i){
427                 for (int j=dst_rect.w ; j ; --j, src_buffer++, dst_buffer++){
428                     // If we've run out of source area, ignore the remainder.
429                     if (src_buffer >= srcmax) goto break2;
430                     SET_PIXEL(*src_buffer, 0xff);
431                 }
432                 src_buffer += total_width - dst_rect.w;
433 #ifdef BPP16
434                 alphap += image_surface->w - dst_rect.w;
435 #else
436                 alphap += (image_surface->w - dst_rect.w)*4;
437 #endif
438                 dst_buffer += dst_surface->w  - dst_rect.w;
439             }
440         } else if (alpha != 0) {
441             ONSBuf* srcmax = (ONSBuf*)image_surface->pixels +
442                 image_surface->w * image_surface->h;
443 
444             for (int i=dst_rect.h ; i ; --i){
445 #ifdef BPP16
446                 for (int j=dst_rect.w ; j ; --j, src_buffer++, dst_buffer++){
447                     // If we've run out of source area, ignore the remainder.
448                     if (src_buffer >= srcmax) goto break2;
449                     BLEND_PIXEL();
450                 }
451                 src_buffer += total_width - dst_rect.w;
452                 dst_buffer += dst_surface->w - dst_rect.w;
453                 alphap += image_surface->w - dst_rect.w;
454 #else
455                 if (src_buffer >= srcmax) goto break2;
456                 gfx.imageFilterBlend(dst_buffer, src_buffer, alphap, alpha,
457                                  dst_rect.w);
458                 src_buffer += total_width;
459                 dst_buffer += dst_surface->w;
460                 alphap += (image_surface->w)*4;
461 #endif
462             }
463         }
464 #ifndef BPP16
465     } else if (blending_mode == BLEND_ADD) {
466         if ((trans_mode == TRANS_COPY) && (alpha == 256)) {
467             // "add" the src pix value to the dst
468             Uint8* srcmax = (Uint8*) ((Uint32*)image_surface->pixels +
469                 image_surface->w * image_surface->h);
470             Uint8* src_buf = (Uint8*) src_buffer;
471             Uint8* dst_buf = (Uint8*) dst_buffer;
472 
473             for (int i=dst_rect.h ; i ; --i){
474                 if (src_buf >= srcmax) goto break2;
475                 gfx.imageFilterAddTo(dst_buf, src_buf, dst_rect.w*4);
476                 src_buf += total_width * 4;
477                 dst_buf += dst_surface->w * 4;
478             }
479         } else if (alpha != 0) {
480             // gotta do additive alpha blending
481             Uint32* srcmax = (Uint32*)image_surface->pixels +
482                 image_surface->w * image_surface->h;
483 
484             for (int i=dst_rect.h ; i ; --i){
485                 for (int j=dst_rect.w ; j ; --j, src_buffer++, dst_buffer++){
486                     // If we've run out of source area, ignore the remainder.
487                     if (src_buffer >= srcmax) goto break2;
488                         ADDBLEND_PIXEL();
489                     }
490                 src_buffer += total_width - dst_rect.w;
491                 alphap += (image_surface->w - dst_rect.w)*4;
492                 dst_buffer += dst_surface->w  - dst_rect.w;
493             }
494         }
495     } else if (blending_mode == BLEND_SUB) {
496         if ((trans_mode == TRANS_COPY) && (alpha == 256)) {
497             // "subtract" the src pix value from the dst
498             Uint8* srcmax = (Uint8*) ((Uint32*)image_surface->pixels +
499                 image_surface->w * image_surface->h);
500             Uint8* src_buf = (Uint8*) src_buffer;
501             Uint8* dst_buf = (Uint8*) dst_buffer;
502 
503             for (int i=dst_rect.h ; i ; --i){
504                 if (src_buf >= srcmax) goto break2;
505                 gfx.imageFilterSubFrom(dst_buf, src_buf, dst_rect.w*4);
506                 src_buf += total_width * 4;
507                 dst_buf += dst_surface->w * 4;
508             }
509         } else if (alpha != 0) {
510             // gotta do subtractive alpha blending
511             Uint32* srcmax = (Uint32*)image_surface->pixels +
512                 image_surface->w * image_surface->h;
513 
514             for (int i=dst_rect.h ; i ; --i){
515                 for (int j=dst_rect.w ; j ; --j, src_buffer++, dst_buffer++){
516                     // If we've run out of source area, ignore the remainder.
517                     if (src_buffer >= srcmax) goto break2;
518                         SUBBLEND_PIXEL();
519                     }
520                 src_buffer += total_width - dst_rect.w;
521                 alphap += (image_surface->w - dst_rect.w)*4;
522                 dst_buffer += dst_surface->w  - dst_rect.w;
523             }
524         }
525     }
526 #endif
527 break2:
528     SDL_UnlockSurface( image_surface );
529     SDL_UnlockSurface( dst_surface );
530 
531     --locked;
532 }
533 
534 
blendOnSurface2(SDL_Surface * dst_surface,int dst_x,int dst_y,SDL_Rect & clip,int alpha)535 void AnimationInfo::blendOnSurface2(SDL_Surface* dst_surface, int dst_x,
536                                     int dst_y, SDL_Rect &clip, int alpha)
537 {
538     if (image_surface == NULL) return;
539     if (scale_x == 0 || scale_y == 0) return;
540 
541     int i, x, y;
542 
543     // project corner point and calculate bounding box
544     int min_xy[2] = { bounding_rect.x, bounding_rect.y };
545     int max_xy[2] = { bounding_rect.x + bounding_rect.w - 1,
546                       bounding_rect.y + bounding_rect.h - 1 };
547 
548     // clip bounding box
549     if (max_xy[0] < clip.x) return;
550     if (max_xy[0] >= clip.x + clip.w) max_xy[0] = clip.x + clip.w - 1;
551     if (min_xy[0] >= clip.x + clip.w) return;
552     if (min_xy[0] < clip.x) min_xy[0] = clip.x;
553     if (max_xy[1] < clip.y) return;
554     if (max_xy[1] >= clip.y + clip.h) max_xy[1] = clip.y + clip.h - 1;
555     if (min_xy[1] >= clip.y + clip.h) return;
556     if (min_xy[1] < clip.y) min_xy[1] = clip.y;
557 
558     SDL_LockSurface(dst_surface);
559     SDL_LockSurface(image_surface);
560 
561 #ifdef BPP16
562     int total_width = image_surface->pitch / 2;
563 #else
564     int total_width = image_surface->pitch / 4;
565 #endif
566     // set pixel by inverse-projection with raster scan
567     for (y = min_xy[1]; y <= max_xy[1]; y++) {
568         // calculate the start and end point for each raster scan
569         int raster_min = min_xy[0], raster_max = max_xy[0];
570         for (i = 0; i < 4; i++) {
571             if (corner_xy[i][1] == corner_xy[(i + 1) % 4][1])
572                 continue;
573             x = ((corner_xy[(i + 1) % 4][0] - corner_xy[i][0]) *
574                  (y - corner_xy[i][1]) /
575                  (corner_xy[(i + 1) % 4][1] - corner_xy[i][1])) +
576                 corner_xy[i][0];
577             if (corner_xy[(i + 1) % 4][1] - corner_xy[i][1] > 0) {
578                 if (raster_min < x) raster_min = x;
579             }
580             else {
581                 if (raster_max > x) raster_max = x;
582             }
583         }
584 
585         ONSBuf* dst_buffer = (ONSBuf*) dst_surface->pixels + dst_surface->w * y + raster_min;
586 
587         // inverse-projection
588         int x_offset = inv_mat[0][1] * (y - dst_y) / 1000 + pos.w / 2;
589         int y_offset = inv_mat[1][1] * (y - dst_y) / 1000 + pos.h / 2;
590         for (x = raster_min - dst_x; x <= raster_max - dst_x; x++, dst_buffer++) {
591             int x2 = inv_mat[0][0] * x / 1000 + x_offset;
592             int y2 = inv_mat[1][0] * x / 1000 + y_offset;
593 
594             if (x2 < 0 || x2 >= pos.w
595                 || y2 < 0 || y2 >= pos.h) continue;
596 
597             ONSBuf* src_buffer = (ONSBuf*) image_surface->pixels + total_width * y2 + x2 + pos.w * current_cell;
598 #ifdef BPP16
599             unsigned char* alphap = alpha_buf + image_surface->w * y2 + x2 + pos.w * current_cell;
600 #else
601 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
602             unsigned char* alphap = (unsigned char*) src_buffer + 3;
603 #else
604             unsigned char* alphap = (unsigned char*) src_buffer;
605 #endif
606 #endif
607 #ifndef BPP16
608             if (blending_mode == BLEND_NORMAL) {
609 #endif
610                 if ((trans_mode == TRANS_COPY) && (alpha == 256)) {
611                     SET_PIXEL(*src_buffer, 0xff);
612                 } else {
613                     BLEND_PIXEL();
614                 }
615 #ifndef BPP16
616             } else if (blending_mode == BLEND_ADD) {
617                 ADDBLEND_PIXEL();
618             } else if (blending_mode == BLEND_SUB) {
619                 SUBBLEND_PIXEL();
620             }
621 #endif
622         }
623     }
624 
625     // unlock surface
626     SDL_UnlockSurface(image_surface);
627     SDL_UnlockSurface(dst_surface);
628 }
629 
630 
631 // used to draw characters on text_surface
632 // Alpha = 1 - (1-Da)(1-Sa)
633 // Color = (DaSaSc + Da(1-Sa)Dc + Sa(1-Da)Sc)/A
blendText(SDL_Surface * surface,int dst_x,int dst_y,SDL_Color & color,SDL_Rect * clip,bool rotate_flag)634 void AnimationInfo::blendText( SDL_Surface *surface, int dst_x, int dst_y,
635                                SDL_Color &color, SDL_Rect *clip,
636                                bool rotate_flag )
637 {
638     if (image_surface == NULL || surface == NULL) return;
639 
640     SDL_Rect dst_rect = { dst_x, dst_y, surface->w, surface->h };
641     if (rotate_flag){
642         dst_rect.w = surface->h;
643         dst_rect.h = surface->w;
644     }
645     SDL_Rect src_rect = { 0, 0, 0, 0 };
646     SDL_Rect clipped_rect;
647 
648     /* ---------------------------------------- */
649     /* 1st clipping */
650     if (clip) {
651         if (doClipping(&dst_rect, clip, &clipped_rect)) return;
652 
653         src_rect.x += clipped_rect.x;
654         src_rect.y += clipped_rect.y;
655     }
656 
657     /* ---------------------------------------- */
658     /* 2nd clipping */
659     SDL_Rect clip_rect = { 0, 0, image_surface->w, image_surface->h };
660     if (doClipping(&dst_rect, &clip_rect, &clipped_rect)) return;
661 
662     src_rect.x += clipped_rect.x;
663     src_rect.y += clipped_rect.y;
664 
665     /* ---------------------------------------- */
666 
667     SDL_LockSurface(surface);
668     SDL_LockSurface(image_surface);
669 
670 #ifdef BPP16
671     int total_width = image_surface->pitch / 2;
672     Uint32 src_color = ((color.r >> RLOSS) << RSHIFT) |
673                        ((color.g >> GLOSS) << GSHIFT) |
674                        (color.b >> BLOSS);
675     src_color = (src_color | src_color << 16) & BLENDMASK;
676 #else
677     int total_width = image_surface->pitch / 4;
678     Uint32 src_color1 = color.r << RSHIFT | color.b;
679     Uint32 src_color2 = color.g << GSHIFT;
680 #endif
681     ONSBuf *dst_buffer = (ONSBuf *)image_surface->pixels +
682                          total_width * dst_rect.y +
683                          image_surface->w*current_cell/num_of_cells +
684                          dst_rect.x;
685 #ifdef BPP16
686     unsigned char *alphap = alpha_buf + image_surface->w * dst_rect.y +
687                             image_surface->w*current_cell/num_of_cells +
688                             dst_rect.x;
689 #endif
690     if (!rotate_flag){
691         unsigned char *src_buffer = (unsigned char*)surface->pixels +
692                                     surface->pitch*src_rect.y + src_rect.x;
693         for (int i=dst_rect.h; i>0; i--){
694             for (int j=dst_rect.w; j>0; j--, dst_buffer++, src_buffer++){
695                 BLEND_PIXEL8_ALPHA();
696             }
697             dst_buffer += total_width - dst_rect.w;
698 #ifdef BPP16
699             alphap += image_surface->w - dst_rect.w;
700 #endif
701             src_buffer += surface->pitch - dst_rect.w;
702         }
703     }
704     else{
705         for (int i=0; i<dst_rect.h; i++){
706             unsigned char *src_buffer = (unsigned char*)surface->pixels +
707                                         surface->pitch * (surface->h -
708                                                           src_rect.x - 1) +
709                                         src_rect.y + i;
710             for (int j=dst_rect.w; j>0; j--, dst_buffer++){
711                 BLEND_PIXEL8_ALPHA();
712                 src_buffer -= surface->pitch;
713             }
714             dst_buffer += total_width - dst_rect.w;
715 #ifdef BPP16
716             alphap += image_surface->w - dst_rect.w;
717 #endif
718         }
719     }
720 
721     SDL_UnlockSurface(image_surface);
722     SDL_UnlockSurface(surface);
723 }
724 
725 
calcAffineMatrix()726 void AnimationInfo::calcAffineMatrix()
727 {
728     // calculate forward matrix
729     // |mat[0][0] mat[0][1]|
730     // |mat[1][0] mat[1][1]|
731     int cos_i = 1000, sin_i = 0;
732     if (rot != 0){
733         cos_i = (int)(1000.0 * cos(-M_PI * rot / 180));
734         sin_i = (int)(1000.0 * sin(-M_PI * rot / 180));
735     }
736     mat[0][0] =  cos_i * scale_x / 100;
737     mat[0][1] = -sin_i * scale_y / 100;
738     mat[1][0] =  sin_i * scale_x / 100;
739     mat[1][1] =  cos_i * scale_y / 100;
740 
741     // calculate bounding box
742     int min_xy[2] = { 0, 0 }, max_xy[2] = { 0, 0 };
743     for (int i = 0; i < 4; ++i) {
744         int c_x = i < 2       ? -pos.w / 2 :  pos.w / 2;
745         int c_y = (i + 1) & 2 ?  pos.h / 2 : -pos.h / 2;
746         //Mion: need to make sure corners are in right order (UL,LL,LR,UR)
747         if (scale_x < 0) c_x = -c_x;
748         if (scale_y < 0) c_y = -c_y;
749         corner_xy[i][0] = (mat[0][0] * c_x + mat[0][1] * c_y) / 1000 + pos.x;
750         corner_xy[i][1] = (mat[1][0] * c_x + mat[1][1] * c_y) / 1000 + pos.y;
751 
752         if (i==0 || min_xy[0] > corner_xy[i][0]) min_xy[0] = corner_xy[i][0];
753         if (i==0 || max_xy[0] < corner_xy[i][0]) max_xy[0] = corner_xy[i][0];
754         if (i==0 || min_xy[1] > corner_xy[i][1]) min_xy[1] = corner_xy[i][1];
755         if (i==0 || max_xy[1] < corner_xy[i][1]) max_xy[1] = corner_xy[i][1];
756     }
757 
758     bounding_rect.x = min_xy[0];
759     bounding_rect.y = min_xy[1];
760     bounding_rect.w = max_xy[0] - min_xy[0] + 1;
761     bounding_rect.h = max_xy[1] - min_xy[1] + 1;
762 
763     // calculate inverse matrix
764     int denom = scale_x * scale_y;
765     if (denom == 0) return;
766 
767     inv_mat[0][0] =  mat[1][1] * 10000 / denom;
768     inv_mat[0][1] = -mat[0][1] * 10000 / denom;
769     inv_mat[1][0] = -mat[1][0] * 10000 / denom;
770     inv_mat[1][1] =  mat[0][0] * 10000 / denom;
771 }
772 
773 
allocSurface(int w,int h)774 SDL_Surface* AnimationInfo::allocSurface(int w, int h)
775 {
776     return SDL_CreateRGBSurface(0, w, h, BPP, RMASK, GMASK, BMASK, AMASK);
777 }
778 
779 
allocImage(int w,int h)780 void AnimationInfo::allocImage(int w, int h)
781 {
782     if (!image_surface
783         || image_surface->w != w
784         || image_surface->h != h) {
785         deleteImage();
786 
787         image_surface = allocSurface(w, h);
788 #ifdef BPP16
789         if (image_surface)
790         alpha_buf = new unsigned char[w * h];
791 #endif
792     }
793 
794     abs_flag = true;
795     pos.w = w / num_of_cells;
796     pos.h = h;
797 }
798 
799 
copySurface(SDL_Surface * surface,SDL_Rect * src_rect,SDL_Rect * dst_rect)800 void AnimationInfo::copySurface(SDL_Surface* surface, SDL_Rect* src_rect,
801                                 SDL_Rect* dst_rect)
802 {
803     if (!image_surface || !surface) return;
804 
805     SDL_Rect _dst_rect = {0, 0, image_surface->w, image_surface->h};
806     if (dst_rect) _dst_rect = *dst_rect;
807 
808     SDL_Rect _src_rect = {0, 0, surface->w, surface->h};
809     if (src_rect) _src_rect = *src_rect;
810 
811     if (_src_rect.x >= surface->w) return;
812     if (_src_rect.y >= surface->h) return;
813 
814     if (_src_rect.x+_src_rect.w >= surface->w)
815         _src_rect.w = surface->w - _src_rect.x;
816     if (_src_rect.y+_src_rect.h >= surface->h)
817         _src_rect.h = surface->h - _src_rect.y;
818 
819     if (_dst_rect.x+_src_rect.w > image_surface->w)
820         _src_rect.w = image_surface->w - _dst_rect.x;
821     if (_dst_rect.y+_src_rect.h > image_surface->h)
822         _src_rect.h = image_surface->h - _dst_rect.y;
823 
824     SDL_LockSurface( surface );
825     SDL_LockSurface( image_surface );
826 
827     int i;
828     for (i=0 ; i<_src_rect.h ; i++)
829         memcpy( (ONSBuf*)((unsigned char*)image_surface->pixels + image_surface->pitch * (_dst_rect.y+i)) + _dst_rect.x,
830                 (ONSBuf*)((unsigned char*)surface->pixels + surface->pitch * (_src_rect.y+i)) + _src_rect.x,
831                 _src_rect.w*sizeof(ONSBuf) );
832 #if defined(BPP16)
833     for (i=0 ; i<_src_rect.h ; i++)
834         memset( alpha_buf + image_surface->w * (_dst_rect.y+i) + _dst_rect.x, 0xff, _src_rect.w );
835 #endif
836 
837     SDL_UnlockSurface(image_surface);
838     SDL_UnlockSurface(surface);
839 }
840 
841 
fill(Uint8 r,Uint8 g,Uint8 b,Uint8 a)842 void AnimationInfo::fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
843 {
844     if (!image_surface) return;
845 
846     SDL_LockSurface(image_surface);
847     ONSBuf* dst_buffer = (ONSBuf*) image_surface->pixels;
848 
849 #ifdef BPP16
850     Uint32 rgb = ((r>>RLOSS) << RSHIFT) | ((g>>GLOSS) << GSHIFT) | (b>>BLOSS);
851     unsigned char *alphap = alpha_buf;
852     int dst_margin = image_surface->w % 2;
853 #else
854     Uint32 rgb = (r << RSHIFT) | (g << GSHIFT) | b;
855 
856 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
857     unsigned char *alphap = (unsigned char *)dst_buffer + 3;
858 #else
859     unsigned char *alphap = (unsigned char *)dst_buffer;
860 #endif
861     int dst_margin = 0;
862 #endif
863 
864     for (int i=0 ; i<image_surface->h ; i++){
865         for (int j=0 ; j<image_surface->w ; j++, dst_buffer++)
866             SET_PIXEL(rgb, a);
867         dst_buffer += dst_margin;
868     }
869     SDL_UnlockSurface( image_surface );
870 }
871 
872 
setupImage(SDL_Surface * surface,SDL_Surface * surface_m,bool has_alpha,int ratio1,int ratio2)873 void AnimationInfo::setupImage( SDL_Surface *surface, SDL_Surface *surface_m,
874                                 bool has_alpha, int ratio1, int ratio2 )
875 {
876     if (surface == NULL) return;
877 
878     SDL_LockSurface(surface);
879     Uint32* buffer = (Uint32*) surface->pixels;
880     SDL_PixelFormat *fmt = surface->format;
881 
882     int w = surface->w;
883     int h = surface->h;
884     int w2 = w / num_of_cells;
885     if ((trans_mode == TRANS_ALPHA) && !has_alpha)
886         w2 /= 2;
887     w = w2 * num_of_cells;
888     orig_pos.w = w;
889     orig_pos.h = h;
890 
891     // Create a 32bpp buffer for image processing
892 #ifdef BPP16
893     SDL_Surface *tmp = SDL_CreateRGBSurface( 0, w, h,
894                                              fmt->BitsPerPixel, fmt->Rmask,
895                                              fmt->Gmask, fmt->Bmask, fmt->Amask);
896     Uint32 *dst_buffer = (Uint32 *)tmp->pixels;
897 #else
898     allocImage(w, h);
899     SDL_Surface *tmp = image_surface;
900     ONSBuf *dst_buffer = (ONSBuf *)image_surface->pixels;
901 #endif
902 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
903     unsigned char *alphap = (unsigned char *)dst_buffer + 3;
904 #else
905     unsigned char *alphap = (unsigned char *)dst_buffer;
906 #endif
907 
908     Uint32 ref_color = 0;
909     if (trans_mode == TRANS_TOPLEFT) {
910         ref_color = *buffer;
911     }
912     else if (trans_mode == TRANS_TOPRIGHT) {
913         ref_color = *(buffer + surface->w - 1);
914     }
915     else if (trans_mode == TRANS_DIRECT) {
916         ref_color = direct_color.r << fmt->Rshift |
917                     direct_color.g << fmt->Gshift |
918                     direct_color.b << fmt->Bshift;
919     }
920 
921     ref_color &= RGBMASK;
922 
923     int i, j, c;
924     if ( trans_mode == TRANS_ALPHA ){
925         if (has_alpha){
926             for (i=h ; i>0 ; i--){
927                 for (j=w ; j>0 ; j--, buffer++, dst_buffer++)
928                     SET_PIXEL32(*buffer, *buffer >> 24);
929             }
930         }
931         else {
932             const int cw = surface->w / num_of_cells;
933             for (i=h ; i>0 ; i--){
934                 for (c=num_of_cells ; c>0 ; c--){
935                     for (j=w2 ; j>0 ; j--, buffer++, dst_buffer++){
936                         SET_PIXEL32(*buffer, (*(buffer+w2) & 0xff) ^ 0xff);
937                     }
938                     buffer += cw - w2;
939                 }
940                 buffer += surface->w - (cw * num_of_cells);
941             }
942         }
943     }
944     else if ( trans_mode == TRANS_MASK ){
945         if (surface_m){
946             SDL_LockSurface( surface_m );
947             int mw = surface_m->w;
948             int mh = surface_m->h;
949             if (!has_alpha){
950                 for (i=0 ; i<h ; i++){
951                     Uint32 *buffer_m = (Uint32 *)surface_m->pixels + mw*(i%mh);
952                     for (c=num_of_cells ; c>0 ; c--){
953                         for (j=0 ; j<w2 ; j++, buffer++, dst_buffer++){
954                             SET_PIXEL32(*buffer, (*(buffer_m + j%mw) & 0xff) ^ 0xff);
955                         }
956                     }
957                 }
958             } else {
959                 //if has_alpha, combine the pixel alpha with the mask value
960                 for (i=0 ; i<h ; i++){
961                     Uint32 *buffer_m = (Uint32 *)surface_m->pixels + mw*(i%mh);
962                     for (c=num_of_cells ; c>0 ; c--){
963                         for (j=0 ; j<w2 ; j++, buffer++, dst_buffer++){
964                             SET_PIXEL32(*buffer,
965                                         (((*(buffer_m + j%mw) & 0xff) ^ 0xff) *
966                                          (*buffer >> 24)) >> 8);
967                         }
968                     }
969                 }
970             }
971             SDL_UnlockSurface( surface_m );
972         } else {
973             for (i=h ; i>0 ; i--){
974                 for (j=w ; j>0 ; j--, buffer++, dst_buffer++)
975                     SET_PIXEL32(*buffer, 0xff);
976             }
977         }
978     }
979     else if (has_alpha){
980         for (i=h ; i>0 ; i--){
981             for (j=w ; j>0 ; j--, buffer++, dst_buffer++)
982                 SET_PIXEL32(*buffer, *buffer >> 24);
983         }
984     }
985     else if ( trans_mode == TRANS_TOPLEFT ||
986               trans_mode == TRANS_TOPRIGHT ||
987               trans_mode == TRANS_DIRECT ){
988         for (i=h ; i>0 ; i--){
989             for (j=w ; j>0 ; j--, buffer++, dst_buffer++){
990                 if ( (*buffer & RGBMASK) == ref_color ){
991                     SET_PIXEL32(MEDGRAY, 0x00);
992                 }
993                 else{
994                     SET_PIXEL32(*buffer, 0xff);
995                 }
996             }
997         }
998     }
999     else if ( trans_mode == TRANS_STRING ){
1000         for (i=h ; i>0 ; i--){
1001             for (j=w ; j>0 ; j--, buffer++, dst_buffer++)
1002                 SET_PIXEL32(*buffer, *buffer >> 24);
1003         }
1004     }
1005     else { // TRANS_COPY
1006         for (i=h ; i>0 ; i--){
1007             for (j=w ; j>0 ; j--, buffer++, dst_buffer++)
1008                 SET_PIXEL32(*buffer, 0xff);
1009         }
1010     }
1011 
1012     SDL_UnlockSurface( surface );
1013 
1014     if (ratio1 != ratio2) {
1015         SDL_Surface *src_s = tmp;
1016 
1017         w = ((src_s->w / num_of_cells) * ratio1 / ratio2) * num_of_cells;
1018         if (w >= 16384){
1019             //too wide for SDL_Surface pitch (Uint16) at 4bpp; size differently
1020             fprintf(stderr, " *** image '%s' is too wide to resize to (%d,%d); ",
1021                     (const char *)file_name, w, src_s->h * ratio1 / ratio2);
1022             int ratio3 = 16384 * ratio2 / src_s->w;
1023             w = ((src_s->w / num_of_cells) * ratio3 / ratio2) * num_of_cells;
1024             h = src_s->h * ratio3 / ratio2;
1025             if ( h == 0 ) h = 1;
1026             fprintf(stderr, "resizing to (%d,%d) instead *** \n", w, h);
1027         }else{
1028             if ( w == 0 ) w = num_of_cells;
1029             h = src_s->h * ratio1 / ratio2;
1030             if ( h == 0 ) h = 1;
1031         }
1032 #ifdef BPP16
1033         tmp = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h,
1034                                     fmt->BitsPerPixel, fmt->Rmask,
1035                                     fmt->Gmask, fmt->Bmask, fmt->Amask);
1036 #else
1037         image_surface = NULL;
1038         allocImage(w, h);
1039         tmp = image_surface;
1040 #endif
1041         resizeSurface( src_s, tmp, num_of_cells );
1042         SDL_FreeSurface( src_s );
1043     }
1044 #ifdef BPP16
1045     allocImage(w, h);
1046     ONSBuf *img_buffer = (ONSBuf *)image_surface->pixels;
1047     alphap = alpha_buf;
1048     buffer = (Uint32 *)tmp->pixels;
1049     for (i=0 ; i<h ; i++){
1050         for (j=0 ; j<w ; j++, buffer++, img_buffer++)
1051             SET_PIXEL32TO16(*buffer, *buffer >> 24);
1052         img_buffer += w % 2;
1053     }
1054     SDL_FreeSurface( tmp );
1055 #endif
1056 }
1057 
1058 
update_showing()1059 bool AnimationInfo::update_showing()
1060 {
1061     bool do_show = visible_ && enabled_;
1062     if (showing_ != do_show) {
1063         showing_ = do_show;
1064         return true;
1065     }
1066     return false;
1067 }
1068 
1069 
1070 #include "resize_image.h"
1071 
1072 static unsigned char *resize_buffer = NULL;
1073 static size_t resize_buffer_size = 0;
1074 
resetResizeBuffer()1075 void AnimationInfo::resetResizeBuffer() {
1076     if (resize_buffer_size != 16){
1077         if (resize_buffer) delete[] resize_buffer;
1078         resize_buffer = new unsigned char[16];
1079         resize_buffer_size = 16;
1080     }
1081 }
1082 
1083 
1084 // resize 32bit surface to 32bit surface
resizeSurface(SDL_Surface * src,SDL_Surface * dst,int num_cells)1085 int AnimationInfo::resizeSurface( SDL_Surface *src, SDL_Surface *dst, int num_cells )
1086 {
1087     SDL_LockSurface( dst );
1088     SDL_LockSurface( src );
1089     Uint32 *src_buffer = (Uint32 *)src->pixels;
1090     Uint32 *dst_buffer = (Uint32 *)dst->pixels;
1091 
1092     /* size of tmp_buffer must be larger than 16 bytes */
1093     size_t len = src->w * (src->h+1) * 4 + 4;
1094     if (resize_buffer_size < len){
1095         if (resize_buffer) delete[] resize_buffer;
1096         resize_buffer = new unsigned char[len];
1097         resize_buffer_size = len;
1098     }
1099     resizeImage( (unsigned char*)dst_buffer, dst->w, dst->h, dst->w * 4,
1100                  (unsigned char*)src_buffer, src->w, src->h, src->w * 4,
1101                  4, resize_buffer, src->w * 4, num_cells );
1102 
1103     SDL_UnlockSurface( src );
1104     SDL_UnlockSurface( dst );
1105 
1106     return 0;
1107 }
1108