1
char *rcsid_gtk_sdl_c =
2
"$Id: sdl.c,v 1.4 2005/07/16 17:23:57 akirschbaum Exp $";
5
Crossfire client, a client program for the crossfire program.
7
Copyright (C) 2005 Mark Wedel & Crossfire Development Team
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
The author can be reached via e-mail to crossfire@metalforge.org
30
#include <client-types.h>
32
#include <SDL_image.h>
34
/* Pick up the gtk headers we need */
37
#include <gdk/gdkkeysyms.h>
42
#include "gtk2proto.h"
44
/* Actual SDL surface the game view is painted on */
45
SDL_Surface* mapsurface;
46
static SDL_Surface* lightmap;
47
static SDL_Surface* fogmap;
48
static char *redrawbitmap;
50
extern int time_map_redraw;
51
extern uint8 map_did_scroll, map_updated;
54
/* Move some of the SDL code to this file here. This makes it easier to share
55
* between the gnome and gtk client. It also reduces the length of both the gx11.c
56
* and gnome.c file. It also is more readable, as not as many #ifdef SDL.. #endif
57
* constructs are needed.
58
* Note that there may still be some SDL code in gx11.c - some areas are embedded
59
* so much that it is not easy to remove.
62
/* these should generally be included by the file including this file. */
64
#include <SDL_image.h>
67
static void do_SDL_error( char* SDL_function, char* file, int line)
69
LOG(LOG_CRITICAL,SDL_function,"SDL error in file %s line %d\n%s",
70
file, line, SDL_GetError());
76
* Set the pixel at (x, y) to the given value
77
* NOTE: The surface must be locked before calling this!
78
* This function is directly grabbed from the SDL docs.
79
* Note this is not currently used, but is useful enough
80
* that it should be included.
82
static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
84
int bpp = surface->format->BytesPerPixel;
85
/* Here p is the address to the pixel we want to set */
86
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
98
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
99
p[0] = (pixel >> 16) & 0xff;
100
p[1] = (pixel >> 8) & 0xff;
104
p[1] = (pixel >> 8) & 0xff;
105
p[2] = (pixel >> 16) & 0xff;
110
*(Uint32 *)p = pixel;
115
static void overlay_grid( int re_init, int ax, int ay)
118
static SDL_Surface* grid_overlay;
120
static int first_pass;
126
SDL_PixelFormat* fmt;
128
/* Need to convert back to screen coordinates */
135
SDL_FreeSurface( grid_overlay);
141
if( grid_overlay == NULL)
143
grid_overlay= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA,
144
use_config[CONFIG_MAPWIDTH]*map_image_size,
145
use_config[CONFIG_MAPHEIGHT]*map_image_size,
146
mapsurface->format->BitsPerPixel,
147
mapsurface->format->Rmask,
148
mapsurface->format->Gmask,
149
mapsurface->format->Bmask,
150
mapsurface->format->Amask);
151
if( grid_overlay == NULL)
152
do_SDL_error( "CreateRGBSurface", __FILE__, __LINE__);
154
grid_overlay= SDL_DisplayFormatAlpha( grid_overlay);
160
* If this is our first time drawing the grid, we need to build up the
166
/* Red pixels around the edge and along image borders
167
* fully transparent pixels everywhere else
170
fmt= grid_overlay->format;
171
for( x= 0; x < map_image_size*use_config[CONFIG_MAPWIDTH]; x++)
173
for( y= 0; y < map_image_size*use_config[CONFIG_MAPHEIGHT]; y++)
175
/* FIXME: Only works for 32 bit displays right now */
176
pixel= (Uint32*)grid_overlay->pixels+y*grid_overlay->pitch/4+x;
178
if( x == 0 || y == 0 ||
179
((x % map_image_size) == 0) || ((y % map_image_size) == 0 ) ||
180
y == use_config[CONFIG_MAPHEIGHT]*map_image_size-1 || x == use_config[CONFIG_MAPWIDTH]*map_image_size -1 )
182
*pixel= SDL_MapRGBA( fmt, 255, 0, 0, SDL_ALPHA_OPAQUE);
186
*pixel= SDL_MapRGBA( fmt, 0, 0, 0, SDL_ALPHA_TRANSPARENT);
193
* If this is our first pass then we need to overlay the entire grid
194
* now. Otherwise we just update the tile we are on
198
dst.w= map_image_size*use_config[CONFIG_MAPWIDTH];
199
dst.h= map_image_size*use_config[CONFIG_MAPHEIGHT];
200
SDL_BlitSurface( grid_overlay, NULL, mapsurface, &dst);
204
dst.x= ax* map_image_size;
205
dst.y= ay* map_image_size;
206
dst.w= map_image_size;
207
dst.h= map_image_size;
208
/* One to one pixel mapping of grid and mapsurface so we
209
* can share the SDL_Rect
211
SDL_BlitSurface( grid_overlay, &dst, mapsurface, &dst);
218
* Takes two args, the first is the GtkWindow to draw on, this should always
219
* be 'drawingarea'. The second is a boolean, if 0 then the whole
220
* SDL system in initialized or reinited if already run once before,
221
* if non zero then only the lightmap is rebuilt, if we switch between
222
* per-pixel or per-tile lighting
224
void init_SDL( GtkWidget* sdl_window, int just_lightmap)
227
char SDL_windowhack[32];
229
if( just_lightmap == 0) {
230
g_assert( sdl_window != NULL);
231
if( SDL_WasInit( SDL_INIT_VIDEO) != 0) {
233
SDL_FreeSurface( lightmap);
235
SDL_FreeSurface( mapsurface);
240
* SDL hack to tell SDL which xwindow to paint onto
242
sprintf( SDL_windowhack, "SDL_WINDOWID=%ld",
243
GDK_WINDOW_XWINDOW(sdl_window->window) );
244
putenv( SDL_windowhack);
246
if( SDL_Init( SDL_INIT_VIDEO) < 0)
248
LOG(LOG_CRITICAL,"gtk::init_SDL", "Could not initialize SDL: %s", SDL_GetError());
252
mapsurface= SDL_SetVideoMode( map_image_size*use_config[CONFIG_MAPWIDTH], map_image_size*use_config[CONFIG_MAPHEIGHT], 0,
253
SDL_HWSURFACE|SDL_DOUBLEBUF);
255
if( mapsurface == NULL)
257
do_SDL_error( "SetVideoMode", __FILE__, __LINE__);
261
SDL_FreeSurface( fogmap);
263
fogmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
265
mapsurface->format->BitsPerPixel,
266
mapsurface->format->Rmask,
267
mapsurface->format->Gmask,
268
mapsurface->format->Bmask,
269
mapsurface->format->Amask);
273
do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
277
* This is a persurface alpha value, not an alpha channel value.
278
* So this surface doesn't actually need a full alpha channel
280
if( SDL_SetAlpha( fogmap, SDL_SRCALPHA|SDL_RLEACCEL, 128) < 0)
282
do_SDL_error( "SDL_SetAlpha", __FILE__, __LINE__);
286
if( just_lightmap != 0 && lightmap)
287
SDL_FreeSurface( lightmap);
289
lightmap= SDL_CreateRGBSurface( SDL_HWSURFACE|SDL_SRCALPHA, map_image_size,
291
mapsurface->format->BitsPerPixel,
292
mapsurface->format->Rmask,
293
mapsurface->format->Gmask,
294
mapsurface->format->Bmask,
295
mapsurface->format->Amask);
296
if( lightmap == NULL)
298
do_SDL_error( "SDL_CreateRGBSurface", __FILE__, __LINE__);
301
if(use_config[CONFIG_LIGHTING] != CFG_LT_TILE)
303
/* Convert surface to have a full alpha channel if we are doing
304
* per-pixel lighting */
305
lightmap= SDL_DisplayFormatAlpha( lightmap);
306
if( lightmap == NULL)
308
do_SDL_error( "DisplayFormatAlpha", __FILE__, __LINE__);
312
if(use_config[CONFIG_SHOWGRID] == TRUE)
314
overlay_grid( TRUE, 0, 0);
316
/* We make this a bit bigger than the actual map - thus, there
317
* is a 1 space pad in all directions. This enables us
318
* to store a value in that area without having to do checks to
319
* see if we are at the edge of the map - doing a store vs 4
320
* checks is going to be much faster.
322
redrawbitmap = malloc(sizeof(char) * (MAP_MAX_SIZE +2)* (MAP_MAX_SIZE+2));
326
/* Draw a alpha square on lightmap. Topleft corner is at startx,starty.
327
* values for topleft, topright, bottomleft,bottomright corners are knowns
328
* This use bilinear interpolation for other points. Width and heights are given
329
* for surrouding known values square. Interpolation is done in a small square whose
330
* coordinates are given by start{x|y} and end{x|y}
331
* dest{x|y} is top-left corner in destination map.
334
* Note - profile shows this is a very costly function - of a small run,
335
* 77% of the time of the cpu time for the client was in this function.
338
void drawquarterlightmap_sdl(int tl, int tr, int bl, int br, /*colors*/
339
int width, int height, /*color square size*/
340
int startx, int starty, int endx, int endy, /*interpolation region*/
341
int destx, int desty){ /*where in lightmap to save result*/
344
for (x=startx;x<endx;x++){
345
top= ((x*(tr-tl))/ width)+tl; /*linear interpolation for top color*/
346
bottom= ((x*(br-bl))/ width)+bl; /*linear interpolation for bottom color*/
347
for (y=starty;y<endy;y++){
348
val=((y*(bottom-top))/height)+top; /*linear interpolation between top and bottom*/
353
//printf("writing pel at %d,%d\n",destx+x,desty+y);
354
putpixel(lightmap, destx+x-startx, desty+y-starty,
355
SDL_MapRGBA(lightmap->format, 0, 0, 0, val));
360
/* Do the lighting on a per pixel basis.
361
* x and y are coordinates on the drawable map surfaces (but in terms of
362
* spaces, not pixels). mx and my are indexes into the
363
* the_map.cells[][] array.
364
* All the below goes out and figures lighting for each pixel on
365
* the space, and creates a surface (with alpha) that is then put on
366
* top of the exiting map space.
368
* TODO: I think it is possible to greatly speed this up by using
369
* pre-generated darkness masks. Doing all the possibilities
370
* would be 3125 images (5 positions, each with 5 values, 5^5),
371
* Doing it based on quadrants would only reduce that to 1024.
372
* But I _think_ it may be possible to do this with just 64 images
373
* (2^5 + one 90 degree rotation of the same) based on quadrants.
374
* ie, do a 16x16 image with the 5 gradiants (0,64,128,255 at the
375
* left, and each of those values at the right). Then do the same
376
* idea for top and bottom. For any single quadrant, you would
377
* then merge thse two values (which can be done with a fast blit),
378
* corresponding to the right values, and you do the same thing for
379
* the other four quadrants. Note this only works so long as
380
* 4 lighting values are used - if more are added, this quickly
381
* breaks. Also, if lighting colored effects are desired,
382
* this also doesn't work very well.
384
* For now, I've just kept the old logic. MSW 2001-10-09
387
/* See note below about ALPHA_FUDGE - used to adjust lighting effects some */
389
#define ALPHA_FUDGE(x) (2*(x) / 3)
390
#define GENDARK(x,y) ( (((x)&(y) & 1) == 1)?255:0 )
391
void do_sdl_per_pixel_lighting(int x, int y, int mx, int my)
394
int dark0, dark1, dark2, dark3, dark4;
397
/* I use dark0 -> dark4 in the order to keep it similar to
400
dark0 = the_map.cells[mx][my].darkness;
402
if (y-1 < 0 || !the_map.cells[mx][my-1].have_darkness) dark1 = dark0;
403
else dark1 = the_map.cells[mx][my-1].darkness;
405
if (x+1 >= use_config[CONFIG_MAPWIDTH] || !the_map.cells[mx+1][my].have_darkness) dark2 = dark0;
406
else dark2 = the_map.cells[mx+1][my].darkness;
408
if (y+1 >= use_config[CONFIG_MAPHEIGHT] || !the_map.cells[mx][my+1].have_darkness) dark3 = dark0;
409
else dark3 = the_map.cells[mx][my+1].darkness;
411
if (x-1 < 0 || !the_map.cells[mx-1][my].have_darkness) dark4 = dark0;
412
else dark4 = the_map.cells[mx-1][my].darkness;
414
/* If they are all the same, processing is easy
416
* Note, the best lightining algorithm also uses diagonals
417
* so we should check the diagonals are same too
418
* We don't check for now, simply do all raw computation on best mode
421
if (dark0 == dark1 && dark0 == dark2 && dark0 == dark3 && dark0 == dark4 && (use_config[CONFIG_LIGHTING] != CFG_LT_PIXEL_BEST)) {
422
dst.x = x * map_image_size;
423
dst.y = y * map_image_size;
424
dst.w = map_image_size;
425
dst.h = map_image_size;
428
SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
429
} else if (the_map.cells[mx][my].darkness != 0) {
430
SDL_FillRect(lightmap,NULL, SDL_MapRGBA(lightmap->format, 0, 0, 0, the_map.cells[mx][my].darkness));
431
SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
437
if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ) {
438
/* This almost works as well as the per pixel code below, but does have some various
439
* artifacts in the drawing. It uses the same logic as the per pixel code below,
440
* bit since SDL does the blit, the alpha handling ends up being different
441
* (I think it ends up being additive). This results in the darkness being
442
* darker, but you also don't get the smooth effects. If you divide all the values
443
* by 2 (change ALPHA_FUDGE), the blending is smooth, but now the things are not dark
444
* enough, so the blending aganst solid black spaces does not look good.
445
* The reason this code is of interest is that on my system, it is about 50%
446
* faster than the code below (25 ms to darkness the church in the starting
447
* town vs 50 ms for the code further down)
448
* Setting ALPHA_FUDGE to 2/3 seems to reduce the artifacts described above
449
* to fairly minimal levels, while still keeping things dark enough.
455
if (dark1 == dark0) {
456
/* If we don't have usable darkness at the top, then this entire region
457
* should be the same value. Likewise, if the top value and center value
458
* are the same, we can do the entire region.
462
dst.w = map_image_size;
463
dst.h = map_image_half_size;
464
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
466
else for (i=0; i<map_image_half_size; i++) {
467
/* Need to do it line by line */
471
dst.w = map_image_size;
473
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
474
ALPHA_FUDGE((map_image_half_size - i) * dark1 + i * dark0)/map_image_half_size));
477
/* All the following blocks are basically the same as above, just different
480
if (dark3 == dark0) {
482
dst.y=map_image_half_size;
483
dst.w = map_image_size;
484
dst.h = map_image_half_size;
485
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
487
else for (i=map_image_half_size; i<map_image_size; i++) {
488
/* Need to do it line by line */
492
dst.w = map_image_size;
494
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
495
ALPHA_FUDGE(dark0*(map_image_size-i) + dark3*(i-map_image_half_size)) / map_image_half_size));
497
/* Blit this to the screen now. Otherwise, we need to look at the alpha values
501
dst.x= x * map_image_size;
502
dst.y= y * map_image_size;
503
SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
505
if (dark4 == dark0) {
508
dst.w = map_image_half_size;
509
dst.h = map_image_size;
510
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
512
else for (i=0; i<map_image_half_size; i++) {
513
/* Need to do it line by line */
517
dst.h = map_image_size;
518
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
519
ALPHA_FUDGE(dark4*(map_image_half_size-i) + dark0*i) / map_image_half_size));
521
if (dark2 == dark0) {
522
dst.x=map_image_half_size;
524
dst.w = map_image_half_size;
525
dst.h = map_image_size;
526
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0, ALPHA_FUDGE(dark0)));
528
else for (i=map_image_half_size; i<map_image_size; i++) {
529
/* Need to do it line by line */
534
dst.h = map_image_size;
535
SDL_FillRect(lightmap, &dst, SDL_MapRGBA(lightmap->format, 0, 0, 0,
536
ALPHA_FUDGE(dark0*(map_image_size-i) + dark2*(i-map_image_half_size)) / map_image_half_size));
538
dst.x= x * map_image_size;
539
dst.y= y * map_image_size;
540
SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
541
} else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST ) {
544
static int *darkx=NULL, *darky=NULL,darkx_allocated=0;
546
/* Generated stored for the darkx[] array. Do it dynamically, but
547
* only allocate if the size needs to be expanded to keep performance
548
* better. darkx could be null in the initial case, but realloc should
549
* just treat that as a malloc (so according to the man page)
551
if (map_image_size > darkx_allocated) {
552
darkx = realloc(darkx, map_image_size * sizeof(int));
553
darky = realloc(darky, map_image_size * sizeof(int));
554
darkx_allocated = map_image_size;
557
for( dx= 0; dx < map_image_half_size; dx++)
558
darkx[dx]= (dark4*(map_image_half_size-dx) + dark0*dx) / map_image_half_size;
559
for( dx= map_image_half_size; dx < map_image_size; dx++)
560
darkx[dx] = (dark0*(map_image_size-dx) + dark2*(dx-map_image_half_size)) / map_image_half_size;
562
for( dy= 0; dy < map_image_half_size; dy++)
563
darky[dy]= (dark1*(map_image_half_size-dy) + dark0*dy) / map_image_half_size;
564
for( dy= map_image_half_size; dy < map_image_size; dy++)
565
darky[dy] = (dark0*(map_image_size-dy) + dark3*(dy-map_image_half_size)) / map_image_half_size;
567
SDL_LockSurface( lightmap);
569
for (dx=0; dx<map_image_size; dx++)
570
for (dy=0; dy<map_image_size; dy++)
571
putpixel(lightmap, dx, dy, SDL_MapRGBA(lightmap->format, 0, 0, 0,(darkx[dx] + darky[dy])/2));
573
/*we need additionnal surrounding infos*/
574
int dark5, dark6, dark7, dark8;
575
if ( (y-1 < 0) || (x+1 >= use_config[CONFIG_MAPWIDTH])
576
|| !the_map.cells[mx+1][my-1].have_darkness) dark5 = (dark1+dark2)>>1; /*(fast div 2)*/
577
else dark5 = the_map.cells[mx+1][my-1].darkness;
579
if ( (x+1 >= use_config[CONFIG_MAPWIDTH])
580
|| (y+1 >= use_config[CONFIG_MAPHEIGHT])
581
|| !the_map.cells[mx+1][my+1].have_darkness) dark6 = (dark2+dark3)>>1;
582
else dark6 = the_map.cells[mx+1][my+1].darkness;
584
if ( (y+1 >= use_config[CONFIG_MAPHEIGHT]) || (x-1 < 0)
585
|| !the_map.cells[mx-1][my+1].have_darkness) dark7 = (dark3+dark4)>>1;
586
else dark7 = the_map.cells[mx-1][my+1].darkness;
588
if ( (x-1 < 0) || (y-1 < 0)
589
|| !the_map.cells[mx-1][my-1].have_darkness) dark8 = (dark4+dark1)>>1;
590
else dark8 = the_map.cells[mx-1][my-1].darkness;
591
/*upper left lightmap quarter*/
592
drawquarterlightmap_sdl(dark8, dark1, dark4, dark0, /*colors*/
593
map_image_size, map_image_size, /*color square size*/
594
map_image_half_size, map_image_half_size, map_image_size, map_image_size, /*interpolation region*/
595
0, 0); /*where in lightmap to save result*/
596
/*upper right lightmap quarter*/
597
drawquarterlightmap_sdl(dark1, dark5, dark0, dark2, /*colors*/
598
map_image_size, map_image_size, /*color square size*/
599
0, map_image_half_size, map_image_half_size, map_image_size, /*interpolation region*/
600
map_image_half_size, 0); /*where in lightmap to save result*/
601
/*bottom left lightmap quarter*/
602
drawquarterlightmap_sdl(dark4, dark0, dark7, dark3, /*colors*/
603
map_image_size, map_image_size, /*color square size*/
604
map_image_half_size, 0, map_image_size, map_image_half_size, /*interpolation region*/
605
0, map_image_half_size); /*where in lightmap to save result*/
606
/*bottom right lightmap quarter*/
607
drawquarterlightmap_sdl(dark0, dark2, dark3, dark6, /*colors*/
608
map_image_size, map_image_size, /*color square size*/
609
0, 0, map_image_half_size, map_image_half_size, /*interpolation region*/
610
map_image_half_size, map_image_half_size); /*where in lightmap to save result*/
612
dst.w= map_image_size;
613
dst.h= map_image_size;
614
dst.x= x * map_image_size;
615
dst.y= y * map_image_size;
616
SDL_UnlockSurface(lightmap);
617
SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
620
/* Draw anything in adjacent squares that could smooth on given square
621
* mx,my square to smooth on. you should not call this function to
622
* smooth on a 'completly black' square. (simply for visual result)
623
* layer layer to examine (we smooth only one layer at a time)
624
* dst place on the mapwindow to draw
626
static void drawsmooth_sdl (int mx,int my,int layer,SDL_Rect dst){
627
static int dx[8]={0,1,1,1,0,-1,-1,-1};
628
static int dy[8]={-1,-1,0,1,1,1,0,-1};
629
static int bweights[8]={2,0,4,0,8,0,1,0};
630
static int cweights[8]={0,2,0,4,0,8,0,1};
631
static int bc_exclude[8]={
632
1+2,/*north exclude northwest (bit0) and northeast(bit1)*/
634
2+4,/*east exclude northeast and southeast*/
641
int partdone[8]={0,0,0,0,0,0,0,0};
644
int i,lowest,weight,weightC;
651
if ( (the_map.cells[mx][my].heads[0].face==0)
652
|| !CAN_SMOOTH(the_map.cells[mx][my],layer) )
657
if ( (emx<0) || (emy<0) || (the_map.x<=emx) || (the_map.y<=emy)){
659
sfaces[i]=0; /*black picture*/
661
if (the_map.cells[emx][emy].smooth[layer]<=the_map.cells[mx][my].smooth[layer]){
663
sfaces[i]=0; /*black picture*/
665
slevels[i]=the_map.cells[emx][emy].smooth[layer];
666
sfaces[i]=pixmaps[the_map.cells[emx][emy].heads[layer].face]->smooth_face;
670
/* ok, now we have a list of smoothlevel higher than current square.
671
* there are at most 8 different levels. so... let's check 8 times
672
* for the lowest one (we draw from botto to top!).
678
if ( (slevels[i]>0) && (!partdone[i]) &&
679
((lowest<0) || (slevels[i]<slevels[lowest]))
684
break; /*no more smooth to do on this square*/
685
/*printf ("hey, must smooth something...%d\n",sfaces[lowest]);*/
686
/*here we know 'what' to smooth*/
687
/* we need to calculate the weight
688
* for border and weight for corners.
690
* the corresponding squares
692
/*first, the border, which may exclude some corners*/
694
weightC=15; /*works in backward. remove where there is nothing*/
697
for (i=0;i<8;i++){ /*check all nearby squares*/
698
if ( (slevels[i]==slevels[lowest]) &&
699
(sfaces[i]==sfaces[lowest])){
701
weight=weight+bweights[i];
702
weightC&=~bc_exclude[i];
704
/*must rmove the weight of a corner if not in smoothing*/
705
weightC&=~cweights[i];
709
/*We can't do this before since we need the partdone to be adjusted*/
710
if (sfaces[lowest]<=0)
711
continue; /*Can't smooth black*/
712
smoothface=sfaces[lowest];
714
continue; /*picture for smoothing not yet available*/
716
/* now, it's quite easy. We must draw using a 32x32 part of
717
* the picture smoothface.
718
* This part is located using the 2 weights calculated:
719
* (32*weight,0) and (32*weightC,32)
721
if ( (!pixmaps[smoothface]->map_image) ||
722
(pixmaps[smoothface] == pixmaps[0]))
723
continue; /*don't have the picture associated*/
725
src.x=map_image_size*weight;
727
if (the_map.cells[mx][my].cleared) {
728
if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
729
&src, mapsurface, &dst))
730
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
732
if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
733
&src, mapsurface, &dst))
734
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
738
src.x=map_image_size*weightC;
739
src.y=map_image_size;
740
if (the_map.cells[mx][my].cleared) {
741
if (SDL_BlitSurface(pixmaps[smoothface]->fog_image,
742
&src, mapsurface, &dst))
743
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
745
if (SDL_BlitSurface(pixmaps[smoothface]->map_image,
746
&src, mapsurface, &dst))
747
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
752
}/*while there's some smooth to do*/
755
/* This function tells if a specific square need to be redrawn
756
* Reason for redrawing can be content change, smoothing change or
757
* surrounding lightning change. Conditions depend on type of
758
* lightning code used.
761
* Profile shows this is a big CPU user (50% in CFG_LT_PIXEL mode,
762
* so I rewrote it to be much more efficient in the update_redrawbitmap()
763
* function below. Logic is a bit different, so not a straigtforward
767
int sdl_square_need_redraw(int mx, int my){
768
#define SDL_LIGHT_CHANGED(_x_,_y_) ( ( ( (_x_)<0) || ( (_y_)<0) || ( (_x_)>=the_map.x) || ( (_y_)>=the_map.y) )?0: the_map.cells[_x_][_y_].need_update )
770
if ( (the_map.cells[mx][my].need_update) || (the_map.cells[mx][my].need_resmooth && use_config[CONFIG_SMOOTH]))
773
if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL){
774
/*The fast per pixel uses 4 additionnal datas which may have changed:*/
775
/*we suppose need_redraw -> lightr may have change. in future maybe we could add a need_relight toggle*/
776
if (SDL_LIGHT_CHANGED(mx-1,my) ||
777
SDL_LIGHT_CHANGED(mx,my-1) ||
778
SDL_LIGHT_CHANGED(mx+1,my) ||
779
SDL_LIGHT_CHANGED(mx,my+1))
782
if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST){
783
if (SDL_LIGHT_CHANGED(mx-1,my) ||
784
SDL_LIGHT_CHANGED(mx,my-1) ||
785
SDL_LIGHT_CHANGED(mx+1,my) ||
786
SDL_LIGHT_CHANGED(mx,my+1) ||
787
SDL_LIGHT_CHANGED(mx-1,my+1) ||
788
SDL_LIGHT_CHANGED(mx-1,my-1) ||
789
SDL_LIGHT_CHANGED(mx+1,my-1) ||
790
SDL_LIGHT_CHANGED(mx+1,my+1) )
793
return 0; /*no need to redraw :)*/
796
/* update_redrawbitmap() - replacment of sdl_square_need_redraw logic.
797
* use of sdl_square_need_redraw is relatively inefficient becuase
798
* it is called for every space (hence function call overhead),
799
* but also has 4 checks to make sure the neighbor space is within valid
800
* range, and if non tile mode, performs that check at least 4 times
802
* This is much more efficient, because our redrawbitmap array is
803
* large enough we don't need those checks - we know we are always safe
804
* to go one outside the bounds (hence, the +1 in the coordinate
807
static void update_redrawbitmap()
811
memset(redrawbitmap, 0, (use_config[CONFIG_MAPWIDTH]+2) * (use_config[CONFIG_MAPHEIGHT]+2));
813
for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
814
for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
818
/* Basically, we need to check the conditions that require this space.
819
* to be redrawn. We store this in redrawbitmap, because storing
820
* in the_map[][].need_update would cause a cascade effect, of space
821
* 1,0 need an update, so we thing 2,0 needs an update due to smoothing/
822
* like, which causes 3,0 to be updated, etc. Having our own
823
* memory area allows the memset above, which is an optimized routine
826
if (the_map.cells[mx][my].need_update) {
827
redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
828
/* If this space has changed, and using non tile lighting,
829
* we need to update the neighbor spaces. Ideally, we'd
830
* have a flag just to denote lighting changes, since
831
* that is handled on a different surface anyways.
833
if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL ||
834
use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
835
/* This is where having redrawbitmap bigger pays off - don't have
836
* to check to see if values are within redrawbitmap is within bounds
838
redrawbitmap[x + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
839
redrawbitmap[x + 2 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
840
redrawbitmap[x + 1 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
841
redrawbitmap[x + 1 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
843
/* In best mode, have to update diaganols in addition*/
844
if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
845
redrawbitmap[x + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
846
redrawbitmap[x + 2 + (y) * use_config[CONFIG_MAPWIDTH]] = 1;
847
redrawbitmap[x + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
848
redrawbitmap[x + 2 + (y+2) * use_config[CONFIG_MAPWIDTH]] = 1;
851
else if (the_map.cells[mx][my].need_resmooth) {
852
redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] = 1;
858
/* This generates a map in SDL mode.
860
* I had to totally change the logic on how we do this in SDL mode -
861
* to support variable sized images, the old method of generating each
862
* space does not work, as one space may spill over to the other.
863
* Instead, we first blit the bottom layer, then the layer above
864
* that, and so on. This results in the map being drawn a bit
865
* more correctly. In fact, that logic actually isn't needed, as
866
* with the new map commands, we know the offset and size of the
869
* The logic here only redraws spaces that change. The logic in the
870
* common/commands.c files the odd layers with links for 'big images'.
871
* for objects on these layers, we look at the size_x and size_y values
872
* to determine the offset from which we should be blitting.
874
* Old notes, but left in:
875
* The performance here is very good in most cases - about 30 ms (on my system)
876
* is used just for my flip at the bottom of the function, drawing only what
877
* is needed generally saves a lot of time (<15 ms in most cases) compared to the
878
* 80-120 ms usually needed on a 15x15 map.
881
void sdl_gen_map(int redraw) {
882
int mx,my, layer,x,y, num_spaces=0, num_drawn=0;
884
struct timeval tv1, tv2,tv3;
885
long elapsed1, elapsed2;
888
gettimeofday(&tv1, NULL);
890
if (map_did_scroll) {
893
/* If nothing changed, don't need to do all the code below */
894
if (!redraw && !map_updated) return;
897
update_redrawbitmap();
899
for( x= 0; x<use_config[CONFIG_MAPWIDTH]; x++) {
900
for(y = 0; y<use_config[CONFIG_MAPHEIGHT]; y++) {
902
/* mx,my represent the spaces on the 'virtual' map (ie, the_map structure).
903
* x and y (from the for loop) represent the visable screen.
908
/* This will be updated in the for loop above for
909
* whatever conditions that need this space to be redrawn
911
if (!redrawbitmap[x + 1 + (y+1) * use_config[CONFIG_MAPWIDTH]] && !redraw)
916
/* First, we need to black out this space. */
917
dst.x = x * map_image_size; dst.y = y* map_image_size;
918
dst.w = map_image_size;
919
dst.h = map_image_size;
920
SDL_FillRect(mapsurface, &dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
922
/* now draw the different layers. Only draw if using fog of war or the
925
if (use_config[CONFIG_FOGWAR] || !the_map.cells[mx][my].cleared)
926
for (layer=0; layer<MAXLAYERS; layer++) {
928
/* draw the tail first - this seems to get better results */
929
if (the_map.cells[mx][my].tails[layer].face &&
930
pixmaps[the_map.cells[mx][my].tails[layer].face]->map_image) {
932
/* add one to the size values to take into account the actual width of the space */
933
src.x = pixmaps[the_map.cells[mx][my].tails[layer].face]->map_width -
934
(the_map.cells[mx][my].tails[layer].size_x + 1) * map_image_size;
935
src.y = pixmaps[the_map.cells[mx][my].tails[layer].face]->map_height -
936
(the_map.cells[mx][my].tails[layer].size_y + 1) * map_image_size;
937
src.w = map_image_size;
938
src.h = map_image_size;
939
dst.x = x * map_image_size;
940
dst.y = y * map_image_size;
941
if (the_map.cells[mx][my].cleared) {
942
if (SDL_BlitSurface(pixmaps[the_map.cells[mx][my].tails[layer].face]->fog_image,
943
&src, mapsurface, &dst))
944
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
946
if (SDL_BlitSurface(pixmaps[the_map.cells[mx][my].tails[layer].face]->map_image,
947
&src, mapsurface, &dst))
948
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
951
/* Draw the head now - logic is pretty much exactly the same
952
* as that for the tail, except we know that we this is at the lower right,
953
* so we don't need to adjust the origin as much.
955
if (the_map.cells[mx][my].heads[layer].face &&
956
pixmaps[the_map.cells[mx][my].heads[layer].face]->map_image) {
958
src.x = pixmaps[the_map.cells[mx][my].heads[layer].face]->map_width - map_image_size;
959
src.y = pixmaps[the_map.cells[mx][my].heads[layer].face]->map_height - map_image_size;
960
src.w = map_image_size;
961
src.h = map_image_size;
962
dst.x = x * map_image_size;
963
dst.y = y * map_image_size;
964
if (the_map.cells[mx][my].cleared) {
965
if (SDL_BlitSurface(pixmaps[the_map.cells[mx][my].heads[layer].face]->fog_image,
966
&src, mapsurface, &dst))
967
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
969
if (SDL_BlitSurface(pixmaps[the_map.cells[mx][my].heads[layer].face]->map_image,
970
&src, mapsurface, &dst))
971
do_SDL_error( "BlitSurface", __FILE__, __LINE__);
973
/*We have added either a head. Let's draw nearby squares coverts*/
974
if ( use_config[CONFIG_SMOOTH])
975
drawsmooth_sdl (mx,my,layer,dst);
977
/* Sometimes, it may happens we need to draw the smooth while there
978
* is nothing to draw at that layer (but there was something at lower
979
* layers). This is handled here. The else part is to take into account
980
* cases where the smooth as already been handled 2 code lines before
982
else if ( use_config[CONFIG_SMOOTH] &&
983
the_map.cells[mx][my].need_resmooth )
984
drawsmooth_sdl (mx,my,layer,dst);
985
} /* else for processing the layers */
987
/* Do final logic for this map space */
988
the_map.cells[mx][my].need_update=0;
990
if (use_config[CONFIG_LIGHTING] == CFG_LT_TILE) {
991
dst.x = x * map_image_size;
992
dst.y = y * map_image_size;
993
dst.w = map_image_size;
994
dst.h = map_image_size;
996
/* Note - Instead of using a lightmap, I just fillrect
997
* directly onto the map surface - I would think this should be
1000
if (the_map.cells[mx][my].darkness == 255) {
1001
SDL_FillRect(mapsurface,&dst, SDL_MapRGB(mapsurface->format, 0, 0, 0));
1002
} else if (the_map.cells[mx][my].darkness != 0) {
1003
SDL_SetAlpha(lightmap, SDL_SRCALPHA|SDL_RLEACCEL, the_map.cells[mx][my].darkness);
1004
SDL_BlitSurface(lightmap, NULL, mapsurface, &dst);
1006
} else if (use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL || use_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST) {
1007
do_sdl_per_pixel_lighting(x, y, mx, my);
1009
} /* For y spaces */
1010
} /* for x spaces */
1011
if (time_map_redraw)
1012
gettimeofday(&tv2, NULL);
1014
SDL_Flip(mapsurface);
1016
if (time_map_redraw) {
1017
gettimeofday(&tv3, NULL);
1018
elapsed1 = (tv2.tv_sec - tv1.tv_sec)*1000000 + (tv2.tv_usec - tv1.tv_usec);
1019
elapsed2 = (tv3.tv_sec - tv2.tv_sec)*1000000 + (tv3.tv_usec - tv2.tv_usec);
1021
/* I care about performance for 'long' updates, so put the check in to make
1022
* these a little more noticable */
1023
if ((elapsed1 + elapsed2)>10000)
1024
LOG(LOG_INFO,"gtk::sdl_gen_map","gen took %7ld, flip took %7ld, total = %7ld",
1025
elapsed1, elapsed2, elapsed1 + elapsed2);
1027
/*fprintf(stderr,"sdl_gen_map: %d/%d spaces drawn\n", num_drawn, num_spaces);*/
1028
} /* sdl_gen_map function */
1030
void sdl_mapscroll(int dx, int dy)
1035
/* Don't sdl_gen_map should take care of the redraw */
1037
/* a copy of what pngximage does except sdl specfic
1038
* mapsurface->pitch is the length of a scanline in bytes
1039
* including alignment padding
1041
SDL_LockSurface( mapsurface);
1043
int offset= mapsurface->pitch * (-dy*map_image_size);
1044
memmove( mapsurface->pixels + offset, mapsurface->pixels,
1045
mapsurface->pitch * (mapsurface->h + dy*map_image_size) );
1048
int offset= mapsurface->pitch * (dy*map_image_size);
1049
memmove( mapsurface->pixels, mapsurface->pixels + offset,
1050
mapsurface->pitch * (mapsurface->h - dy*map_image_size) );
1055
for( y= 0; y < mapsurface->h; y++) {
1057
char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1058
int offset= ( mapsurface->format->BytesPerPixel * map_image_size * -dx);
1059
memmove( start_of_row + offset, start_of_row,
1060
mapsurface->pitch - offset);
1063
char* start_of_row= mapsurface->pixels + mapsurface->pitch * y;
1064
int offset= ( mapsurface->format->BytesPerPixel * map_image_size * dx);
1065
memmove( start_of_row, start_of_row + offset,
1066
mapsurface->pitch - offset);
1070
SDL_UnlockSurface( mapsurface);