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