1 /*
2 * Copyright (C) 2003 Tim Martin
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17 */
18
19
20 #include "sdlwin.h"
21 #include "sdl.h"
22
23 #include "landvalue.h"
24 #include "map.h"
25 #include "utils.h"
26
27 #include <SDL_image.h>
28 #include "SDL_rotozoom.h"
29
30 SDL_Surface *sdlscreen = NULL;
31 SDLFont *myfont = NULL;
32 static int sdlwin_inited = 0;
33
34 int ownercolors[][3] =
35 {
36 {255, 255, 255},
37 {60, 175, 80},
38 {255, 255, 0},
39 {255, 75, 125},
40 {125, 100, 255},
41 {255, 0, 255},
42 };
43
44 static SDL_Surface *
resize_image(SDL_Surface * src,int request_width)45 resize_image(SDL_Surface *src, int request_width)
46 {
47 double zoom = (double)request_width/src->w;
48 return zoomSurface(src, zoom, zoom, 0);
49 }
50
51 /* Integer math version of SDL_ScaleBlit().
52 * Where necessary, a number uses the 16 high bits for the integer
53 * and the 16 low bits for the decimal portion.
54 *
55 * eg:
56 * float a = (float) (b >> 16) + (b & 0xFFFF)/65536.0;
57 */
58
ifloor(Uint32 i)59 static inline Uint32 ifloor(Uint32 i)
60 {
61 return i & 0xFFFF0000;
62 }
63
iceil(Uint32 i)64 static inline Uint32 iceil(Uint32 i)
65 {
66 return (i & 0xFFFF) ? i : ifloor(i) + (1<<16);
67 }
68
69 static int
set_alpha(int specials,SDL_Surface * image)70 set_alpha(int specials, SDL_Surface *image)
71 {
72 int alpha = 255;
73
74 if ((specials & MAPSPECIAL_HILITE) == MAPSPECIAL_HILITE) {
75 alpha -= 50;
76 }
77 if ((specials & MAPSPECIAL_HILITE_INVALID) == MAPSPECIAL_HILITE_INVALID) {
78 alpha -= 100;
79 }
80 if ((specials & MAPSPECIAL_CURSOR) == MAPSPECIAL_CURSOR) {
81 alpha -= 100;
82 }
83 if ((specials & MAPSPECIAL_SELECTED) == MAPSPECIAL_SELECTED) {
84 alpha -= 60;
85 }
86
87 if (alpha < 100) alpha = 100;
88
89 if (alpha < 255) {
90 SDL_SetAlpha(image, SDL_SRCALPHA, alpha);
91 }
92
93 return alpha;
94 }
95
96 static void
reset_alpha(int alpha,SDL_Surface * image)97 reset_alpha(int alpha, SDL_Surface *image)
98 {
99 if (alpha < 255) {
100 SDL_SetAlpha(image, SDL_SRCALPHA, 255);
101 }
102 }
103
104
105 static void
ShowImg(SDL_Surface * screen,SDL_Surface * image,int x,int y,int specials)106 ShowImg(SDL_Surface *screen, SDL_Surface *image, int x, int y, int specials)
107 {
108 SDL_Rect dest;
109 int alpha;
110
111 if (!image) return;
112
113 /* Blit onto the screen surface.
114 The surfaces should not be locked at this point.
115 */
116 dest.x = x;
117 dest.y = y;
118 dest.w = image->w;
119 dest.h = image->h;
120
121 alpha = set_alpha(specials, image);
122
123 SDL_BlitSurface(image, NULL, screen, &dest);
124
125 reset_alpha(alpha, image);
126 }
127
sdlwin_clearscreen(void)128 void sdlwin_clearscreen(void)
129 {
130 SDL_Rect rect;
131
132 rect.x = 0;
133 rect.y = 0;
134 rect.w = sdlscreen->w-1;
135 rect.h = sdlscreen->h-1;
136 SDL_FillRect(sdlscreen, &rect, SDL_MapRGB(sdlscreen->format, 0, 0, 0));
137 }
138
sdlwin_updatescreen(void)139 void sdlwin_updatescreen(void)
140 {
141 SDL_Rect dest;
142 dest.x = 0;
143 dest.y = 0;
144 dest.w = sdlscreen->w-1;
145 dest.h = sdlscreen->h-1;
146
147 SDL_UpdateRects(sdlscreen, 1, &dest);
148 }
149
sdlwin_init(GtkWidget * widget)150 int sdlwin_init(GtkWidget *widget)
151 {
152 /* Hack to get SDL to use GTK window */
153 {
154 char SDL_windowhack[32];
155 sprintf(SDL_windowhack,"SDL_WINDOWID=%ld",
156 GDK_WINDOW_XWINDOW(widget->window));
157 putenv(SDL_windowhack);
158 }
159
160 /* Initialize SDL */
161 if (!sdlwin_inited) {
162 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
163 fprintf(stderr,_("Couldn't initialize SDL: %s\n"),SDL_GetError());
164 gtk_main_quit();
165 }
166 }
167
168 if (sdlscreen) SDL_FreeSurface(sdlscreen);
169 sdlscreen = SDL_SetVideoMode(widget->allocation.width,
170 widget->allocation.height,
171 0, SDL_RESIZABLE);
172 sdlwin_updatescreen();
173
174 if (!myfont) {
175 myfont = load_fixed_font(IMG_DIRECTORY "f_small_green.bmp", 32, 96, 8 );
176 if (!myfont) {
177 myfont = load_fixed_font( "../img/f_small_green.bmp", 32, 96, 8 );
178 if (!myfont) {
179 printf(_("Unable to load font!\n"));
180 }
181 }
182 }
183
184 sdlwin_inited = 1;
185
186 return 0;
187 }
188
189 static void
draw_grid_lines(display_t * display,square_t * drawsquare,int owner,map_t * map,int mapx,int mapy)190 draw_grid_lines(display_t *display,
191 square_t *drawsquare, int owner, map_t *map, int mapx, int mapy)
192 {
193 Uint32 gridlinecolor = -1;
194
195
196 gridlinecolor = SDL_MapRGB(sdlscreen->format,
197 ownercolors[owner][0],
198 ownercolors[owner][1],
199 ownercolors[owner][2]);
200
201 /* draw grid lines */
202 DoLine(sdlscreen,
203 drawsquare->parts.leftx, drawsquare->parts.lefty,
204 drawsquare->parts.topx, drawsquare->parts.topy,
205 gridlinecolor, 255);
206 DoLine(sdlscreen,
207 drawsquare->parts.topx, drawsquare->parts.topy,
208 drawsquare->parts.rightx, drawsquare->parts.righty,
209 gridlinecolor, 255);
210 DoLine(sdlscreen,
211 drawsquare->parts.rightx, drawsquare->parts.righty,
212 drawsquare->parts.botx, drawsquare->parts.boty,
213 gridlinecolor, 255);
214 DoLine(sdlscreen,
215 drawsquare->parts.botx, drawsquare->parts.boty,
216 drawsquare->parts.leftx, drawsquare->parts.lefty,
217 gridlinecolor, 255);
218
219 /*
220 * If in owner view display another set of lines closer in
221 */
222 if ((display->view == GAMEVIEW_OWNERS) && (owner > 0)) {
223 if ((mapx == 0) || (map_get_owner(map, mapx-1, mapy) != owner)) {
224 DoLine(sdlscreen,
225 drawsquare->parts.leftx+3, drawsquare->parts.lefty,
226 drawsquare->parts.topx, drawsquare->parts.topy+2,
227 gridlinecolor, 255);
228 DoLine(sdlscreen,
229 drawsquare->parts.leftx+6, drawsquare->parts.lefty,
230 drawsquare->parts.topx, drawsquare->parts.topy+4,
231 gridlinecolor, 255);
232 }
233
234 if ((mapy == 0) || (map_get_owner(map, mapx, mapy-1) != owner)) {
235 DoLine(sdlscreen,
236 drawsquare->parts.topx, drawsquare->parts.topy+2,
237 drawsquare->parts.rightx-3, drawsquare->parts.righty,
238 gridlinecolor, 255);
239 DoLine(sdlscreen,
240 drawsquare->parts.topx, drawsquare->parts.topy+4,
241 drawsquare->parts.rightx-6, drawsquare->parts.righty,
242 gridlinecolor, 255);
243 }
244
245 if ((mapx == map_get_sizex(map)-1) || (map_get_owner(map, mapx+1, mapy) != owner)) {
246 DoLine(sdlscreen,
247 drawsquare->parts.rightx-3, drawsquare->parts.righty,
248 drawsquare->parts.botx, drawsquare->parts.boty-2,
249 gridlinecolor, 255);
250 DoLine(sdlscreen,
251 drawsquare->parts.rightx-6, drawsquare->parts.righty,
252 drawsquare->parts.botx, drawsquare->parts.boty-4,
253 gridlinecolor, 255);
254 }
255
256 if ((mapy == map_get_sizey(map)-1) || (map_get_owner(map, mapx, mapy+1) != owner)) {
257 DoLine(sdlscreen,
258 drawsquare->parts.botx, drawsquare->parts.boty-2,
259 drawsquare->parts.leftx+3, drawsquare->parts.lefty,
260 gridlinecolor, 255);
261 DoLine(sdlscreen,
262 drawsquare->parts.botx, drawsquare->parts.boty-4,
263 drawsquare->parts.leftx+6, drawsquare->parts.lefty,
264 gridlinecolor, 255);
265 }
266 }
267 }
268
269 static void
fillsquare(int r,int g,int b,int a,square_t * drawsquare)270 fillsquare(int r, int g, int b, int a, square_t *drawsquare)
271 {
272 Uint32 color;
273
274 color = SDL_MapRGBA(sdlscreen->format,
275 r, g, b, a);
276
277 DoFilledPolygon (sdlscreen,
278 drawsquare->parts.leftx, drawsquare->parts.lefty,
279 drawsquare->parts.topx, drawsquare->parts.topy,
280 drawsquare->parts.rightx, drawsquare->parts.righty,
281 drawsquare->parts.botx, drawsquare->parts.boty,
282 color, a);
283 }
284
285 static void
ShowPattern(SDL_Surface * screen,SDL_Surface * pattern,square_t * drawsquare,int specials)286 ShowPattern(SDL_Surface *screen, SDL_Surface *pattern, square_t *drawsquare,
287 int specials)
288 {
289 int alpha;
290
291 alpha = set_alpha(specials, pattern);
292
293 DoPattern (sdlscreen,
294 drawsquare->parts.leftx, drawsquare->parts.lefty,
295 drawsquare->parts.topx, drawsquare->parts.topy,
296 drawsquare->parts.rightx, drawsquare->parts.righty,
297 drawsquare->parts.botx, drawsquare->parts.boty,
298 pattern);
299
300 reset_alpha(alpha, pattern);
301 }
302
303 #if 0
304 static void
305 ShowSolid(SDL_Surface *screen, int r, int g, int b,
306 square_t *square, int specials)
307 {
308 int alpha = set_alpha(specials, sdlscreen);
309
310 fillsquare(r, g, b, alpha, square);
311
312 reset_alpha(alpha, sdlscreen);
313 }
314 #endif /* 0 */
315
316 static void
ShowSolid_minus(SDL_Surface * screen,int r,int g,int b,square_t * square,int minus,int specials)317 ShowSolid_minus(SDL_Surface *screen, int r, int g, int b,
318 square_t *square, int minus, int specials)
319 {
320 int alpha = set_alpha(specials, sdlscreen);
321 square_t sq2;
322
323 sq2.parts.topx = square->parts.topx;
324 sq2.parts.rightx = square->parts.rightx - minus;
325 sq2.parts.leftx = square->parts.leftx + minus;
326 sq2.parts.botx = square->parts.botx;
327
328 sq2.parts.topy = square->parts.topy + minus;
329 sq2.parts.righty = square->parts.righty;
330 sq2.parts.lefty = square->parts.lefty;
331 sq2.parts.boty = square->parts.boty - minus;
332
333 fillsquare(r, g, b, alpha, &sq2);
334
335 reset_alpha(alpha, sdlscreen);
336 }
337
338 static void
show_tile(display_t * display,tiles_t * tiles,screen_t * screen,mapobj_t mapobj,int x,int y,int sx,int sy,surrounding_t * surrounding,heightsquare_t * heightsquare,square_t * drawsquare,int dirview,int zoom,int specials)339 show_tile(display_t *display, tiles_t *tiles, screen_t *screen, mapobj_t mapobj,
340 int x, int y, int sx, int sy,
341 surrounding_t *surrounding,
342 heightsquare_t *heightsquare,
343 square_t *drawsquare,
344 int dirview, int zoom, int specials)
345 {
346 tile_t *tile;
347 int tilesizex;
348 int tilesizey;
349 int tileheight;
350
351 screen_tilesizes(screen, &tilesizex, &tilesizey, &tileheight);
352
353 if (!display->showbuildings) {
354
355 #if 0 /* xxx */
356 switch (map_item_gettype(mapobj))
357 {
358 case MAPTYPE_GOVERNMENT:
359 case MAPTYPE_EMPTY:
360 case MAPTYPE_ENTERTAINMENT:
361 /* don't change */
362 break;
363 case MAPTYPE_HOUSE:
364 mapobj = MAPOBJ_ZONE_HOUSE;
365 break;
366 case MAPTYPE_COMMERCIAL:
367 mapobj = MAPOBJ_ZONE_COMMERCIAL;
368 break;
369 case MAPTYPE_OFFICE:
370 mapobj = MAPOBJ_ZONE_OFFICE;
371 break;
372 case MAPTYPE_INDUSTRIAL:
373 mapobj = MAPOBJ_ZONE_INDUSTRIAL;
374 break;
375 case MAPTYPE_FARM:
376 mapobj = MAPOBJ_ZONE_FARM;
377 break;
378 }
379 #endif /* 0 */
380 }
381
382
383 if (tiles_get(tiles, mapobj, surrounding, heightsquare, &tile) == 0) {
384 void *image = tile_image(tiles, tile, dirview, zoom);
385
386 if (image) {
387 if (tile->ispattern) {
388 ShowPattern(sdlscreen, image, drawsquare, specials);
389 } else {
390 ShowImg(sdlscreen, image,
391 x - ((sy-1)*tilesizex/2), y - heightsquare->dir.topleft*tileheight - tile->extray[dirview][zoom] - (sx-1+sy-1)*tilesizey/2,
392 specials);
393 }
394 } else {
395 ShowSolid_minus(sdlscreen, tile->color_r, tile->color_g, tile->color_b,
396 drawsquare, 1, specials);
397 }
398 } else {
399 printf(_("unable to get tile! obj = %d\n"), mapobj);
400 }
401 }
402
403 static void
display_land_value(map_t * map,tiles_t * tiles,int mapx,int mapy,square_t * drawsquare,int zoom,int owner,int activity)404 display_land_value(map_t *map, tiles_t *tiles, int mapx, int mapy, square_t *drawsquare,
405 int zoom, int owner, int activity)
406 {
407 int value;
408 char str[10];
409 int strheight = 0;
410 int strwidth;
411
412 if (zoom >= 2) return;
413
414 switch (activity)
415 {
416 case MAPOBJ_ACTION_BUYLAND:
417 if (!map_empty_land(map, mapx, mapy)) return;
418 /* fallthru */
419 case MAPOBJ_ACTION_BUYALL:
420 if (owner != NO_OWNER) return;
421 break;
422 case MAPOBJ_ACTION_SELLLAND:
423 if (!map_empty_land(map, mapx, mapy)) return;
424 /* fallthru */
425 case MAPOBJ_ACTION_SELLALL:
426 if (owner == NO_OWNER) return;
427 break;
428
429 default:
430 return;
431 }
432
433 value = government_calculate_onelandvalue(map, tiles, mapx, mapy);
434
435 snprintf(str, sizeof(str),"$%d",value);
436
437 strwidth = text_width(myfont, str);
438 strheight = 12; /* xxx */
439
440 write_text(myfont, sdlscreen,
441 (drawsquare->parts.leftx + drawsquare->parts.rightx)/2 - strwidth/2,
442 (drawsquare->parts.lefty + drawsquare->parts.righty)/2 - strheight/2,
443 str, OPAQUE);
444 }
445
446 void
sdlwin_draw_spot(display_t * display,map_t * map,player_t * me,screen_t * screen,tiles_t * tiles,int screen_moved,int mapx,int mapy,int x,int y)447 sdlwin_draw_spot(display_t *display,
448 map_t *map, player_t *me, screen_t *screen, tiles_t *tiles,
449 int screen_moved, int mapx, int mapy, int x, int y)
450 {
451 square_t drawsquare;
452 mapobj_t mapobj;
453 surrounding_t surrounding;
454 heightsquare_t heightsquare;
455 int specials;
456 int owner = -1;
457 int zoom = screen_getzoom(screen);
458 int screen_dirview = screen_getdirview(screen);
459 int tilesizex;
460 int tilesizey;
461 int tileheight;
462 int sx;
463 int sy;
464 int i;
465 int j;
466 int topx;
467 int topy;
468 int xoffset;
469
470 screen_tilesizes(screen, &tilesizex, &tilesizey, &tileheight);
471
472 /*
473 * Get info on this spot
474 */
475 mapobj = map_get_info(map, mapx, mapy,
476 screen_dirview, &surrounding, &heightsquare,
477 &specials, me, &owner);
478
479 /*
480 * If tile is bigger than 1x1 do the right thing
481 */
482 tiles_getsize(tiles, mapobj, &sx, &sy);
483
484 topx = mapx;
485 topy = mapy;
486 map_find_tiletop(map, &topx, &topy);
487
488 switch(screen_dirview)
489 {
490 case 0:
491 if ((mapx != topx+sx-1) ||
492 (mapy != topy+sy-1)) {
493 return;
494 }
495 break;
496 case 1:
497 if ((mapx != topx+sx-1) ||
498 (mapy != topy)) {
499 return;
500 }
501 break;
502 case 2:
503 if ((mapx != topx) ||
504 (mapy != topy)) {
505 return;
506 }
507 break;
508 case 3:
509 if ((mapx != topx) ||
510 (mapy != topy+sy-1)) {
511 return;
512 }
513 break;
514 }
515
516 /*
517 * Figure out where we're drawing
518 */
519 xoffset = (sy - sx)*tilesizex;
520 drawsquare.parts.topx = x + xoffset + tilesizex/2;
521 drawsquare.parts.rightx = x + xoffset + tilesizex*(1+sx)/2;
522 drawsquare.parts.leftx = x + xoffset - tilesizex*(sy-1)/2;
523 drawsquare.parts.botx = x + xoffset + tilesizex*(1+sx-sy)/2;
524
525 drawsquare.parts.topy = y + 0 - heightsquare.dir.topleft*tileheight;
526
527 drawsquare.parts.righty = y + tilesizey*sx/2 - heightsquare.dir.topright*tileheight;
528
529 drawsquare.parts.lefty = y + tilesizey*sy/2 - heightsquare.dir.botleft*tileheight;
530
531 drawsquare.parts.boty = y + tilesizey*(sx+sy)/2 - heightsquare.dir.botright*tileheight;
532
533 /*
534 * xxx
535 */
536 if (screen_moved) {
537 screen_viewarea_set(screen, mapx, mapy, &drawsquare);
538 }
539
540 /*
541 * If highlighted check if can really place that there
542 */
543 if (display->activity == MAPOBJ_ACTION_FLATTEN) {
544 if (specials & MAPSPECIAL_HILITE_INVALID) {
545 fillsquare(255, 0, 0, 255,
546 &drawsquare);
547 } else if ((specials) ||
548 (mapspot_is_in_list(display->height_change_list, mapx, mapy))) {
549 fillsquare(0, 0, 0, 255,
550 &drawsquare);
551 }
552
553 } else if (specials) {
554
555 if (specials & MAPSPECIAL_HILITE_INVALID) {
556 fillsquare(255, 0, 0, 255,
557 &drawsquare);
558 } else {
559 fillsquare(0, 0, 0, 255,
560 &drawsquare);
561 }
562 }
563
564 if ((display->grid) && (zoom < 3)) {
565 draw_grid_lines(display, &drawsquare, owner, map, mapx, mapy);
566 }
567
568 switch (display->view)
569 {
570 case GAMEVIEW_OWNERS:
571 ShowSolid_minus(sdlscreen,
572 ownercolors[owner][0],
573 ownercolors[owner][1],
574 ownercolors[owner][2],
575 &drawsquare, 1, specials);
576 break;
577 case GAMEVIEW_MINE:
578 if (owner == player_getnum(me)) {
579 show_tile(display, tiles, screen, mapobj, x, y, sx, sy,
580 &surrounding, &heightsquare, &drawsquare,
581 screen_dirview, zoom, specials);
582 } else {
583 ShowSolid_minus(sdlscreen,
584 170, 170, 170, &drawsquare, 1, specials);
585 }
586 break;
587 case GAMEVIEW_NORMAL:
588 show_tile(display, tiles, screen, mapobj, x, y, sx, sy,
589 &surrounding, &heightsquare, &drawsquare,
590 screen_dirview, zoom, specials);
591 break;
592 case GAMEVIEW_POLICE_COVER:
593 case GAMEVIEW_HOSPITAL_COVER:
594 case GAMEVIEW_FIRE_COVER:
595 if (map_item_gettype(mapobj) == display->viewtype) {
596 ShowSolid_minus(sdlscreen,
597 10, 10, 10, &drawsquare, 1, specials);
598 } else if (mapspot_within_range(display->objlist, mapx, mapy, map, tiles)) {
599 ShowSolid_minus(sdlscreen,
600 150, 150, 150, &drawsquare, 1, specials);
601 } else {
602 show_tile(display, tiles, screen, mapobj, x, y, sx, sy,
603 &surrounding, &heightsquare, &drawsquare,
604 screen_dirview, zoom, specials);
605 }
606 break;
607 }
608
609
610 /*
611 * Draw land value if buying land
612 */
613 display_land_value(map, tiles, mapx, mapy, &drawsquare, zoom, owner, display->activity);
614
615 }
616
sdlwin_loadimage(char * filename,int request_width,int request_height,int * extra_height,void * rock)617 void *sdlwin_loadimage(char *filename,
618 int request_width, int request_height,
619 int *extra_height,
620 void *rock)
621 {
622 SDL_Surface *buf;
623 SDL_Surface *image;
624
625 buf = IMG_Load(filename);
626 if (!buf) {
627 printf(_("Error loading %s\n"), filename);
628 return NULL;
629 }
630
631 if (request_width != buf->w) {
632 image = resize_image(buf, request_width);
633 SDL_FreeSurface(buf);
634 } else {
635 image = buf;
636 }
637
638 *extra_height = image->h - request_height;
639
640 /*
641 image = SDL_DisplayFormat(image);
642 */
643
644 /* Set colorkey for non-opaque tiles */
645 if (strstr(filename, "png")) {
646 /*
647 SDL_SetColorKey(image,
648 SDL_SRCCOLORKEY|SDL_RLEACCEL,
649 SDL_MapRGBA(image->format, 0, 0, 0, 0));
650 */
651 } else {
652 SDL_SetColorKey(image,
653 SDL_SRCCOLORKEY|SDL_RLEACCEL,
654 SDL_MapRGBA(image->format, 255, 255, 255, 255));
655 }
656
657 return image;
658 }
659
660