root/window/picture.cc

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