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