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