0
|
1 /*
|
|
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno
|
|
3 * All rights reserved.
|
|
4 *
|
|
5 * Redistribution and use in source and binary forms, with or without
|
|
6 * modification, are permitted provided that the following conditions
|
|
7 * are met:
|
|
8 * 1. Redistributions of source code must retain the above copyright
|
|
9 * notice, this list of conditions and the following disclaimer.
|
|
10 * 2. Redistributions in binary form must reproduce the above copyright
|
|
11 * notice, this list of conditions and the following disclaimer in the
|
|
12 * documentation and/or other materials provided with the distribution.
|
|
13 * 3. The name of the author may not be used to endorse or promote products
|
|
14 * derived from this software without specific prior written permission.
|
|
15 *
|
|
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26 */
|
|
27
|
|
28 #include<stdio.h>
|
|
29 #include<vector>
|
|
30 #include<list>
|
|
31 #include<algorithm>
|
|
32
|
|
33 #include"rect.h"
|
|
34 #include"event.h"
|
|
35 #include"font/font.h"
|
|
36 #include"font/text.h"
|
|
37 #include"SDL_rotozoom.h"
|
|
38 #include"system/file.h"
|
|
39
|
|
40 #include"picture.h"
|
|
41
|
|
42 using namespace std;
|
|
43
|
|
44 int print_blit=0;
|
|
45 inline void dprintf(const char* fmt, ...) {}
|
|
46 /* render.cc */
|
|
47 void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
|
|
48 void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
|
|
49 void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect);
|
|
50 void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // クリア
|
|
51 #if 0 /* DEBUG */
|
|
52 #include<sys/types.h>
|
|
53 #include<sys/time.h>
|
|
54 #define dprintf printf
|
|
55 static struct timeval tv;
|
|
56 void gettm(void) {
|
|
57 gettimeofday(&tv, 0);
|
|
58 }
|
|
59 int calctm(void) {
|
|
60 struct timeval tv2;
|
|
61 gettimeofday(&tv2, 0);
|
|
62 int n = (tv2.tv_sec-tv.tv_sec)*100000 + (tv2.tv_usec-tv.tv_usec)/10;
|
|
63 return n;
|
|
64 }
|
|
65 #endif
|
|
66
|
|
67 /******************************************
|
|
68 ** PicBase
|
|
69 */
|
|
70 PicBase::PicBase(const Rect& _rel_pos, PicContainer* _parent, int _attr) :
|
|
71 parent(_parent), rel_pos(_rel_pos), rel_solid_area(0,0,0,0), clip_area(0,0,0,0),
|
|
72 is_hidden(true), is_hidden_now(true), is_cached(false), attribute(_attr), surface_alpha_rect(0,0) {
|
|
73
|
|
74 if (parent) root = parent->root;
|
|
75 else root = 0;
|
|
76 surface_back = 0;
|
|
77 surface_own = 0;
|
|
78 surface_alpha = 0;
|
|
79 surface_x = 0; surface_y = 0;
|
|
80 surface_w = -1; surface_h = -1;
|
|
81 widget = 0;
|
|
82 attribute |= NO_PICTURE;
|
|
83 if ( (attribute & CACHE_BACK) && root) {
|
|
84 surface_back = root->NewSurface(rel_pos.width(), rel_pos.height(), NO_MASK);
|
|
85 }
|
|
86
|
|
87 if (parent) {
|
|
88 parent->children.push_back(this);
|
|
89 z_pos = parent->children.end(); z_pos--;
|
|
90 distance_root = parent->DistanceRoot() + 1;
|
|
91 } else {
|
|
92 distance_root = 1;
|
|
93 }
|
|
94 }
|
|
95 PicBase::~PicBase() {
|
|
96 ClearAnm();
|
|
97 if (widget) {
|
|
98 fprintf(stderr,"Warning: PicBase::~PicBase: surface is disallocated but widget is still alive.\n");
|
|
99 widget->deactivate();
|
|
100 }
|
|
101 if (surface_back) root->DeleteSurface(surface_back);
|
|
102 if (surface_own && (attribute & SURFACE_FREE)) root->DeleteSurface(surface_own);
|
|
103 if (surface_alpha && (attribute & ALPHA_FREE)) delete surface_alpha;
|
|
104 iterator it;
|
|
105 if (parent) { // 自分を親から削除
|
|
106 parent->children.remove(this);
|
|
107 // root の update 情報から自分を削除
|
|
108 parent->Root().DeleteUpdatePic(this);
|
|
109 // 自分の領域を書き直す
|
|
110 Rect old_ppos = rel_pos;
|
|
111 parent->QueryAbsPos(old_ppos);
|
|
112 parent->ReBlit(old_ppos);
|
|
113 }
|
|
114 }
|
|
115 void PicBase::Blit(const Rect& rpos_orig) {
|
|
116 // 実際に描画する領域を得る
|
|
117 Rect rpos = rpos_orig;
|
|
118 // 親widget上に設定されたclip area 内に描画を限定する
|
|
119 if (clip_area.width() != 0) {
|
|
120 Rect clip = clip_area;
|
|
121 clip = child_pos(clip, this);
|
|
122 rpos.intersect(clip);
|
|
123 }
|
|
124 Rect apos = QueryAbsPos(rpos);
|
|
125 if (rpos.empty()) return;
|
|
126 // 必要に応じて保存、描画
|
|
127 if (attribute & CACHE_BACK) root->BlitSurface(root->surface, apos, surface_back, rpos);
|
|
128 if (! (attribute & NO_PICTURE)) {
|
|
129 rpos.rmove(surface_x, surface_y);
|
|
130 if (surface_w >= 0 && surface_h >= 0) {
|
|
131 Rect clip(surface_x, surface_y, surface_x+surface_w, surface_y+surface_h);
|
|
132 rpos.intersect(clip);
|
|
133 }
|
|
134 //if (apos.ty < 200) fprintf(stderr,"Blit: %08x : (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",surface_own,rpos_orig.lx,rpos_orig.ty,rpos_orig.rx,rpos_orig.by,apos.lx,apos.ty,apos.rx,apos.by);
|
|
135 root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, root->surface, apos, attribute);
|
|
136 rpos.rmove(-surface_x, -surface_y);
|
|
137 } else if (parent == 0) { // 親がいないなら背景消去の責任をもつ
|
|
138 DSurfaceFill(root->surface, apos, 0, 0, 0);
|
|
139 }
|
|
140 PicContainer* cur = dynamic_cast<PicContainer*>(this);
|
|
141 if (cur && (!cur->children.empty())) {
|
|
142 cur->BlitChildren(rpos);
|
|
143 }
|
|
144 }
|
|
145 void PicBase::SimpleBlit(Surface* screen) {
|
|
146 // 実際に描画する領域を得る
|
|
147 Rect rpos(0, 0, rel_pos.width(), rel_pos.height());
|
|
148 Rect apos = QueryAbsPos(rpos);
|
|
149 if (rpos.empty()) return;
|
|
150 rpos.rmove(surface_x, surface_y);
|
|
151 if (surface_w >= 0 && surface_h >= 0) {
|
|
152 Rect clip(surface_x, surface_y, surface_x+surface_w, surface_y+surface_h);
|
|
153 rpos.intersect(clip);
|
|
154 }
|
|
155 //if (apos.ty < 200) fprintf(stderr,"S-Blit: %08x : (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",surface_own,rel_pos.lx,rel_pos.ty,rel_pos.rx,rel_pos.by,apos.lx,apos.ty,apos.rx,apos.by);
|
|
156 root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, screen, apos, attribute);
|
|
157 }
|
|
158
|
|
159 Rect PicBase::QueryAbsPos(Rect& rpos) {
|
|
160 rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
|
|
161 if (parent == 0) { // root container
|
|
162 return rpos;
|
|
163 }
|
|
164 // 親の座標に変換後、Query する
|
|
165 Rect ppos = parent_pos(rpos);
|
|
166 Rect apos = parent->QueryAbsPos(ppos);
|
|
167 rpos = child_pos(ppos, this);
|
|
168 return apos;
|
|
169 };
|
|
170 void PicBase::ReBlit(const Rect& rpos_c) {
|
|
171 Rect rpos = rpos_c;
|
|
172 Rect apos = QueryAbsPos(rpos);
|
|
173
|
|
174 root->Update(this, rpos, apos);
|
|
175 }
|
|
176 void PicBase::ExecReBlit(const Rect& rpos_c) {
|
|
177 Rect rpos = rpos_c;
|
|
178 Rect abs_r = QueryAbsPos(rpos);
|
|
179 Rect ppos = parent_pos(rpos);
|
|
180 if(print_blit) fprintf(stderr,"back.");
|
|
181 if (parent) parent->BlitBack(z_pos, ppos);
|
|
182 if(print_blit) fprintf(stderr,"self.");
|
|
183 if (!is_hidden_now) Blit(rpos);
|
|
184 if(print_blit) fprintf(stderr,"front.");
|
|
185 if (parent) parent->BlitFront(z_pos, ppos);
|
|
186 if(print_blit) fprintf(stderr,"end.");
|
|
187 }
|
|
188
|
|
189 void PicBase::ZMove(PicBase* move_to) {
|
|
190 if (parent == 0) {
|
|
191 fprintf(stderr,"Warning: PicBase::ZMove is called by root.\n");
|
|
192 return;
|
|
193 }
|
|
194 if (move_to == ZMOVE_TOP) {
|
|
195 if (this == parent->children.back()) return;
|
|
196 } else if (move_to == ZMOVE_BOTTOM) {
|
|
197 if (this == parent->children.front()) return;
|
|
198 } else if (move_to == this) {
|
|
199 fprintf(stderr,"Error: PicBase::ZMove : move in front of itself!\n");
|
|
200 return;
|
|
201 } else if (move_to && move_to->parent != parent) {
|
|
202 fprintf(stderr,"Error: PicBase::ZMove was called with a no-brother picture\n");
|
|
203 return;
|
|
204 }
|
|
205 // move_to と zpos のうち、後ろの方の picture から書きなおす必要がある
|
|
206 iterator redraw_zpos = z_pos; redraw_zpos++;
|
|
207 if (move_to == ZMOVE_BOTTOM) { // 最背面へ
|
|
208 parent->children.erase(z_pos);
|
|
209 parent->children.push_front(this);
|
|
210 z_pos = parent->children.begin();
|
|
211 redraw_zpos = parent->children.begin();
|
|
212 } else if (move_to == ZMOVE_TOP) { // 最前面へ
|
|
213 redraw_zpos = z_pos; redraw_zpos++;
|
|
214 parent->children.erase(z_pos);
|
|
215 parent->children.push_back(this);
|
|
216 z_pos = parent->children.end(); z_pos--;
|
|
217 } else {
|
|
218 int dis_to = distance(move_to->parent->children.begin(), move_to->z_pos);
|
|
219 int dis_cur = distance(parent->children.begin(), z_pos);
|
|
220 if (dis_cur < dis_to) redraw_zpos = move_to->z_pos;
|
|
221 parent->children.erase(z_pos);
|
|
222 iterator insert_pos = move_to->z_pos; insert_pos++;
|
|
223 parent->children.insert(insert_pos, this);
|
|
224 z_pos = move_to->z_pos; z_pos++;
|
|
225 }
|
|
226 if (! is_hidden_now) {
|
|
227 is_cached = false;
|
|
228 ReBlit();
|
|
229 /* @@@ parent->Blit() と Blit() の違いが分からないので修正 06/12/02
|
|
230 Rect ppos = rel_pos;
|
|
231 parent->QueryAbsPos(ppos);
|
|
232 parent->ReBlit(ppos);
|
|
233 */
|
|
234 }
|
|
235 };
|
|
236 void PicBase::RMove(int add_x, int add_y) {
|
|
237 Rect old_ppos = rel_pos;
|
|
238 rel_pos.rmove(add_x, add_y);
|
|
239 parent->QueryAbsPos(old_ppos);
|
|
240 parent->ReBlit(old_ppos);
|
|
241 ReBlit();
|
|
242
|
|
243 if (widget) {
|
|
244 Rect new_ppos = rel_pos;
|
|
245 Rect new_apos = parent->QueryAbsPos(new_ppos);
|
|
246 widget->SetRegion(new_apos);
|
|
247 }
|
|
248 }
|
|
249 void PicBase::Move(int new_rx, int new_ry) {
|
|
250 RMove(new_rx-rel_pos.lx, new_ry-rel_pos.ty);
|
|
251 }
|
|
252 void PicBase::SetEventWidget(PicWidget* new_widget) {
|
|
253 widget = new_widget;
|
|
254 if (widget) {
|
|
255 Rect new_ppos = rel_pos;
|
|
256 Rect apos = parent->QueryAbsPos(new_ppos);
|
|
257 widget->SetRegion(apos);
|
|
258 }
|
|
259 }
|
|
260 void PicBase::show_all(void) {
|
|
261 PicContainer* cont = dynamic_cast<PicContainer*>(this);
|
|
262 if (cont && (!cont->children.empty())) cont->set_showflag();
|
|
263 show();
|
|
264 }
|
|
265 bool PicBase::IsParent(PicBase* to) {
|
|
266 if (parent == 0) return false;
|
|
267 if (parent == to) return true;
|
|
268 return parent->IsParent(to);
|
|
269 }
|
|
270 void PicBase::show(void) {
|
|
271 /* 自分の親がすべて shown か? */
|
|
272 PicContainer* cur;
|
|
273 for (cur = parent; cur != 0; cur = cur->parent)
|
|
274 if (cur->is_hidden) break;
|
|
275 if (cur) { // 親が隠れているので表示はしない
|
|
276 is_hidden = false;
|
|
277 is_hidden_now = true;
|
|
278 return;
|
|
279 }
|
|
280 if (is_hidden == false) return; // すでに表示されているのでなにもしない
|
|
281 if (widget) {
|
|
282 widget->activate();
|
|
283 }
|
|
284 is_hidden = false;
|
|
285 is_hidden_now = false;
|
|
286 is_cached = false;
|
|
287 cur = dynamic_cast<PicContainer*>(this);
|
|
288 if (cur && (!cur->children.empty())) cur->set_nowhiddenflag(false);
|
|
289 ReBlit();
|
|
290 }
|
|
291 void PicBase::hide(void) {
|
|
292 if (is_hidden) return;
|
|
293 if (widget) {
|
|
294 widget->deactivate();
|
|
295 }
|
|
296 is_hidden = true;
|
|
297 is_hidden_now = true;
|
|
298 is_cached = false;
|
|
299 PicContainer* cur = dynamic_cast<PicContainer*>(this);
|
|
300 if (cur && (!cur->children.empty())) cur->set_nowhiddenflag(true);
|
|
301 ReBlit();
|
|
302 }
|
|
303 void PicBase::SetSurfaceAlpha(const unsigned char* alpha, const Rect& alpha_r) {
|
|
304 if (attribute & ALPHA_FREE) {
|
|
305 if (surface_alpha) delete[] surface_alpha;
|
|
306 surface_alpha = 0;
|
|
307 }
|
|
308 surface_alpha = alpha;
|
|
309 surface_alpha_rect = alpha_r;
|
|
310 if (!is_hidden) ReBlit();
|
|
311 }
|
|
312 void PicBase::SetSurfaceColorKey(int r, int g, int b) {
|
|
313 surface_alpha = 0;
|
|
314 surface_alpha_rect = Rect(0,0);
|
|
315 attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
|
|
316 if (surface_own) {
|
|
317 int key = SDL_MapRGB( ((SDL_Surface*)surface_own)->format, r, g, b);
|
|
318 key |= 0xff000000;
|
|
319 SDL_SetColorKey( (SDL_Surface*)surface_own, SDL_SRCCOLORKEY, key);
|
|
320 }
|
|
321 if (!is_hidden) ReBlit();
|
|
322 }
|
|
323 void PicBase::SetSurfaceAlphaFile(const char* file) {
|
|
324
|
|
325 /* ファイルを元に alpha 画像を作成する */
|
|
326 /* ファイル: パルフェの 'fil' ファイル */
|
|
327 ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, file,"fil");
|
|
328 if (info == 0) return;
|
|
329 char* new_alpha = info->CopyRead();
|
|
330 int alpha_size = info->Size();
|
|
331 delete info;
|
|
332 Rect sr(0,0); int w,h;
|
|
333 if (surface_own == 0 || new_alpha == 0) {
|
|
334 err_ret:
|
|
335 if (new_alpha) delete[] new_alpha;
|
|
336 SetSurfaceAlpha(0,Rect(0,0));
|
|
337 return;
|
|
338 }
|
|
339 sr = Rect(*surface_own);
|
|
340 w = sr.width();
|
|
341 h = sr.height();
|
|
342 if (alpha_size < w*h) goto err_ret;
|
|
343 int i,j;
|
|
344 if ( ((SDL_Surface*)surface_own)->format->Amask == 0) { // mask を surface に繰り込む
|
|
345 Surface* dest = root->NewSurface(w,h, ALPHA_MASK);
|
|
346 for (i=0; i<h; i++) {
|
|
347 char* a = new_alpha + w*i;
|
|
348 char* s = (char*)((SDL_Surface*)surface_own)->pixels + ((SDL_Surface*)surface_own)->pitch*i;
|
|
349 char* d = (char*)((SDL_Surface*)dest)->pixels + ((SDL_Surface*)dest)->pitch*i;
|
|
350 int sbpp = ((SDL_Surface*)surface_own)->format->BytesPerPixel;
|
|
351 int dbpp = ((SDL_Surface*)dest)->format->BytesPerPixel;
|
|
352
|
|
353 for (j=0; j<w; j++) {
|
|
354 int d = read_little_endian_int(s);
|
|
355 d &= 0xffffff;
|
|
356 if (d == 0) ;
|
|
357 else if (*a == 0) d |= 0xff000000;
|
|
358 else d |= (int(*a) << 24);
|
|
359 s += sbpp; d += dbpp; a++;
|
|
360 }
|
|
361 }
|
|
362 delete new_alpha;
|
|
363 root->DeleteSurface(surface_own);
|
|
364 surface_own = dest;
|
|
365 SetSurfaceAlpha(0, Rect(0,0));
|
|
366 } else { // 外部にマスク作成
|
|
367 /* マスクのうち、0xff であるべき部分を画像から判別、変更する */
|
|
368 for (i=0; i<h; i++) {
|
|
369 char* a = new_alpha + w*i;
|
|
370 char* s = (char*)((SDL_Surface*)surface_own)->pixels + ((SDL_Surface*)surface_own)->pitch*i;
|
|
371 int bpp = ((SDL_Surface*)surface_own)->format->BytesPerPixel;
|
|
372 for (j=0; j<w; j++) {
|
|
373 if ( ((*(int*)s) & 0xffffff) == 0) *a = 0;
|
|
374 else if (*a == 0) *a = 0xff;
|
|
375 s += bpp; a++;
|
|
376 }
|
|
377 }
|
|
378 SetSurfaceAlpha( (unsigned char*)new_alpha, Rect(0,0,w,h));
|
|
379 attribute |= ALPHA_FREE;
|
|
380 }
|
|
381 }
|
|
382 void PicBase::SetSurface(const char* filename, int x, int y) {
|
|
383 Surface* s = root->NewSurface(filename);
|
|
384 SetSurface(s, x, y, SURFACE_FREE);
|
|
385 }
|
|
386 void PicBase::SetSurface(Surface* new_surface, int x, int y, int new_attr) {
|
|
387 if (surface_own && (attribute & SURFACE_FREE)) {
|
|
388 root->DeleteSurface(surface_own);
|
|
389 }
|
|
390 attribute &= ~(SURFACE_FREE | BLIT_SATURATE | BLIT_MULTIPLY | NO_PICTURE | SOLID);
|
|
391 attribute |= new_attr;
|
|
392 surface_own = new_surface;
|
|
393 surface_x = x;
|
|
394 surface_y = y;
|
|
395 surface_w = -1;
|
|
396 surface_h = -1;
|
|
397
|
|
398 if (attribute & FIT_SURFACE) {
|
|
399 // surface の大きさに自分の大きさを変更
|
|
400 parent->ReBlit(rel_pos);
|
|
401 if (surface_own == 0) {
|
|
402 rel_pos = Rect(rel_pos.lx, rel_pos.ty);
|
|
403 } else {
|
|
404 Rect r(*surface_own);
|
|
405 int w = r.width(), h = r.height();
|
|
406 w -= x; h -= y;
|
|
407 rel_pos = Rect(rel_pos.lx, rel_pos.ty, rel_pos.lx+w, rel_pos.ty+h);
|
|
408 }
|
|
409 }
|
|
410
|
|
411 rel_solid_area = Rect(0,0,0,0);
|
|
412 if (! surface_own) attribute |= NO_PICTURE;
|
|
413 else if (root->with_mask(surface_own) == 0) {
|
|
414 attribute |= SOLID;
|
|
415 rel_solid_area = rel_pos;
|
|
416 }
|
|
417 if (!is_hidden) ReBlit();
|
|
418 }
|
|
419 void PicBase::SetSurfacePos(int x, int y) {
|
|
420 if (surface_x == x && surface_y == y && surface_w == -1 && surface_h == -1) return;
|
|
421 surface_x = x; surface_y = y;
|
|
422 surface_w = -1; surface_h = -1;
|
|
423 if (!is_hidden_now) ReBlit();
|
|
424 }
|
|
425 int PicBase::SurfacePosX(void) {
|
|
426 return surface_x;
|
|
427 }
|
|
428 int PicBase::SurfacePosY(void) {
|
|
429 return surface_y;
|
|
430 }
|
|
431 void PicBase::SetSurfaceRect(const Rect& r) {
|
|
432 if (surface_x == r.lx && surface_y == r.ty && surface_w == r.width() && surface_h == r.height()) return;
|
|
433 surface_x = r.lx; surface_y = r.ty;
|
|
434 surface_w = r.width(); surface_h = r.height();
|
|
435 parent->ReBlit(rel_pos);
|
|
436 rel_pos = Rect(rel_pos.lx, rel_pos.ty, rel_pos.lx+surface_w, rel_pos.ty+surface_h);
|
|
437 if (widget) {
|
|
438 Rect new_ppos = rel_pos;
|
|
439 Rect apos = parent->QueryAbsPos(new_ppos);
|
|
440 widget->SetRegion(apos);
|
|
441 }
|
|
442 if (!is_hidden_now) ReBlit();
|
|
443 }
|
|
444 void PicBase::SetClipArea(const Rect& r) {
|
|
445 if (clip_area == r) return;
|
|
446 clip_area = r;
|
|
447 parent->ReBlit(rel_pos);
|
|
448 }
|
|
449
|
|
450 void PicBase::SetSurfaceAttribute(int new_attribute) {
|
|
451 attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
|
|
452 attribute |= new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY);
|
|
453 if (new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY)) {
|
|
454 rel_solid_area = Rect(0,0);
|
|
455 }
|
|
456 }
|
|
457 void PicBase::SetSurfaceFreeFlag(bool flag) {
|
|
458 if (flag) attribute |= SURFACE_FREE;
|
|
459 else attribute &= ~SURFACE_FREE;
|
|
460
|
|
461 }
|
|
462
|
|
463 /******************************************
|
|
464 ** PicContainer
|
|
465 */
|
|
466 PicContainer::PicContainer(const Rect& rel_pos, PicContainer* parent, int attr) :
|
|
467 PicBase(rel_pos, parent, attr) {
|
|
468 }
|
|
469 PicContainer::~PicContainer() {
|
|
470 iterator end = children.end();
|
|
471 for (iterator it = children.begin(); it != end; ) {
|
|
472 iterator it_next = it; it_next++;
|
|
473 if ((*it)->widget) delete (*it)->widget; // picture にwidget が付属しているなら、そちらをdelete
|
|
474 else delete (*it);
|
|
475 it = it_next;
|
|
476 }
|
|
477 }
|
|
478 void PicContainer::BlitBack(iterator z, Rect rpos) {
|
|
479 rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
|
|
480 if (rpos.empty()) return;
|
|
481 iterator end = children.end(), begin = children.begin(); iterator it = begin;
|
|
482
|
|
483 Rect ppos = parent_pos(rpos);
|
|
484 if (is_hidden_now) goto parent_redraw;
|
|
485 // cache されている領域を探す
|
|
486 // z自身がキャッシュしていれば、ここで終了
|
|
487 if ( ((*z)->attribute & CACHE_BACK) && ( (*z)->is_cached) && (*z)->rel_pos.is_inner(rpos)) {
|
|
488 Rect cpos = child_pos(rpos, *z);
|
|
489 Rect apos = (*z)->QueryAbsPos(cpos);
|
|
490 root->BlitSurface( (*z)->surface_back, cpos, root->surface, apos);
|
|
491 return;
|
|
492 }
|
|
493 // z より下の子がキャッシュ、あるいは SOLID 描画できないか?
|
|
494 for (it = z; it != begin;) { // 子がcontainerの場合のチェックは省略
|
|
495 it--;
|
|
496 if ( (*it)->is_hidden_now) continue;
|
|
497 if ( (*it)->rel_pos.is_crossed(rpos)) {
|
|
498 if ( ((*it)->attribute & CACHE_BACK) && ((*it)->is_cached) && (*it)->rel_pos.is_inner(rpos)) {
|
|
499 Rect cpos = child_pos(rpos, *it);
|
|
500 Rect apos = (*it)->QueryAbsPos(cpos);
|
|
501 root->BlitSurface( (*it)->surface_back, cpos, root->surface, apos);
|
|
502 goto children_redraw;
|
|
503 }
|
|
504 if ( (*it)->rel_solid_area.is_inner(rpos)) {
|
|
505 goto children_redraw;
|
|
506 }
|
|
507 }
|
|
508 }
|
|
509 // 自分自身がキャッシュ、あるいは SOLID 描画できないか?
|
|
510 if (rel_solid_area.is_inner(ppos)) {
|
|
511 goto self_redraw;
|
|
512 }
|
|
513 if ( (attribute & CACHE_BACK) && is_cached) {
|
|
514 Rect cpos = child_pos(rpos, *z);
|
|
515 Rect apos = (*z)->QueryAbsPos(cpos);
|
|
516 Rect draw_rpos = (*z)->parent_pos(cpos);
|
|
517 if(print_blit) fprintf(stderr,"cahce.");
|
|
518 root->BlitSurface(surface_back, draw_rpos, root->surface, apos);
|
|
519 goto self_redraw;
|
|
520 }
|
|
521 parent_redraw:
|
|
522 if (parent) {
|
|
523 Rect ppos = parent_pos(rpos);
|
|
524 if(print_blit) fprintf(stderr,"parent-back.");
|
|
525 parent->BlitBack(z_pos, ppos);
|
|
526 }
|
|
527 if (is_hidden_now) return;
|
|
528 self_redraw:
|
|
529 if(print_blit) fprintf(stderr,"back-self.");
|
|
530 BlitSelf(rpos); // 子は描画せず、自分だけ描画
|
|
531 children_redraw:
|
|
532 for (; it != z; it++) {
|
|
533 if ( (*it)->is_hidden_now) continue;
|
|
534 if ( (*it)->rel_pos.is_crossed(rpos)) {
|
|
535 Rect cpos = child_pos(rpos, *it);
|
|
536 (*it)->Blit(cpos);
|
|
537 }
|
|
538 }
|
|
539 }
|
|
540 void PicContainer::BlitChildren(Rect rpos) {
|
|
541 if (print_blit) fprintf(stderr,"bc.");
|
|
542 iterator end = children.end();
|
|
543 for (iterator it = children.begin(); it != end; it++) {
|
|
544 if ( (*it)->is_hidden_now) if(print_blit) fprintf(stderr,"bch %08x;",*it);
|
|
545 if ( (*it)->is_hidden_now) continue;
|
|
546 if ( (*it)->rel_pos.is_crossed(rpos)) {
|
|
547 Rect cpos = child_pos(rpos, *it);
|
|
548 (*it)->Blit(cpos);
|
|
549 }
|
|
550 }
|
|
551 }
|
|
552 void PicContainer::BlitFront(iterator z, Rect rpos) {
|
|
553 rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
|
|
554 if (rpos.empty()) return;
|
|
555 iterator end = children.end(); iterator it;
|
|
556 z++;
|
|
557 for (it = z; it != end; it++) {
|
|
558 if ( (*it)->is_hidden_now) continue;
|
|
559 if ( (*it)->rel_pos.is_crossed(rpos)) {
|
|
560 Rect cpos = child_pos(rpos, *it);
|
|
561 (*it)->Blit(cpos);
|
|
562 }
|
|
563 }
|
|
564 if (parent) {
|
|
565 Rect ppos = parent_pos(rpos);
|
|
566 parent->BlitFront(z_pos, ppos);
|
|
567 }
|
|
568 };
|
|
569 void PicContainer::BlitSelf(Rect rpos) {
|
|
570 // 実際に描画する領域を得る
|
|
571 rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
|
|
572 if (rpos.empty()) return;
|
|
573 Rect apos = QueryAbsPos(rpos);
|
|
574 // 必要に応じて保存、描画
|
|
575 if(print_blit) fprintf(stderr,"self-back.");
|
|
576 if (attribute & CACHE_BACK) root->BlitSurface(root->surface, apos, surface_back, rpos);
|
|
577 if (! (attribute & NO_PICTURE)) {
|
|
578 rpos.rmove(surface_x, surface_y);
|
|
579 if (surface_w >= 0 && surface_h >= 0) {
|
|
580 Rect clip(0, 0, surface_w, surface_h);
|
|
581 clip.rmove(rpos.lx, rpos.ty);
|
|
582 rpos.intersect(clip);
|
|
583 }
|
|
584 if(print_blit) fprintf(stderr,"self-blit.");
|
|
585 root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, root->surface, apos, attribute);
|
|
586 } else if (parent == 0) { // 親がいないなら背景消去の責任をもつ
|
|
587 DSurfaceFill(root->surface, apos, 0, 0, 0);
|
|
588 }
|
|
589 }
|
|
590
|
|
591 void PicContainer::set_showflag(void) {
|
|
592 iterator end = children.end();
|
|
593 for (iterator it = children.begin(); it != end; it++) {
|
|
594 (*it)->is_hidden = false;
|
|
595 PicContainer* next = dynamic_cast<PicContainer*>(*it);
|
|
596 if (next && (!next->children.empty())) next->set_showflag();
|
|
597 }
|
|
598 }
|
|
599 void PicContainer::set_nowhiddenflag(bool is_hide) {
|
|
600 iterator end = children.end();
|
|
601 for (iterator it = children.begin(); it != end; it++) {
|
|
602 if (is_hide) (*it)->is_hidden_now = true;
|
|
603 else (*it)->is_hidden_now = (*it)->is_hidden;
|
|
604 if ( (*it)->widget) {
|
|
605 if ((*it)->is_hidden_now) (*it)->widget->deactivate();
|
|
606 else (*it)->widget->activate();
|
|
607 }
|
|
608 PicContainer* next = dynamic_cast<PicContainer*>(*it);
|
|
609 if (next && (!next->children.empty())) next->set_nowhiddenflag(is_hide);
|
|
610 }
|
|
611 }
|
|
612 void PicContainer::RMove(int add_x, int add_y) { // event widget の移動があり得るので子についてもRMoveを呼び出す
|
|
613 PicBase::RMove(add_x, add_y);
|
|
614 iterator end = children.end();
|
|
615 for (iterator it = children.begin(); it != end; it++) {
|
|
616 (*it)->RMove(0,0);
|
|
617 }
|
|
618 }
|
|
619
|
|
620 PicBase* PicContainer::create_leaf(const Rect& rel_pos, int attr) {
|
|
621 return new PicBase(rel_pos, this, attr);
|
|
622 }
|
|
623 PicContainer* PicContainer::create_node(const Rect& rel_pos, int attr) {
|
|
624 return new PicContainer(rel_pos, this, attr);
|
|
625 }
|
|
626
|
|
627 /***************************************************************
|
|
628 **
|
|
629 ** PicWidget
|
|
630 */
|
|
631
|
|
632 PicWidget::PicWidget(void) {
|
|
633 pic = 0;
|
|
634 }
|
|
635 PicWidget::~PicWidget() {
|
|
636 if (pic) {
|
|
637 pic->SetEventWidget(0);
|
|
638 delete pic;
|
|
639 }
|
|
640 pic = 0;
|
|
641 }
|
|
642 void PicWidget::SetPic(PicBase* new_pic) {
|
|
643 if (pic) {
|
|
644 pic->SetEventWidget(0);
|
|
645 delete pic;
|
|
646 }
|
|
647 pic = new_pic;
|
|
648 if (pic) pic->SetEventWidget(this);
|
|
649 }
|
|
650 PicBase* PicWidget::Pic(void) {
|
|
651 if (pic == 0) {
|
|
652 fprintf(stderr,"Error: PicWidget::Pic returns zero.\n");
|
|
653 }
|
|
654 return pic;
|
|
655 }
|
|
656 PicContainer* PicWidget::PicNode(void) {
|
|
657 PicContainer* node = dynamic_cast<PicContainer*>(pic);
|
|
658 if (node == 0) {
|
|
659 fprintf(stderr,"Error: PicWidget::PicNode returns zero.\n");
|
|
660 }
|
|
661 return node;
|
|
662 }
|
|
663
|
|
664 /******************************************
|
|
665 ** FileToSurface
|
|
666 */
|
|
667
|
|
668 #include<list>
|
|
669 #include<map>
|
|
670 #include<string>
|
|
671 using namespace std;
|
|
672 struct SurfaceIndex {
|
|
673 typedef list<SurfaceIndex*>::iterator qiterator;
|
|
674 string filename;
|
|
675 Surface* surface;
|
|
676 qiterator qpos;
|
|
677 int ref_count;
|
|
678 };
|
|
679
|
|
680 class FileToSurface {
|
|
681 typedef list<SurfaceIndex*>::iterator qiterator;
|
|
682
|
|
683 list<SurfaceIndex*> queue;
|
|
684 map<string, SurfaceIndex*> findex;
|
|
685 map<Surface*, SurfaceIndex*> mindex;
|
|
686 int count;
|
|
687 int count_max;
|
|
688 const PicRoot& root;
|
|
689 bool DeleteData(SurfaceIndex* data);
|
|
690 Surface* LoadSurface(string name, char*& mem);
|
|
691 public:
|
|
692 FileToSurface(const PicRoot& root);
|
|
693 ~FileToSurface(void);
|
|
694 Surface* Load(string name);
|
|
695 bool Free(Surface* s);
|
|
696 };
|
|
697
|
|
698 FileToSurface::FileToSurface(const PicRoot& _root) : root(_root) {
|
|
699 count = 0;
|
|
700 count_max = 32; // キャッシュ量(決め打ち)
|
|
701 };
|
|
702 FileToSurface::~FileToSurface() {
|
|
703 qiterator it;
|
|
704 for (it=queue.begin(); it != queue.end(); it++) {
|
|
705 if ( (*it)->ref_count) {
|
|
706 fprintf(stderr, "Warning: FileToSurface: delete referenced surface named '%s'\n",(*it)->filename.c_str());
|
|
707 }
|
|
708 root.DeleteSurfaceImpl( (*it)->surface);
|
|
709 delete *it;
|
|
710 }
|
|
711 }
|
|
712 inline bool FileToSurface::DeleteData(SurfaceIndex* data) {
|
|
713 if ( data->ref_count) return false;
|
|
714 findex.erase(data->filename);
|
|
715 mindex.erase(data->surface);
|
|
716 queue.erase(data->qpos);
|
|
717 root.DeleteSurfaceImpl(data->surface);
|
|
718 delete data;
|
|
719 count--;
|
|
720 return true;
|
|
721 }
|
|
722 inline Surface* FileToSurface::LoadSurface(string name, char*& mem) {
|
|
723 ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, name.c_str(),"pdt");
|
|
724 if (info == 0) return 0;
|
|
725 GRPCONV* conv = GRPCONV::AssignConverter(info);
|
|
726 if (conv == 0) { delete info;return 0;}
|
|
727 mem = (char*)malloc(conv->Width() * conv->Height() * 4 + 1024);
|
|
728 Surface* s = 0;
|
|
729 if (conv->Read(mem)) {
|
|
730 MaskType is_mask = conv->IsMask() ? ALPHA_MASK : NO_MASK;
|
|
731 if (is_mask == ALPHA_MASK) { // alpha がすべて 0xff ならマスク無しとする
|
|
732 int len = conv->Width()*conv->Height();
|
|
733 unsigned int* d = (unsigned int*)mem;
|
|
734 int i; for (i=0; i<len; i++) {
|
|
735 if ( (*d&0xff000000) != 0xff000000) break;
|
|
736 d++;
|
|
737 }
|
|
738 if (i == len) {
|
|
739 is_mask = NO_MASK;
|
|
740 }
|
|
741 }
|
|
742 s = root.NewSurfaceFromRGBAData(conv->Width(), conv->Height(), mem, is_mask);
|
|
743 }
|
|
744 delete conv; delete info; // delete data;
|
|
745 return s;
|
|
746 }
|
|
747 Surface* FileToSurface::Load(string name) {
|
|
748 if (findex.find(name) != findex.end()) {
|
|
749 findex[name]->ref_count++;
|
|
750 return findex[name]->surface;
|
|
751 }
|
|
752 char* mem;
|
|
753 Surface* surface = LoadSurface(name, mem);
|
|
754 if (surface == 0) return 0;
|
|
755
|
|
756 while (count >= count_max) { // count_max 以上のデータを可能なら削除する
|
|
757 qiterator it;
|
|
758 for (it=queue.begin(); it != queue.end(); it++) {
|
|
759 if (DeleteData(*it)) break;
|
|
760 }
|
|
761 if (it == queue.end()) break; // 全データが使用中なら終了
|
|
762 }
|
|
763 SurfaceIndex* new_index = new SurfaceIndex;
|
|
764 new_index->filename = name;
|
|
765 new_index->surface = surface;
|
|
766 findex[name] = new_index;
|
|
767 mindex[surface] = new_index;
|
|
768 queue.push_back(new_index);
|
|
769 new_index->qpos = queue.end(); new_index->qpos--;
|
|
770 new_index->ref_count = 1;
|
|
771 count++;
|
|
772 return surface;
|
|
773 }
|
|
774 bool FileToSurface::Free(Surface* s) {
|
|
775 if (mindex.find(s) == mindex.end()) {
|
|
776 return false;
|
|
777 }
|
|
778 SurfaceIndex* index = mindex[s];
|
|
779 if (index->ref_count == 0) DeleteData(index);
|
|
780 else index->ref_count--;
|
|
781 return true;
|
|
782 }
|
|
783
|
|
784 /******************************************
|
|
785 ** PicRoot
|
|
786 */
|
|
787 #include<SDL.h>
|
|
788
|
|
789 #include"surface.h"
|
|
790
|
|
791 #define DefaultRmask 0xff0000
|
|
792 #define DefaultGmask 0xff00
|
|
793 #define DefaultBmask 0xff
|
|
794 #define DefaultAmask 0xff000000
|
|
795 #define DefaultBpp 32
|
|
796
|
|
797 PicRoot::PicRoot(void) {
|
|
798 hw_surface = (Surface*)SDL_GetVideoSurface();
|
|
799 SDL_PixelFormat* fmt_SDL = hw_surface->format;
|
|
800 if (fmt_SDL->BitsPerPixel == DefaultBpp && fmt_SDL->Rmask == DefaultRmask && fmt_SDL->Gmask == DefaultGmask && fmt_SDL->Bmask == DefaultBmask) {
|
|
801 surface = hw_surface;
|
|
802 } else {
|
|
803 surface = (Surface*)SDL_CreateRGBSurface(0, hw_surface->w, hw_surface->h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, 0);
|
|
804 }
|
|
805
|
|
806 Rect rpos(0, 0, surface->w, surface->h);
|
|
807 root = new PicContainer(rpos, 0, 0);
|
|
808 root->InitRoot(this);
|
|
809 root->show();
|
|
810 ftosurface = new FileToSurface(*this);
|
|
811 width = surface->w;
|
|
812 height = surface->h;
|
|
813 return;
|
|
814 }
|
|
815 PicRoot::~PicRoot() {
|
|
816 // if (surface) DeleteSurfaceImpl(surface); // SDL_GetVideoSurface() した surface は開放の必要がないらしい
|
|
817 surface = 0;
|
|
818 delete root;
|
|
819 delete ftosurface;
|
|
820 }
|
|
821 void PicRoot::Update(PicBase* pic, const Rect& rpos, const Rect& apos) {
|
|
822 update_rects.push_back(UpdateItem(pic, rpos, apos));
|
|
823 }
|
|
824 bool PicRoot::UpdateItem::less(const PicRoot::UpdateItem& a, const PicRoot::UpdateItem& b) {
|
|
825 return a.pic->DistanceRoot() < b.pic->DistanceRoot();
|
|
826 }
|
|
827 void PicRoot::DeleteUpdatePic(PicBase* pic) {
|
|
828 vector<UpdateItem>::iterator it = update_rects.begin();
|
|
829 while(it != update_rects.end()) {
|
|
830 if (it->pic == pic) {
|
|
831 update_rects.erase(it);
|
|
832 it = update_rects.begin();
|
|
833 continue;
|
|
834 }
|
|
835 it++;
|
|
836 }
|
|
837 return;
|
|
838 }
|
|
839 void PicRoot::ExecUpdate(void) {
|
|
840 /* 共通する領域を消去する */
|
|
841 sort(update_rects.begin(), update_rects.end(), UpdateItem::less);
|
|
842 vector<UpdateItem>::iterator it;
|
|
843 vector<UpdateItem>::iterator end = update_rects.end();
|
|
844 if(print_blit){
|
|
845 fprintf(stderr,"ExecUpdate Start: \n\t");
|
|
846 for (it=update_rects.begin(); it != end; it++) {
|
|
847 fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
|
|
848 }
|
|
849 fprintf(stderr,"\n");
|
|
850 }
|
|
851 for (it=update_rects.begin(); it != end; it++) {
|
|
852 if (it->rpos.width() == 0) continue;
|
|
853
|
|
854 Rect apos = it->apos;
|
|
855 PicBase* pic = it->pic;
|
|
856
|
|
857 vector<UpdateItem>::iterator jt = it; jt++;
|
|
858 for (; jt != end; jt++) {
|
|
859 if (apos.is_inner(jt->apos)) {
|
|
860 if (jt->pic == pic || jt->pic->IsParent(pic)) { // 親が共通、かつ領域も共通
|
|
861 jt->rpos = Rect(0,0); // empty rect をセット
|
|
862 jt->apos = Rect(0,0);
|
|
863 }
|
|
864 } else if (jt->apos.is_inner(apos)) { // 相手に自分が包含される
|
|
865 if (jt->pic == pic || jt->pic->IsParent(pic)) { // 親が共通、かつ領域も共通
|
|
866 it->rpos = Rect(0,0);
|
|
867 it->apos = Rect(0,0);
|
|
868 break;
|
|
869 }
|
|
870 }
|
|
871 }
|
|
872 }
|
|
873 if(print_blit){
|
|
874 fprintf(stderr,"->\t");
|
|
875 for (it=update_rects.begin(); it != end; it++) {
|
|
876 fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
|
|
877 }
|
|
878 fprintf(stderr,"\n");
|
|
879 }
|
|
880
|
|
881 int num = update_rects.size();
|
|
882 SDL_Rect* r = new SDL_Rect[num];
|
|
883 Rect confine = Rect(0, 0, surface->w, surface->h);
|
|
884 int n = 0;
|
|
885 int i;
|
|
886 for (i=0; i<num; i++) {
|
|
887 UpdateItem& item = update_rects[i];
|
|
888 Rect& ur = item.apos;
|
|
889 if (ur.width() == 0) continue;
|
|
890 if(print_blit)fprintf(stderr,"%08x: %d,%d,%d,%d",item.pic, item.apos.lx, item.apos.ty, item.apos.rx, item.apos.by);
|
|
891
|
|
892 item.pic->ExecReBlit(item.rpos);
|
|
893 if(print_blit)fprintf(stderr,"\n");
|
|
894 ur.intersect(confine);
|
|
895 r[n].x = ur.lx;
|
|
896 r[n].y = ur.ty;
|
|
897 r[n].w = ur.rx - ur.lx;
|
|
898 r[n].h = ur.by - ur.ty;
|
|
899 if (surface != hw_surface) SDL_BlitSurface(surface, &r[n], hw_surface, &r[n]);
|
|
900 n++;
|
|
901 }
|
|
902 if(print_blit)fprintf(stderr,"\n");
|
|
903 SDL_UpdateRects(hw_surface, n, r);
|
|
904 delete[] r; update_rects.clear();
|
|
905 }
|
|
906
|
|
907 Surface* PicRoot::NewSurface(int w, int h, MaskType with_mask) const {
|
|
908 Surface* s;
|
|
909 if (with_mask == ALPHA_MASK) {
|
|
910 s = (Surface*)SDL_CreateRGBSurface(SDL_SRCALPHA, w, h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, DefaultAmask);
|
|
911 } else {
|
|
912 s = (Surface*)SDL_CreateRGBSurface(0, w, h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, 0);
|
|
913 }
|
|
914 return s;
|
|
915 }
|
|
916
|
|
917 Surface* PicRoot::NewSurfaceFromRGBAData(int w, int h, char* data, MaskType with_mask) const {
|
|
918 int amask = (with_mask == ALPHA_MASK) ? DefaultAmask : 0;
|
|
919 Surface* s = (Surface*)SDL_CreateRGBSurfaceFrom(data, w, h, DefaultBpp, w*4, DefaultRmask, DefaultGmask, DefaultBmask, amask);
|
|
920 s->flags &= ~SDL_PREALLOC;
|
|
921 return s;
|
|
922 };
|
|
923 Surface* PicRoot::NewSurface(const char* f, MaskType with_mask) {
|
|
924 if (f == 0) return 0;
|
|
925 Surface* s = ftosurface->Load(f);
|
|
926 if (s == 0) return 0;
|
|
927 if (with_mask == COLOR_MASK) {
|
|
928 SDL_SetColorKey( (SDL_Surface*)s, SDL_SRCCOLORKEY, *(Uint32*)s->pixels);
|
|
929 }
|
|
930 /* xkanon の残骸 */
|
|
931 if (strcmp(f, "grdat") == 0)
|
|
932 SDL_SetColorKey(s, SDL_SRCCOLORKEY, 0x55aa66);
|
|
933 return s;
|
|
934 }
|
|
935 Surface* PicRoot::RotZoomSurface(Surface* from, double zoom, double rotate) {
|
|
936 Surface* ret = (Surface*)rotozoomSurface( (SDL_Surface*)from, rotate, zoom, SMOOTHING_OFF);
|
|
937 return ret;
|
|
938 }
|
|
939 void PicRoot::DeleteSurfaceImpl(Surface* s) const {
|
|
940 SDL_FreeSurface(s);
|
|
941 }
|
|
942 void PicRoot::DeleteSurface(Surface* s) {
|
|
943 if (!ftosurface->Free(s))
|
|
944 DeleteSurfaceImpl(s);
|
|
945 }
|
|
946 inline SDL_Rect SDLed(const Rect& rect) {
|
|
947 SDL_Rect r;
|
|
948 r.x = rect.lx;
|
|
949 r.y = rect.ty;
|
|
950 r.w = rect.rx-rect.lx;
|
|
951 r.h = rect.by-rect.ty;
|
|
952 return r;
|
|
953 }
|
|
954
|
|
955 #ifndef ALPHA_MAX
|
|
956 #define ALPHA_MAX 255
|
|
957 #endif
|
|
958 void PicRoot::BlitSurface(Surface* src, const Rect& src_r, const unsigned char* alpha, const Rect& alpha_r, Surface* dest, const Rect& dest_r, int attribute) const {
|
|
959 if (print_blit) fprintf(stderr," s %08x %d:%d:%d:%d;",src, dest_r.lx, dest_r.ty, dest_r.rx, dest_r.by);
|
|
960 SDL_Rect sr = SDLed(src_r); SDL_Rect dr = SDLed(dest_r);
|
|
961 special_blit:
|
|
962 if (attribute & PicBase::BLIT_MULTIPLY) {
|
|
963 if (print_blit) fprintf(stderr,"M");
|
|
964 DSurfaceBlitMultiply(src, src_r, dest, dest_r);
|
|
965 return;
|
|
966 } else if (attribute & PicBase::BLIT_SATURATE) {
|
|
967 if (src->format->Amask != 0) goto normal_blit;
|
|
968 if (print_blit) fprintf(stderr,"S");
|
|
969 unsigned char a = 255;
|
|
970 if (alpha && alpha_r.width() >= 1 && alpha_r.height() >= 1) a = *alpha;
|
|
971 DSurfaceBlitSaturate(src, src_r, dest, dest_r, a);
|
|
972 return;
|
|
973 }
|
|
974 normal_blit:
|
|
975 if (print_blit) fprintf(stderr,"N");
|
|
976 if (alpha == 0 || alpha_r.width() == 0) { // simple blit
|
|
977 if (print_blit) fprintf(stderr,"X");
|
|
978 SDL_BlitSurface(src, &sr, dest, &dr);
|
|
979 return;
|
|
980 }
|
|
981 if (alpha_r.width() == 1 && alpha_r.height() == 1) {
|
|
982 if (*alpha == 255) {
|
|
983 if (print_blit) fprintf(stderr,"Y");
|
|
984 SDL_BlitSurface(src, &sr, dest, &dr);
|
|
985 return;
|
|
986 }
|
|
987 if (src->format->Amask == 0) { // use per-surface alpha
|
|
988 if (print_blit) fprintf(stderr,"Z");
|
|
989 SDL_SetAlpha(src, SDL_SRCALPHA, *alpha);
|
|
990 SDL_BlitSurface(src, &sr, dest, &dr);
|
|
991 SDL_SetAlpha(src, 0, 0);
|
|
992 return;
|
|
993 }
|
|
994 }
|
|
995 // generic alpha blit
|
|
996 if (print_blit) fprintf(stderr,"W");
|
|
997 DSurfaceBlitAlpha(src, src_r, dest, dest_r, alpha, alpha_r);
|
|
998 return;
|
|
999 }
|
|
1000
|
|
1001 bool PicRoot::with_mask(Surface* s) {
|
|
1002 return s->format->Amask != 0;
|
|
1003 }
|
|
1004
|
|
1005 #if USE_X11
|
|
1006 #include<SDL_syswm.h>
|
|
1007 #include<X11/Xlib.h>
|
|
1008 #include<X11/Xutil.h>
|
|
1009 #endif /* USE_X11 */
|
|
1010 void PicRoot::SetWindowCaption(const char* caption) {
|
|
1011 #if USE_X11
|
|
1012 // SDL_WM_SetCaption(caption, 0);
|
|
1013 // SDLの関数では2バイト文字をサポートしてくれないので、同等の内容に修正
|
|
1014 SDL_SysWMinfo info;
|
|
1015 memset(&info,0,sizeof(info));
|
|
1016 SDL_VERSION(&(info.version));
|
|
1017 if (SDL_GetWMInfo(&info) == 1) {
|
|
1018 Display* display = info.info.x11.display;
|
|
1019 Window wm = info.info.x11.wmwindow;
|
|
1020 if (wm == 0) wm = info.info.x11.window;
|
|
1021 if (wm != 0) {
|
|
1022 XTextProperty titleprop;
|
|
1023 XmbTextListToTextProperty(display, (char**)&caption, 1, XCompoundTextStyle, &titleprop);
|
|
1024 XSetWMName(display, wm, &titleprop);
|
|
1025 XSetWMIconName(display, wm, &titleprop);
|
|
1026 XFree(titleprop.value);
|
|
1027 }
|
|
1028 XSync(display, False);
|
|
1029 }
|
|
1030 #endif /* USE_X11 */
|
|
1031 }
|
|
1032
|
|
1033 /************************************************************
|
|
1034 ** PicAnm
|
|
1035 */
|
|
1036
|
|
1037 void PicBase::ClearAnm(void) {
|
|
1038 while(!anm.empty()) {
|
|
1039 delete anm.back();
|
|
1040 }
|
|
1041 }
|
|
1042 PicAnm::PicAnm(PicBase* _pic) {
|
|
1043 pic.push_back(_pic);
|
|
1044 pic[0]->anm.push_back(this);
|
|
1045 return;
|
|
1046
|
|
1047 }
|
|
1048 PicAnm::PicAnm(vector<PicBase*> _pic) : pic(_pic) {
|
|
1049 if (pic.empty()) return;
|
|
1050 pic[0]->anm.push_back(this);
|
|
1051 return;
|
|
1052 }
|
|
1053 PicAnm::~PicAnm() {
|
|
1054 vector<PicAnm*>::iterator it = find(pic[0]->anm.begin(), pic[0]->anm.end(), this);
|
|
1055 if (it == pic[0]->anm.end()) {
|
|
1056 fprintf(stderr,"Cannot found this in PicAnm::~PicAnm()");
|
|
1057 } else {
|
|
1058 pic[0]->anm.erase(it);
|
|
1059 }
|
|
1060 }
|