1 /*
2   Copyright (C) 2009 Facundo Domínguez
3 
4   This file is part of Spacejunk.
5 
6   Spacejunk is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   Foobar is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "graphic.h"
21 #include "global.h"
22 #include <stdlib.h>
23 #include "resourcemanager.h"
24 #include <sge.h>
25 #include <iostream>
26 #include "clipping.h"
27 #include "gem-uta.h"
28 
29 using namespace std;
30 
toScreenx(int x)31 int Graphic::toScreenx(int x){ return int(round(Graphic::screenx+Graphic::getBaseScaleFactorX()*x)); }
toScreeny(int y)32 int Graphic::toScreeny(int y){ return int(round(Graphic::screeny+Graphic::getBaseScaleFactorY()*y)); }
toScreenw(int w)33 int Graphic::toScreenw(int w){ return int(round(Graphic::getBaseScaleFactorX()*w)); }
toScreenh(int h)34 int Graphic::toScreenh(int h){ return int(round(Graphic::getBaseScaleFactorY()*h)); }
35 
fromScreenx(int x)36 int Graphic::fromScreenx(int x){ return int(round((x-screenx)/getBaseScaleFactorX())); }
fromScreeny(int y)37 int Graphic::fromScreeny(int y){ return int(round((y-screeny)/getBaseScaleFactorY())); }
38 
39 class UpdateSystemUta {
40 private:
41     GemUta * uta;
42     GemUta * newrects;
43 
44 public:
45     int UPDW;
46     int UPDH;
47 
UpdateSystemUta()48     UpdateSystemUta() {
49         UPDW=640;
50         UPDH=480;
51         uta = NULL;
52         newrects = NULL;
53     }
54 
init(int x,int y,int w,int h)55     void init(int x,int y,int w,int h) {
56         UPDW=w;
57         UPDH=h;
58         uta = gem_uta_new_coords (x, y, UPDW, UPDH);
59         newrects = gem_uta_new_coords (x, y, UPDW, UPDH);
60     }
61 
~UpdateSystemUta()62     ~UpdateSystemUta() {
63         if (uta!=NULL)
64             gem_uta_free (uta);
65         if (newrects!=NULL)
66             gem_uta_free (newrects);
67     }
68 
clear()69     void clear() {
70         gem_uta_clear (uta);
71         gem_uta_clear (newrects);
72     }
73 
commit()74     void commit() {
75         int num_rects;
76         gem_uta_union(uta,newrects);
77         SDL_Rect *rects = gem_uta_get_rects (uta, &num_rects, 0, 0, UPDW, UPDH);
78         SDL_UpdateRects (Graphic::getScreen(), num_rects, rects);
79         free (rects);
80         gem_uta_copy(uta,newrects);
81         gem_uta_clear(newrects);
82     }
83 
update(const SDL_Rect & r)84     void update(const SDL_Rect & r) {
85         GemRect grect={r.x,r.x + r.w - 1,r.y,r.y + r.h-1};
86         gem_uta_add_rect (newrects, &grect);
87     }
88 };
89 
90 UpdateSystemUta upd;
91 
updateRect(SDL_Surface * s,SDL_Rect * r)92 void Graphic::updateRect(SDL_Surface * s,SDL_Rect * r) {
93     if (!r->w || !r->h) return;
94 
95     SDL_Rect rs = {toScreenx(r->x),toScreeny(r->y),toScreenw(r->w),toScreenh(r->h)};
96     if (clipRectangle(&rs,screenx,screeny,screenw,screenh))
97         upd.update(rs);
98 }
99 
100 
mUpdateRect(SDL_Surface * s,SDL_Rect * r)101 void Graphic::mUpdateRect(SDL_Surface * s,SDL_Rect * r) {
102     if (!r->w || !r->h) return;
103 
104     if (clipRectangle(r,screenx,screeny,screenw,screenh)) {
105         upd.update(*r);
106     }
107 }
108 
fullUpdate()109 void Graphic::fullUpdate() {
110     fullupdate=true;
111 };
112 
113 bool Graphic::alwaysupdate=false;
114 
setAlwaysUpdate(bool always)115 void Graphic::setAlwaysUpdate(bool always) {
116     alwaysupdate=(getScreen()->flags & SDL_DOUBLEBUF)!=SDL_DOUBLEBUF && always;
117 };
118 
119 
120 Uint32 Graphic::sdlflags= /*SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF*/ 0;
121 
122 Vector2d Graphic::screencenter;
123 int Graphic::screenx;
124 int Graphic::screeny;
125 int Graphic::screenw;
126 int Graphic::screenh;
127 
min(float x,float y)128 float inline min(float x,float y) {
129     return x<y?x:y;
130 }
131 
132 float Graphic::base_scalefactor=1.0f;
133 bool Graphic::updates=false;
134 bool Graphic::fullupdate=false;
135 
toggle_updates(bool on)136 void Graphic::toggle_updates(bool on) {
137     updates=alwaysupdate || ((getScreen()->flags & SDL_DOUBLEBUF)!=SDL_DOUBLEBUF && on);
138 }
139 
140 SDL_Surface * Graphic::screen=NULL;
141 
142 
getBaseScaleFactorX()143 float Graphic::getBaseScaleFactorX(){ return base_scalefactor; };
getBaseScaleFactorY()144 float Graphic::getBaseScaleFactorY(){ return base_scalefactor; };
145 
setScaleFactors()146 void Graphic::setScaleFactors() {
147     if (getScreen()->w!=LOGICAL_WIDTH || getScreen()->h!=LOGICAL_HEIGHT)
148         base_scalefactor=min(getScreen()->w/float(LOGICAL_WIDTH),getScreen()->h/float(LOGICAL_HEIGHT));
149     else
150         base_scalefactor=1.0f;
151 
152     if (getScreen()->w>int(base_scalefactor*LOGICAL_WIDTH))
153         screenw = int(base_scalefactor*LOGICAL_WIDTH);
154     else
155         screenw = getScreen()->w;
156     if (getScreen()->h>int(base_scalefactor*LOGICAL_HEIGHT))
157         screenh = int(base_scalefactor*LOGICAL_HEIGHT);
158     else
159         screenh = getScreen()->h;
160 
161     screenx = (getScreen()->w-screenw)/2;
162     screeny = (getScreen()->h-screenh)/2;
163 }
164 
set_video_mode(int w,int h)165 void Graphic::set_video_mode(int w,int h) {
166 
167     screen = SDL_SetVideoMode(w, h, 8, sdlflags|SDL_HWPALETTE|SDL_ANYFORMAT);
168     if (screen == NULL) {
169         CHERROR<<"Graphic: Unable to set video mode "<<w<<"x"<<h<<": "<<SDL_GetError()<<ENDL;
170         exit(1);
171     }
172     if (screen->flags & SDL_HWPALETTE)
173         CHERROR<<"Graphic: hwpalette set\n";
174     else
175         CHERROR<<"Graphic: hwpalette not set\n";
176 
177     if (screen->format->palette)
178         CHERROR<<"Graphic: there's palette"<<ENDL;
179     else
180         CHERROR<<"Graphic: there is not palette"<<ENDL;
181 
182     screencenter.x=LOGICAL_WIDTH/2;
183     screencenter.y=LOGICAL_HEIGHT/2;
184 
185     // determine how should we scale graphics relative to
186     // the current resolution.
187     setScaleFactors();
188 
189     upd.init(0,0,screen->w,screen->h);
190 
191     sge_Update_OFF();
192 
193     CHERROR<<"Graphic: Screen is at "<<screen->w<<"x"<<screen->h<<"@"<<int(screen->format->BitsPerPixel)<<ENDL;
194 }
195 
196 RMPALETTERef pal;
197 
setPalette(const std::string & id,int flags)198 void Graphic::setPalette(const std::string & id,int flags) {
199     /* Attemp to set palette */
200     if (getScreen()->format->palette) {
201         pal=RMPALETTERef(id);
202 
203         if (!SDL_SetPalette(getScreen(), flags, pal->colors, 0,pal->ncolors)) {
204             CHERROR<<"Unable to set "<<id<<" palette: "<<SDL_GetError()<<ENDL;
205             exit(1);
206         };
207     }
208 }
209 
setPalette(const SDL_Palette * pal)210 void Graphic::setPalette(const SDL_Palette * pal) {
211     if (getScreen()->format->palette && pal) {
212         if (!SDL_SetColors(getScreen(), pal->colors, 0,pal->ncolors)) {
213             CHERROR<<"Unable to set main palette: "<<SDL_GetError()<<ENDL;
214             exit(1);
215         };
216     }
217 }
218 
getPalette()219 SDL_Palette * Graphic::getPalette() {
220     return &*bmp ? bmp->format->palette : NULL;
221 }
222 
223 
flip(bool full)224 void Graphic::flip(bool full) {
225     if ((getScreen()->flags & SDL_DOUBLEBUF) ==SDL_DOUBLEBUF || full || fullupdate || !updates) {
226         SDL_Flip(getScreen());
227         fullupdate=false;
228     } else {
229         upd.commit();
230     }
231 }
232 
setFullscreenFlag(bool full)233 void Graphic::setFullscreenFlag(bool full) {
234     if (full)
235         sdlflags |= SDL_FULLSCREEN;
236     else
237         sdlflags &= ~SDL_FULLSCREEN;
238 }
239 
toggleFullscreen()240 void Graphic::toggleFullscreen() {
241     sdlflags ^= SDL_FULLSCREEN;
242     set_video_mode(getScreen()->w,getScreen()->h);
243 }
244 
clearScreen(Uint32 color)245 void Graphic::clearScreen(Uint32 color) {
246     SDL_Rect r={0,0,getScreen()->w,getScreen()->h};
247     SDL_FillRect(getScreen(),&r,color);
248 }
249 
Graphic()250 Graphic::Graphic() : cache(NULL),images(Ref<RMIMGRef,delarray>(),0),bmp() {
251     ROT_FLAG=0;
252 };
253 
getWidth() const254 int Graphic::getWidth() const {
255     return int(bmp->w/getBaseScaleFactorX());
256 }
257 
getHeight() const258 int Graphic::getHeight() const {
259     return int(bmp->h/getBaseScaleFactorY());
260 }
261 
262 
263 
264 //#define ROT_FLAG 0
265 
Graphic(const std::string & id,bool usecache,bool isopaque,bool prerotate)266 Graphic::Graphic(const std::string & id,bool usecache,bool isopaque,bool prerotate) : cache(NULL),images(Ref<RMIMGRef,delarray>(),0) {
267     if (!id.length()) {
268         return;
269     }
270 
271     images=getImageSet(id);
272     if (!images.second) {
273         fprintf(stderr,"Unable to load graphic %s: %s\n",id.c_str(),SDL_GetError());
274         exit(1);
275     }
276     if (isopaque) { // Clear color key
277         for (int i=0;i<images.second;i++) SDL_SetColorKey(&*((&*images.first)[i]),0,0);
278     }
279     bmp=(&*images.first)[0];
280 
281     // Ask cache with the biggest possible size.
282     if (usecache && !prerotate) {
283         cache_angle=0.0;
284         cache_zoom=1.0;
285         cache=Ref<SDL_Surface,SDL_FreeSurface>(SDL_DisplayFormat(&*bmp));
286         cache_rect.x=cache_rect.y=0;
287         cache_rect.w=cache->w;
288         cache_rect.h=cache->h;
289         hotspot.x=getWidth()/2;
290         hotspot.y=getHeight()/2;
291         if (!(&*cache)) {
292             CHERROR<<"Graphic error: Could not get a cache surface."<<ENDL;
293             exit(1);
294         }
295     } else {
296         cache_zoom=0;
297         cache_rect.x=cache_rect.y=0;
298         cache_rect.w=bmp->w;
299         cache_rect.h=bmp->h;
300         hotspot=Vector2d();
301     }
302     if (getScreen()->format->palette || bmp->w*bmp->h>64*64) ROT_FLAG=0;
303     else ROT_FLAG=SGE_TAA;
304 
305     if (prerotate) {
306         hotspot.x=getWidth()/2;
307         hotspot.y=getHeight()/2;
308         rot=RMROTRef(id);
309     }
310 }
311 
~Graphic()312 Graphic::~Graphic() {};
313 
draw(Vector2d pos,real zoom,real angle)314 void Graphic::draw(Vector2d pos,real zoom,real angle) {
315     draw(int(pos.x),int(pos.y),zoom,angle);
316 }
317 
draw(int x,int y,SDL_Rect * r)318 void Graphic::draw(int x,int y,SDL_Rect * r) {
319     SDL_Rect trec={toScreenx(x),toScreeny(y),0,0};
320     SDL_Surface * s= cache_zoom ? &*cache : &*bmp;
321     SDL_Surface * screen=getScreen();
322     if (r) {
323         trec.w=toScreenw(r->w);
324         trec.h=toScreenh(r->h);
325     } else {
326         trec.w=cache_rect.w;
327         trec.h=cache_rect.h;
328     }
329     SDL_BlitSurface(s,r,screen,&trec);
330     if (updates)
331         mUpdateRect(screen,&trec);
332 };
333 
draw(int x,int y,real zoom,real angle)334 void Graphic::draw(int x,int y,real zoom,real angle) {
335     if (!&*bmp) return;
336 
337     SDL_Surface * screen=getScreen();
338     if (!cache_zoom) {
339         if (&*rot) {
340             x -= int(zoom*hotspot.x);
341             y -= int(zoom*hotspot.y);
342             rot->draw(x,y,angle,zoom);
343         } else {
344             x -= int(hotspot.x);
345             y -= int(hotspot.y);
346             SDL_Rect srcrec={0,0,bmp->w,bmp->h};
347             SDL_Rect trec={toScreenx(x),toScreeny(y),bmp->w,bmp->h};
348             SDL_BlitSurface(&*bmp,&srcrec,screen,&trec);
349             if (updates)
350                 mUpdateRect(screen,&trec);
351         }
352         return;
353     }
354 
355     x -= int(zoom*hotspot.x);
356     y -= int(zoom*hotspot.y);
357     if (0<=x+zoom*getWidth() && x<LOGICAL_WIDTH && 0<=y+zoom*getHeight() && y<LOGICAL_HEIGHT) {
358         if (fabsf(cache_angle-angle)>EPS || fabsf(cache_zoom-zoom)>EPS) {
359             // Recompute cache if necesary.
360             cache_angle=angle;
361             cache_zoom=zoom;
362             SDL_FillRect(&*cache,&cache_rect,SDL_MapRGB(bmp->format,0,0, 0));
363             real hx = hotspot.x*Graphic::getBaseScaleFactorX();
364             real hy = hotspot.y*Graphic::getBaseScaleFactorY();
365             sge_transform(&*bmp,&*cache,cache_angle,zoom,zoom,
366                           Uint16(hx),Uint16(hy),int(zoom*hx), int(zoom*hy),ROT_FLAG);
367             cache_rect.w = int(zoom*bmp->w);
368             cache_rect.h = int(zoom*bmp->h);
369             cache_rect.x = 0;
370             cache_rect.y = 0;
371         }
372 
373         // Blit cache.
374         SDL_Rect trec={toScreenx(x),toScreeny(y),0,0};
375         SDL_BlitSurface(&*cache,&cache_rect,screen,&trec);
376         if (updates)
377             mUpdateRect(screen,&trec);
378     }
379 }
380 
381 const real SQRT2 = sqrt(2);
382 
drawCircle(Vector2d center,int radius,Uint32 color)383 void Graphic::drawCircle(Vector2d center,int radius,Uint32 color) {
384     SDL_Surface* s=getScreen();
385     float rx=radius*getBaseScaleFactorX();
386     float ry=radius*getBaseScaleFactorY();
387     int cx = toScreenx(int(center.x));
388     int cy = toScreeny(int(center.y));
389     sge_Ellipse(s,cx,cy,int(rx),int(ry),color);
390     if (updates) {
391         real dx=rx/SQRT2;
392         real dy=ry/SQRT2;
393         SDL_Rect trec={Sint16(cx-rx),Sint16(cy-ry),int(2*rx),int(2*ry)};
394         SDL_Rect trec1={trec.x,Sint16(cy-dy-1),Sint16(rx-dx+3),Sint16(2*dy+3)};
395         SDL_Rect trec2=trec1;
396         mUpdateRect(s,&trec1);
397         trec2.x=Sint16(cx+dx);
398         mUpdateRect(s,&trec2);
399         SDL_Rect trec3={Sint16(cx-dx),trec.y,Sint16(2*dx+3),Sint16(ry-dy+4)};
400         SDL_Rect trec4=trec3;
401         mUpdateRect(s,&trec3);
402         trec4.y=Sint16(cy+dy-1);
403         mUpdateRect(s,&trec4);
404     }
405 }
406 
drawSurroundingCircle(Vector2d center,real zoom,Uint32 color)407 void Graphic::drawSurroundingCircle(Vector2d center,real zoom,Uint32 color) {
408     drawCircle(center,int(zoom*getWidth()/2+2),color);
409 }
410 
411 
drawSurroundingCross(Vector2d center,real zoom,Uint32 color)412 void Graphic::drawSurroundingCross(Vector2d center,real zoom,Uint32 color) {
413     float lx=(getWidth()*zoom/2+12)*Graphic::getBaseScaleFactorX();
414     float ly=(getWidth()*zoom/2+12)*Graphic::getBaseScaleFactorY();
415     float slx = 6*Graphic::getBaseScaleFactorX();
416     float sly = 6*Graphic::getBaseScaleFactorY();
417     SDL_Surface *s=getScreen();
418     center.x = toScreenx(int(center.x));
419     center.y = toScreeny(int(center.y));
420     sge_Line(s,Sint16(center.x-lx),Sint16(center.y),Sint16(center.x-(lx-slx)),Sint16(center.y),color);
421     sge_Line(s,Sint16(center.x+lx),Sint16(center.y),Sint16(center.x+(lx-slx)),Sint16(center.y),color);
422     sge_Line(s,Sint16(center.x),Sint16(center.y-ly),Sint16(center.x),Sint16(center.y-(ly-sly)),color);
423     sge_Line(s,Sint16(center.x),Sint16(center.y+ly),Sint16(center.x),Sint16(center.y+(ly-sly)),color);
424     if (updates) {
425         SDL_Rect trec={Sint16(center.x-lx),Sint16(center.y),Sint16(2*lx+2),1};
426         mUpdateRect(s,&trec);
427         trec.x=Sint16(center.x);
428         trec.y=Sint16(center.y-ly);
429         trec.w=1;
430         trec.h=Sint16(2*ly+2);
431         mUpdateRect(s,&trec);
432     }
433 }
434 
435 
drawArrow(int x1,int y1,int x2,int y2,Uint32 color)436 void Graphic::drawArrow(int x1,int y1,int x2,int y2,Uint32 color) {
437     SDL_Surface *s=getScreen();
438     x1 = toScreenx(x1);
439     y1 = toScreeny(y1);
440     x2 = toScreenx(x2);
441     y2 = toScreeny(y2);
442     sge_Line(s,x1,y1,x2,y2,color);
443     if (updates) {
444         SDL_Rect trec;
445         bbFromLine(&trec,x1,y1,x2,y2);
446         mUpdateRect(s,&trec);
447     }
448 }
449 
drawArrow(int x1,int y1,int x2,int y2)450 void Graphic::drawArrow(int x1,int y1,int x2,int y2) {
451     SDL_Surface *s=getScreen();
452     x1 = toScreenx(x1);
453     y1 = toScreeny(y1);
454     x2 = toScreenx(x2);
455     y2 = toScreeny(y2);
456     sge_Line(s,x1,y1,x2,y2,SDL_MapRGB(s->format, 128,0,0));
457     if (updates) {
458         SDL_Rect trec;
459         bbFromLine(&trec,x1,y1,x2,y2);
460         mUpdateRect(s,&trec);
461     }
462 }
463 
drawRect(Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)464 void Graphic::drawRect(Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color) {
465     SDL_Surface * s=getScreen();
466     x1 = toScreenx(x1);
467     y1 = toScreeny(y1);
468     x2 = toScreenx(x2);
469     y2 = toScreeny(y2);
470     sge_Rect(s,x1,y1,x2,y2,color);
471     if (updates) {
472         SDL_Rect trec;
473         bbFromLine(&trec,x1,y1,x2,y2);
474         if (trec.w<=2 || trec.h<=2)
475             mUpdateRect(s,&trec);
476         else {
477             SDL_Rect r={trec.x,trec.y,1,trec.h};
478             mUpdateRect(s,&r);
479             r.x+=trec.w-1;
480             mUpdateRect(s,&r);
481             r.x=trec.x+1;
482             r.w=trec.w-2;
483             r.h=1;
484             mUpdateRect(s,&r);
485             r.y+=trec.h-1;
486             mUpdateRect(s,&r);
487         }
488     }
489 };
490 
drawFilledRect(Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color)491 void Graphic::drawFilledRect(Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Uint32 color) {
492     SDL_Surface * s=getScreen();
493     SDL_Rect trec;
494     x1 = toScreenx(x1);
495     y1 = toScreeny(y1);
496     x2 = toScreenx(x2);
497     y2 = toScreeny(y2);
498     bbFromLine(&trec,x1,y1,x2,y2);
499     SDL_FillRect(s,&trec,color);
500     if (updates)
501         mUpdateRect(s,&trec);
502 };
503 
setFrame(int i)504 void Graphic::setFrame(int i) {
505     bmp = (i>=getImageCount()) ? RMIMGRef() : (&*images.first)[i];
506     cache_angle++;
507 }
508 
509 
510 /*
511  * Return the pixel value at (x, y)
512  * NOTE: The surface must be locked before calling this!
513  */
getpixel(SDL_Surface * surface,int x,int y)514 Uint32 getpixel(SDL_Surface *surface, int x, int y) {
515     int bpp = surface->format->BytesPerPixel;
516     /* Here p is the address to the pixel we want to retrieve */
517     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
518 
519     switch (bpp) {
520     case 1:
521         return *p;
522 
523     case 2:
524         return *(Uint16 *)p;
525 
526     case 3:
527         if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
528             return p[0] << 16 | p[1] << 8 | p[2];
529         else
530             return p[0] | p[1] << 8 | p[2] << 16;
531 
532     case 4:
533         return *(Uint32 *)p;
534 
535     default:
536         return 0;       /* shouldn't happen, but avoids warnings */
537     }
538 }
539 
SDLinsideImage(SDL_Surface * surface,int x,int y)540 bool SDLinsideImage(SDL_Surface * surface,int x,int y) {
541     x = Graphic::toScreenx(x);
542     y = Graphic::toScreeny(y);
543     if (!surface || x<0 || y<0 || x>=(int)surface->w || y>= (int)surface->h) return false;
544     SDL_LockSurface( surface );
545     Uint32 color=getpixel(surface,x,y);
546     SDL_UnlockSurface( surface );
547     if (surface->format->palette && surface->format->palette->colors) {
548         SDL_Color c=surface->format->palette->colors[color];
549         color=SDL_MapRGB(surface->format,c.r,c.g,c.b);
550     }
551     if (surface->flags & SDL_SRCCOLORKEY)
552         return color!=surface->format->colorkey;
553     else return color!=SDL_MapRGB(surface->format,0,0,0);
554 };
555 
insideImage(int x,int y) const556 bool Graphic::insideImage(int x,int y) const {
557     return SDLinsideImage(&*bmp,x,y);
558 }
559 
560 
GraphicSeq(Graphic * g)561 GraphicSeq::GraphicSeq(Graphic * g) : seqg(g) {
562     current=sstart=0;
563     send=0;
564     sloop=false;
565     hold=false;
566     sstep=1;
567     framestep=30;
568     remaining=framestep;
569 };
570 
571 
setFrameSequence(int start,int end,bool loop,bool forward)572 void GraphicSeq::setFrameSequence(int start,int end,bool loop,bool forward) {
573     current=(start<seqg->getImageCount()) ? start : seqg->getImageCount()-1;
574     sstart=current;
575     send=(end<seqg->getImageCount()) ? end : seqg->getImageCount()-1;
576     sloop=loop;
577     sstep=forward ? 1 : -1;
578 }
579 
stepSeq(int delta)580 void GraphicSeq::stepSeq(int delta) {
581     if (current==send && !sloop) {
582         if (!hold)
583             seqg->setFrame(seqg->getImageCount());
584         return;
585     }
586 
587     delta+=remaining;
588     while (delta>=framestep) {
589         delta-=framestep;
590         nextFrame();
591     }
592     remaining=delta;
593 }
594 
nextFrame()595 void GraphicSeq::nextFrame() {
596 
597     if (current==send && sloop) {
598         sstep*=-1;
599         int temp=sstart;
600         sstart=send;
601         send=temp;
602     }
603     if (current!=send) {
604         if (current+sstep<0)
605             current=seqg->getImageCount()-1;
606         else if ((int(current))+sstep==int(seqg->getImageCount()))
607             current=0;
608         else
609             current+=sstep;
610         seqg->setFrame(current);
611     } else if (!hold)
612         seqg->setFrame(seqg->getImageCount());
613 }
614 
createSurface(Uint16 w,Uint16 h)615 SDL_Surface * Graphic::createSurface(Uint16 w,Uint16 h) {
616     SDL_Surface * s=SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,
617                                          screen->format->BitsPerPixel,
618                                          screen->format->Rmask,
619                                          screen->format->Bmask,
620                                          screen->format->Gmask,
621                                          screen->format->Amask);
622     if (!s) {
623         CHERROR<<"Graphic: Error requesting temporal surface: "<<SDL_GetError()<<ENDL;
624         exit(1);
625     }
626     SDL_SetColorKey(s,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
627     SDL_Surface * t=SDL_DisplayFormat(s);
628     if (!t) {
629         CHERROR<<"Graphic: Error converting temporal surface to display format: "<<SDL_GetError()<<ENDL;
630         SDL_FreeSurface(s);
631         exit(1);
632     }
633     SDL_FreeSurface(s);
634     return t;
635 }
636 
637 
638 
639 #define NUM_ROT_FRAMES 128
640 #define NUM_ROT_FRAMESX 8
641 #define NUM_ROT_FRAMESY 16
642 #define MASKX 0x7
643 #define SHIFTY 3
ZoomRotator(const std::string & id)644 ZoomRotator::ZoomRotator(const std::string & id) {
645     RMIMGSETRef imgs=Singleton<ImageSetLoader>::getInstance()->create(id);
646     img=(&*imgs.first)[0];
647     updated=new bool[NUM_ROT_FRAMES];
648     memset(updated,0,sizeof(bool)*NUM_ROT_FRAMES);
649     rot=new SDL_Surface*[NUM_ROT_FRAMES];
650     for (int i=0;i<NUM_ROT_FRAMES;i++)
651         rot[i]=Graphic::createSurface(img->w,img->h);
652     if (Graphic::getScreen()->format->palette)
653         ROT_FLAG=0;
654     else
655         ROT_FLAG=SGE_TAA;
656     zoom=0;
657 };
658 
659 
draw(int x,int y,float angle,float zoom)660 void ZoomRotator::draw(int x,int y,float angle,float zoom) {
661     x = Graphic::toScreenx(x);
662     y = Graphic::toScreeny(y);
663     if (!(Graphic::screenx<=x+zoom*img->w && x<Graphic::screenx+Graphic::screenw &&
664           Graphic::screeny<=y+zoom*img->h && y<Graphic::screeny+Graphic::screenh))
665         return;
666 
667     if (fabsf(this->zoom-zoom)>EPS) {
668         memset(updated,0,sizeof(bool)*NUM_ROT_FRAMESX*NUM_ROT_FRAMESY);
669         this->zoom=zoom;
670     }
671     int i=int(angle*NUM_ROT_FRAMESX*NUM_ROT_FRAMESY/360.0);
672     SDL_Rect clip={0,0,img->w,img->h};
673     if (!updated[i]) {
674         Uint16 hotspotx=img->w>>1;
675         Uint16 hotspoty=img->h>>1;
676         SDL_FillRect(rot[i],NULL,SDL_MapRGB(rot[i]->format,0,0, 0));
677 
678         sge_transform(&*img,rot[i],360.0*i/(NUM_ROT_FRAMESX*NUM_ROT_FRAMESY),zoom,zoom,hotspotx,hotspoty,
679                       clip.x+Uint16(zoom*hotspotx),clip.y+Uint16(zoom*hotspoty),ROT_FLAG);
680         updated[i]=true;
681     }
682     clip.w=Uint16(clip.w*zoom);
683     clip.h=Uint16(clip.h*zoom);
684     SDL_Rect trec={x,y,clip.w,clip.h};
685     SDL_BlitSurface(rot[i],&clip,Graphic::getScreen(),&trec);
686     if (Graphic::isUpdating())
687         Graphic::mUpdateRect(Graphic::getScreen(),&trec);
688 };
689 
~ZoomRotator()690 ZoomRotator::~ZoomRotator() {
691     for (int i=0;i<NUM_ROT_FRAMES;i++)
692         SDL_FreeSurface(rot[i]);
693     delete[] updated;
694     delete[] rot;
695 }
696 
697 
698 #include "parsercombinators.h"
699 #include "SDL_image.h"
700 
parse(Parser & p,std::string * id)701 Parser & ImageLoader::parse(Parser & p,std::string * id) {
702     string imagepath;
703     PARSEbegin(Parser,p);
704     S("path=")PATTTEXT(&imagepath)S("/>");
705     img_paths.insert(imagepath);
706     if (id) *id=imagepath;
707     PARSEend;
708     return p;
709 }
710 
create(const string & path)711 SDL_Surface * ImageLoader::create(const string & path) {
712     if (img_paths.find(path)==img_paths.end()) {
713         CHERROR<<"ResourceManager error: Image file "<<path<<" was not declared in resource file."<<ENDL;
714         exit(1);
715     }
716 
717     // Load image if it is not loaded
718     SDL_RWops* rw=SDL_RWFromFile((GetDataPath()+path).c_str(),"r");
719     if (!rw) {
720         CHERROR<<"ResourceManager error: File "<<(GetDataPath()+path)<<" could not be loaded: "<<SDL_GetError()<<ENDL;
721         exit(1);
722     }
723 
724     SDL_Surface* s = IMG_Load_RW(rw,false);
725     SDL_RWclose(rw);
726     if (!s) {
727         CHERROR<<"ResourceManager error: Image "<<(GetDataPath()+path)<<" could not be loaded."<<ENDL;
728         exit(1);
729     }
730 
731     SDL_SetColorKey(s,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(Graphic::getScreen()->format, 0x00, 0x00, 0x00));
732 
733     SDL_Surface * t2=SDL_DisplayFormat(s);
734     SDL_FreeSurface(s);
735     if (!t2) {
736         CHERROR<<"ResourceManager error: Image "<<(GetDataPath()+path)<<" could not be converted to screen format."<<ENDL;
737         exit(1);
738     }
739 
740     SDL_Surface* t3 = t2;
741     if ((Graphic::getBaseScaleFactorX()!=1.0f || Graphic::getBaseScaleFactorY()!=1.0f)
742             && path!="art/mousepointer.png" && path!="art/deletepointer.png") {
743         t3 = Graphic::createSurface(Graphic::toScreenw(t2->w),Graphic::toScreenh(t2->h));
744         SDL_FillRect(t3,NULL,SDL_MapRGB(t3->format,0,0,0));
745         sge_transform(t2,t3,0.0f, Graphic::getBaseScaleFactorX(),Graphic::getBaseScaleFactorY(),0,0,0,0,
746                                   (Uint8)(t3->format->palette ? 0:SGE_TAA));
747         SDL_FreeSurface(t2);
748         if (!t3) {
749             CHERROR<<"ResourceManager error: Image "<<path<<" could not be scaled."<<ENDL;
750             exit(1);
751         }
752     }
753 
754     return t3;
755 };
756 
757 
parse(Parser & p,std::string * id)758 Parser & ImageSetLoader::parse(Parser & p,std::string * id) {
759     string imagepath,name;
760     vector<string> * vstring=NULL;
761     PARSEbegin(Parser,p);
762         LS("<imagesets>");
763         MANYbegin
764             TRY(S("<iset"));
765             WS
766             S("name=")PATTTEXT(&name)S(">");
767             if (img_sets[name]) {
768                 CHERROR<<"Image resource duplicated: "<<name<<ENDL;
769                 exit(1);
770             }
771             vstring=new vector<string>();
772             MANYbegin
773                 TRY(S("<image"))WS;
774                 P1(Singleton<ImageLoader>::getInstance()->parse,&imagepath);
775                 vstring->push_back(imagepath);
776             MANYend
777             S("</iset>");
778             WS;
779             img_sets[name]=vstring;
780             vstring=NULL;
781         MANYend
782         S("</imagesets>");
783     PARSEend;
784     if (vstring)
785         delete vstring;
786     return p;
787 }
788 
create(const string & id)789 std::pair<Ref<RMIMGRef,delarray> ,int> ImageSetLoader::create(const string & id) {
790     vector<string> * set=img_sets[id];
791     if (!set || set->size()==0) {
792         CHERROR<<"ResourceManager error: Resource image set "<<id<<" is not defined."<<ENDL;
793         exit(1);
794     }
795 
796     std::pair<Ref<RMIMGRef,delarray>,int> buf;
797     buf.first = Ref<RMIMGRef,delarray>(new RMIMGRef[set->size()]);
798     buf.second = set->size();
799     int counter=0;
800     for (vector<string>::iterator i=set->begin();i!=set->end();i++)
801         (&*buf.first)[counter++]=Resource<ImageLoader>(*i);
802 
803     return buf;
804 };
805 
~ImageSetLoader()806 ImageSetLoader::~ImageSetLoader() {
807     for (std::map<std::string,std::vector<std::string>*>::iterator i=img_sets.begin();
808             i!=img_sets.end();i++) delete i->second;
809 };
810 
811 
create(const std::string & id)812 ZoomRotator * RotateImageLoader::create(const std::string & id) {
813     return new ZoomRotator(id);
814 };
free(ZoomRotator * p)815 void RotateImageLoader::free(ZoomRotator * p) {
816     delete p;
817 };
818 
819 
create(const std::string & name)820 FontRenderer * FontLoader::create(const std::string & name) {
821     string path=font_paths[name];
822     if (!path.length()) {
823         CHERROR<<"ResourceManager error: Font "<<name<<" is not defined."<<ENDL;
824         exit(1);
825     }
826 
827     // Load font if it is not loaded
828     SDL_RWops *rw=SDL_RWFromFile((GetDataPath()+path).c_str(),"r");
829     if (!rw) {
830         CHERROR<<"ResourceManager error: File "<<(GetDataPath()+path)<<" could not be loaded: "<<SDL_GetError()<<ENDL;
831         exit(1);
832     }
833 
834     SDL_Surface * s=IMG_Load_RW(rw,false);
835     SDL_RWclose(rw);
836     if (!s) {
837         CHERROR<<"ResourceManager error: Font file "<<(GetDataPath()+path)<<" could not be loaded."<<ENDL;
838         exit(1);
839     }
840 
841     SDL_Surface* ss = s;
842     if ((Graphic::getBaseScaleFactorX()!=1.0f || Graphic::getBaseScaleFactorY()!=1.0f)) {
843         SDL_Surface* temp = SDL_DisplayFormat(s);
844         SDL_FreeSurface(s);
845         ss = sge_transform_surface(temp,SDL_MapRGB(temp->format,0,0,0),0.0f,
846                                   Graphic::getBaseScaleFactorX(),Graphic::getBaseScaleFactorY(),
847                                   (Uint8)SGE_TAA);
848         SDL_FreeSurface(temp);
849         if (!ss) {
850             CHERROR<<"ResourceManager error: Font "<<(GetDataPath()+path)<<" could not be scaled."<<ENDL;
851             exit(1);
852         }
853     }
854 
855 
856     SFont_Font * sf=SFont_InitFont(ss);
857     SDL_FreeSurface(ss);
858 
859     return new SFontRenderer(sf);
860 };
861 
parse(Parser & p,std::string * id)862 Parser & FontLoader::parse(Parser & p,std::string * id) {
863     std::string path, name;
864     PARSEbegin(Parser,p);
865         TRY(LS("<fonts>"));
866         MANYbegin;
867             TRY(S("<font"))WS;
868             S("name=")PATTTEXT(&name)S("path=")PATTTEXT(&path)S("/>");
869             font_paths[name]=path;
870         MANYend;
871         S("</fonts>");
872     PARSEend;
873     return p;
874 };
875 
876