1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 window.cpp - Generic Rendering Window
4 ---------------------------------------------------------------------------
5 * Copyright (C) 2001-2003, 2006, 2007 David Olofson
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "logger.h"
23 #include "window.h"
24 #include "gfxengine.h"
25 #include "sofont.h"
26
27 #define SELECT if(selected != this) _select();
28
29 window_t *window_t::selected = NULL;
30
window_t()31 window_t::window_t()
32 {
33 engine = NULL;
34 surface = NULL;
35 next = NULL;
36 prev = NULL;
37 phys_rect.x = phys_rect.y = 0;
38 phys_rect.w = 320;
39 phys_rect.h = 240;
40 fgcolor = bgcolor = 0;
41 selected = 0;
42 xs = ys = 256;
43 bg_bank = -1;
44 bg_frame = -1;
45 _visible = 1;
46 _offscreen = 0;
47 }
48
49
~window_t()50 window_t::~window_t()
51 {
52 if(_offscreen && surface)
53 SDL_FreeSurface(surface);
54 if(selected == this)
55 selected = NULL;
56 unlink();
57 }
58
59
init(gfxengine_t * e)60 void window_t::init(gfxengine_t *e)
61 {
62 link(e);
63 xs = engine->xs;
64 ys = engine->ys;
65 if(_offscreen && surface)
66 {
67 SDL_FreeSurface(surface);
68 surface = NULL;
69 }
70 _offscreen = 0;
71 surface = engine->surface();
72 }
73
74
visible(int vis)75 void window_t::visible(int vis)
76 {
77 if(_offscreen)
78 return; // Cannot be visible!
79 if(_visible == vis)
80 return;
81 _visible = vis;
82 invalidate();
83 }
84
85
link(gfxengine_t * e)86 void window_t::link(gfxengine_t *e)
87 {
88 unlink();
89 engine = e;
90 next = NULL;
91 prev = engine->windows;
92 if(prev)
93 {
94 while(prev->next)
95 prev = prev->next;
96 prev->next = this;
97 }
98 else
99 engine->windows = this;
100 }
101
102
unlink(void)103 void window_t::unlink(void)
104 {
105 if(engine)
106 {
107 if(engine->windows == this)
108 engine->windows = next;
109 if(engine->surface() == surface)
110 surface = NULL;
111 }
112 if(next)
113 next->prev = prev;
114 if(prev)
115 prev->next = next;
116 }
117
118
place(int left,int top,int sizex,int sizey)119 void window_t::place(int left, int top, int sizex, int sizey)
120 {
121 int x2 = ((left + sizex) * xs + 128) >> 8;
122 int y2 = ((top + sizey) * ys + 128) >> 8;
123 phys_rect.x = (left * xs + 128) >> 8;
124 phys_rect.y = (top * ys + 128) >> 8;
125 phys_rect.w = x2 - phys_rect.x;
126 phys_rect.h = y2 - phys_rect.y;
127 }
128
129
offscreen()130 int window_t::offscreen()
131 {
132 if(!engine)
133 return -1;
134 if(!engine->surface())
135 return -1;
136 if(_offscreen)
137 return 0; // Already offscreen!
138 visible(0);
139 _offscreen = 1;
140 SDL_Surface *s = SDL_CreateRGBSurface(SDL_SWSURFACE,
141 phys_rect.w, phys_rect.h,
142 32, 0xff000000, 0x00ff0000,
143 0x0000ff00, 0x000000ff);
144 if(!s)
145 return -1;
146 surface = SDL_DisplayFormat(s);
147 SDL_FreeSurface(s);
148 if(!surface)
149 return -1;
150 return 0;
151 }
152
153
select()154 void window_t::select()
155 {
156 if(engine)
157 _select();
158 }
159
160
_select()161 void window_t::_select()
162 {
163 SDL_Rect r = phys_rect;
164 selected = this;
165 if(surface)
166 SDL_SetClipRect(surface, &r);
167 }
168
169
invalidate(SDL_Rect * r)170 void window_t::invalidate(SDL_Rect *r)
171 {
172 if(!engine)
173 return;
174 if(!engine->surface())
175 return;
176
177 SELECT
178
179 if(_offscreen)
180 {
181 if(!r)
182 {
183 SDL_Rect rr;
184 rr.x = 0;
185 rr.y = 0;
186 rr.w = phys_rect.w;
187 rr.h = phys_rect.h;
188 phys_refresh(&rr);
189 glSDL_Invalidate(surface, &rr);
190 }
191 else
192 {
193 phys_refresh(r);
194 glSDL_Invalidate(surface, r);
195 }
196 return;
197 }
198
199 if(!r)
200 engine->invalidate(&phys_rect, this);
201 else
202 {
203 /* Translate to screen coordinates */
204 SDL_Rect dr = *r;
205 dr.x = (dr.x * xs + 128) >> 8;
206 dr.y = (dr.y * ys + 128) >> 8;
207 dr.w = (((dr.w + dr.x) * xs + 128) >> 8) - dr.x;
208 dr.h = (((dr.h + dr.y) * ys + 128) >> 8) - dr.y;
209 dr.x += phys_rect.x;
210 dr.y += phys_rect.y;
211
212 /* Clip to window (stolen from SDL_surface.c) */
213 int Amin, Amax, Bmin, Bmax;
214
215 /* Horizontal intersection */
216 Amin = dr.x;
217 Amax = Amin + dr.w;
218 Bmin = phys_rect.x;
219 Bmax = Bmin + phys_rect.w;
220 if(Bmin > Amin)
221 Amin = Bmin;
222 dr.x = Amin;
223 if(Bmax < Amax)
224 Amax = Bmax;
225 dr.w = Amax - Amin > 0 ? Amax - Amin : 0;
226
227 /* Vertical intersection */
228 Amin = dr.y;
229 Amax = Amin + dr.h;
230 Bmin = phys_rect.y;
231 Bmax = Bmin + phys_rect.h;
232 if(Bmin > Amin)
233 Amin = Bmin;
234 dr.y = Amin;
235 if(Bmax < Amax)
236 Amax = Bmax;
237 dr.h = Amax - Amin > 0 ? Amax - Amin : 0;
238
239 if(dr.w && dr.h)
240 engine->invalidate(&dr, this);
241 }
242 }
243
244
245 /*---------------------------------------------------------------
246 Rendering API
247 ---------------------------------------------------------------*/
248
map_rgb(Uint8 r,Uint8 g,Uint8 b)249 Uint32 window_t::map_rgb(Uint8 r, Uint8 g, Uint8 b)
250 {
251 if(!engine)
252 return 0;
253
254 if(surface)
255 return SDL_MapRGB(surface->format, r, g, b);
256 else
257 return 0xffffff;
258 }
259
map_rgb(Uint32 rgb)260 Uint32 window_t::map_rgb(Uint32 rgb)
261 {
262 if(!engine)
263 return 0;
264
265 Uint8 r = (rgb >> 16) & 0xff;
266 Uint8 g = (rgb >> 8) & 0xff;
267 Uint8 b = rgb & 0xff;
268
269 if(surface)
270 return SDL_MapRGB(surface->format, r, g, b);
271 else
272 return 0xffffff;
273 }
274
bgimage(int bank,int frame)275 void window_t::bgimage(int bank, int frame)
276 {
277 bg_bank = bank;
278 bg_frame = frame;
279 }
280
281
colorkey(Uint32 color)282 void window_t::colorkey(Uint32 color)
283 {
284 if(!engine)
285 return;
286 if(!engine->surface())
287 return;
288 if(!_offscreen)
289 return;
290 SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color);
291 }
292
colorkey()293 void window_t::colorkey()
294 {
295 if(!engine)
296 return;
297 if(!engine->surface())
298 return;
299 if(!_offscreen)
300 return;
301 SDL_SetColorKey(surface, 0, 0);
302 }
303
alpha(float a)304 void window_t::alpha(float a)
305 {
306 if(!engine)
307 return;
308 if(!engine->surface())
309 return;
310 if(!_offscreen)
311 return;
312 SDL_SetAlpha(surface, SDL_SRCALPHA, (int)(a * 255.0));
313 }
314
315
font(int fnt)316 void window_t::font(int fnt)
317 {
318 _font = fnt;
319 }
320
321
string(int _x,int _y,const char * txt)322 void window_t::string(int _x, int _y, const char *txt)
323 {
324 string_fxp(PIXEL2CS(_x), PIXEL2CS(_y), txt);
325 }
326
327
center(int _y,const char * txt)328 void window_t::center(int _y, const char *txt)
329 {
330 center_fxp(PIXEL2CS(_y), txt);
331 }
332
333
center_token(int _x,int _y,const char * txt,char token)334 void window_t::center_token(int _x, int _y, const char *txt, char token)
335 {
336 center_token_fxp(PIXEL2CS(_x), PIXEL2CS(_y), txt, token);
337 }
338
339
string_fxp(int _x,int _y,const char * txt)340 void window_t::string_fxp(int _x, int _y, const char *txt)
341 {
342 if(!engine)
343 return;
344
345 _x = CS2PIXEL((_x * xs + 128) >> 8);
346 _y = CS2PIXEL((_y * ys + 128) >> 8);
347 SoFont *f = engine->get_font(_font);
348 if(!f)
349 return;
350 SELECT
351 _x += phys_rect.x;
352 _y += phys_rect.y;
353 if(surface)
354 f->PutString(surface, _x, _y, txt);
355 }
356
357
center_fxp(int _y,const char * txt)358 void window_t::center_fxp(int _y, const char *txt)
359 {
360 _y = CS2PIXEL((_y * ys + 128) >> 8);
361
362 if(!engine)
363 return;
364
365 SoFont *f = engine->get_font(_font);
366 if(!f)
367 return;
368 SELECT
369 int _x = (phys_rect.w - f->TextWidth(txt) + 1) / 2;
370 _x += phys_rect.x;
371 _y += phys_rect.y;
372 if(surface)
373 f->PutString(surface, _x, _y, txt);
374 }
375
376
center_token_fxp(int _x,int _y,const char * txt,char token)377 void window_t::center_token_fxp(int _x, int _y, const char *txt, char token)
378 {
379 _x = CS2PIXEL((_x * xs + 128) >> 8);
380 _y = CS2PIXEL((_y * ys + 128) >> 8);
381
382 if(!engine)
383 return;
384
385 SoFont *f = engine->get_font(_font);
386 if(!f)
387 return;
388 SELECT
389 int _cx;
390 if(-1 == token)
391 _cx = _x - f->TextWidth(txt)/2;
392 else
393 {
394 int tokpos;
395 /*
396 * My docs won't say if strchr(???, 0) is legal
397 * or even defined, so I'm not taking any chances...
398 */
399 if(token)
400 {
401 const char *tok = strchr(txt, token);
402 if(tok)
403 tokpos = tok-txt;
404 else
405 tokpos = 255;
406 }
407 else
408 tokpos = 255;
409 _cx = _x - f->TextWidth(txt, 0, tokpos);
410 }
411 _cx += phys_rect.x;
412 _y += phys_rect.y;
413 if(surface)
414 f->PutString(surface, _cx, _y, txt);
415 }
416
417
textwidth_fxp(const char * txt,int min,int max)418 int window_t::textwidth_fxp(const char *txt, int min, int max)
419 {
420 if(!engine)
421 return strlen(txt);
422
423 SoFont *f = engine->get_font(_font);
424 if(!f)
425 return strlen(txt);
426
427 return (f->TextWidth(txt, min, max) << 16) / xs;
428 }
429
430
textwidth(const char * txt,int min,int max)431 int window_t::textwidth(const char *txt, int min, int max)
432 {
433 if(!engine)
434 return strlen(txt);
435
436 SoFont *f = engine->get_font(_font);
437 if(!f)
438 return strlen(txt);
439
440 return (f->TextWidth(txt, min, max) << 8) / xs;
441 }
442
443
fontheight()444 int window_t::fontheight()
445 {
446 if(!engine)
447 return 1;
448
449 SoFont *f = engine->get_font(_font);
450 if(!f)
451 return 1;
452
453 return (f->FontHeight() * 256) / ys;
454 }
455
456
clear(SDL_Rect * r)457 void window_t::clear(SDL_Rect *r)
458 {
459 SDL_Rect sr, dr;
460 if(!engine)
461 return;
462 if(!surface)
463 return;
464 SELECT
465 if(!r)
466 {
467 sr = phys_rect;
468 sr.x = 0;
469 sr.y = 0;
470 dr = phys_rect;
471 }
472 else
473 {
474 sr.x = ((int)r->x * xs + 128) >> 8;
475 sr.y = ((int)r->y * ys + 128) >> 8;
476 sr.w = (((int)(r->x + r->w) * xs + 128) >> 8) - sr.x;
477 sr.h = (((int)(r->y + r->h) * ys + 128) >> 8) - sr.y;
478 dr = sr;
479 dr.x += phys_rect.x;
480 dr.y += phys_rect.y;
481 }
482 if((-1 == bg_bank) && (-1 == bg_frame))
483 SDL_FillRect(surface, &dr, bgcolor);
484 else
485 {
486 s_sprite_t *s = engine->get_sprite(bg_bank, bg_frame);
487 if(!s || !s->surface)
488 {
489 SDL_FillRect(surface, &dr, bgcolor);
490 return;
491 }
492 SDL_BlitSurface(s->surface, &sr, surface, &dr);
493 }
494 }
495
496
point(int _x,int _y)497 void window_t::point(int _x, int _y)
498 {
499 int x2 = ((_x + 1) * xs + 128) >> 8;
500 int y2 = ((_y + 1) * ys + 128) >> 8;
501 _x = (_x * xs + 128) >> 8;
502 _y = (_y * ys + 128) >> 8;
503
504 if(!engine)
505 return;
506 SELECT
507 /* Quick hack; slow */
508 SDL_Rect r;
509 r.x = phys_rect.x + _x;
510 r.y = phys_rect.y + _y;
511 r.w = x2 - _x;
512 r.h = y2 - _y;
513 if(surface)
514 SDL_FillRect(surface, &r, fgcolor);
515 }
516
517
fillrect(int _x,int _y,int w,int h)518 void window_t::fillrect(int _x, int _y, int w, int h)
519 {
520 int x2 = ((_x + w) * xs + 128) >> 8;
521 int y2 = ((_y + h) * ys + 128) >> 8;
522 _x = (_x * xs + 128) >> 8;
523 _y = (_y * ys + 128) >> 8;
524
525 if(!engine)
526 return;
527 SELECT
528 SDL_Rect r;
529 r.x = phys_rect.x + _x;
530 r.y = phys_rect.y + _y;
531 r.w = x2 - _x;
532 r.h = y2 - _y;
533 if(surface)
534 SDL_FillRect(surface, &r, fgcolor);
535 }
536
537
rectangle(int _x,int _y,int w,int h)538 void window_t::rectangle(int _x, int _y, int w, int h)
539 {
540 fillrect(_x, _y, w, 1);
541 fillrect(_x, _y + h - 1, w, 1);
542 fillrect(_x, _y + 1, 1, h - 2);
543 fillrect(_x + w - 1, _y + 1, 1, h - 2);
544 }
545
546
fillrect_fxp(int _x,int _y,int w,int h)547 void window_t::fillrect_fxp(int _x, int _y, int w, int h)
548 {
549 int xx = CS2PIXEL((_x * xs + 128) >> 8);
550 int yy = CS2PIXEL((_y * ys + 128) >> 8);
551 w = CS2PIXEL(((w + _x) * xs + 128) >> 8) - xx;
552 h = CS2PIXEL(((h + _y) * ys + 128) >> 8) - yy;
553
554 if(!engine)
555 return;
556 SELECT
557 SDL_Rect r;
558 r.x = phys_rect.x + xx;
559 r.y = phys_rect.y + yy;
560 r.w = w;
561 r.h = h;
562 if(surface)
563 SDL_FillRect(surface, &r, fgcolor);
564 }
565
566
sprite(int _x,int _y,int bank,int frame,int inval)567 void window_t::sprite(int _x, int _y, int bank, int frame, int inval)
568 {
569 sprite_fxp(PIXEL2CS(_x), PIXEL2CS(_y), bank, frame, inval);
570 }
571
572
sprite_fxp(int _x,int _y,int bank,int frame,int inval)573 void window_t::sprite_fxp(int _x, int _y, int bank, int frame, int inval)
574 {
575 if(!engine)
576 return;
577 s_sprite_t *s = engine->get_sprite(bank, frame);
578 if(!s || !s->surface)
579 return;
580 _x = CS2PIXEL(((_x - (s->x << 8)) * xs + 128) >> 8);
581 _y = CS2PIXEL(((_y - (s->y << 8)) * ys + 128) >> 8);
582 SDL_Rect dest_rect;
583
584 SELECT
585 dest_rect.x = phys_rect.x + _x;
586 dest_rect.y = phys_rect.y + _y;
587 if(surface)
588 SDL_BlitSurface(s->surface, NULL, surface, &dest_rect);
589
590 if(inval && !engine->autoinvalidate())
591 {
592 dest_rect.w = s->surface->w;
593 dest_rect.h = s->surface->h;
594 engine->invalidate(&dest_rect, this);
595 }
596 }
597
598
blit(int dx,int dy,int sx,int sy,int sw,int sh,window_t * src)599 void window_t::blit(int dx, int dy,
600 int sx, int sy, int sw, int sh, window_t *src)
601 {
602 if(!engine)
603 return;
604 if(!src)
605 return;
606 if(!surface)
607 return;
608 if(!src->surface)
609 return;
610 SELECT
611
612 SDL_Rect src_rect;
613 int sx2 = ((sx + sw) * xs + 128) >> 8;
614 int sy2 = ((sy + sh) * ys + 128) >> 8;
615 src_rect.x = (sx * xs + 128) >> 8;
616 src_rect.y = (sy * ys + 128) >> 8;
617 src_rect.w = sx2 - src_rect.x;
618 src_rect.h = sy2 - src_rect.y;
619
620 SDL_Rect dest_rect;
621 dest_rect.x = phys_rect.x + ((dx * xs + 128) >> 8);
622 dest_rect.y = phys_rect.y + ((dy * ys + 128) >> 8);
623
624 SDL_BlitSurface(src->surface, &src_rect, surface, &dest_rect);
625 }
626
627
blit(int dx,int dy,window_t * src)628 void window_t::blit(int dx, int dy, window_t *src)
629 {
630 if(!engine)
631 return;
632 if(!src)
633 return;
634 if(!surface)
635 return;
636 if(!src->surface)
637 return;
638
639 SELECT
640 dx = (dx * xs + 128) >> 8;
641 dy = (dy * ys + 128) >> 8;
642
643 SDL_Rect src_rect;
644 src_rect.x = 0;
645 src_rect.y = 0;
646 src_rect.w = src->surface->w;
647 src_rect.h = src->surface->h;
648
649 SDL_Rect dest_rect;
650 dest_rect.x = phys_rect.x + dx;
651 dest_rect.y = phys_rect.y + dy;
652
653 SDL_BlitSurface(src->surface, &src_rect, surface, &dest_rect);
654 }
655