53929764e98b4c1de137fee7588d091cc672f603
[crow/jumpnbump.git] / sdl / gfx.c
1 /*
2  * gfx.c
3  * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
4  * 
5  * Copyright (C) 2001 Chuck Mason <cemason@users.sourceforge.net>
6  *
7  * Copyright (C) 2002 Florian Schulze <crow@icculus.org>
8  *
9  * Portions of this code are from the MPEG software simulation group
10  * idct implementation. This code will be replaced with a new
11  * implementation soon.
12  *
13  * This file is part of Jump'n'Bump.
14  *
15  * Jump'n'Bump is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * Jump'n'Bump is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29
30 #include "globals.h"
31
32 int screen_width=400;
33 int screen_height=256;
34 int screen_pitch=400;
35 int scale_up=0;
36 int bytes_per_pixel=1;
37 int dirty_block_shift=4;
38
39 static int current_pal[256];
40 static SDL_Surface *jnb_surface;
41 static int fullscreen = 0;
42 static int vinited = 0;
43 static void *screen_buffer[2];
44 static int drawing_enable = 0;
45 static void *background = NULL;
46 static int background_drawn;
47 static void *mask = NULL;
48 static int dirty_blocks[2][25*16*2];
49
50 void *get_vgaptr(int page, int x, int y)
51 {
52         assert(drawing_enable==1);
53
54         return (unsigned char *)screen_buffer[page] + (y*screen_pitch)+(x*bytes_per_pixel);
55 }
56
57
58 void set_scaling(int scale)
59 {
60         if (scale==1) {
61                 screen_width=800;
62                 screen_height=512;
63                 scale_up=1;
64                 bytes_per_pixel=2;
65                 dirty_block_shift=5;
66                 screen_pitch=screen_width*bytes_per_pixel;
67         } else {
68                 screen_width=400;
69                 screen_height=256;
70                 scale_up=0;
71                 bytes_per_pixel=1;
72                 dirty_block_shift=4;
73                 screen_pitch=screen_width*bytes_per_pixel;
74         }
75 }
76
77 void open_screen(void)
78 {
79         int lval = 0;
80         int bpp;
81         int flags;
82
83 #ifdef __APPLE__
84         lval = SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO);
85 #else
86         lval = SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_AUDIO);
87 #endif
88         if (lval < 0) {
89                 fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
90                 exit(EXIT_FAILURE);
91         }
92
93         if (scale_up)
94                 bpp = 16;
95         else
96                 bpp = 8;
97         flags = SDL_SWSURFACE;
98         if (fullscreen)
99                 flags |= SDL_FULLSCREEN;
100         jnb_surface = SDL_SetVideoMode(screen_width, screen_height, bpp, flags);
101
102         if (!jnb_surface) {
103                 fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
104                 exit(EXIT_FAILURE);
105         }
106
107         SDL_ShowCursor(0);
108
109         vinited = 1;
110
111         memset(current_pal, 0, sizeof(current_pal));
112         memset(dirty_blocks, 0, sizeof(dirty_blocks));
113
114         screen_buffer[0]=malloc(screen_width*screen_height*bytes_per_pixel);
115         screen_buffer[1]=malloc(screen_width*screen_height*bytes_per_pixel);
116
117 /*
118         dirty_blocks[0]=malloc(sizeof(int)*25*16+1000);
119         dirty_blocks[1]=malloc(sizeof(int)*25*16+1000);
120 */
121
122         return;
123 }
124
125
126 void fs_toggle()
127 {
128         if (!vinited) {
129                 fullscreen ^= 1;
130                 return;
131         }
132         if (SDL_WM_ToggleFullScreen(jnb_surface))
133                 fullscreen ^= 1;
134 }
135
136
137 void wait_vrt(int mix)
138 {
139         return;
140 }
141
142
143 void clear_page(int page, int color)
144 {
145         int i,j;
146
147         assert(drawing_enable==1);
148
149         for (i=0; i<(25*16); i++)
150                 dirty_blocks[page][i] = 1;
151
152         if (bytes_per_pixel==1) {
153                 unsigned char *buf = get_vgaptr(page, 0, 0);
154
155                 for (i=0; i<screen_height; i++)
156                         for (j=0; j<screen_width; j++)
157                                 *buf++ = color;
158         } else if (bytes_per_pixel==2) {
159                 unsigned short *buf = get_vgaptr(page, 0, 0);
160
161                 for (i=0; i<screen_height; i++)
162                         for (j=0; j<screen_width; j++)
163                                 *buf++ = color;
164         } else {
165                 unsigned int *buf = get_vgaptr(page, 0, 0);
166
167                 for (i=0; i<screen_height; i++)
168                         for (j=0; j<screen_width; j++)
169                                 *buf++ = color;
170         }
171 }
172
173
174 void clear_lines(int page, int y, int count, int color)
175 {
176         int i,j;
177
178         assert(drawing_enable==1);
179
180         if (scale_up) {
181                 count *= 2;
182                 y *= 2;
183         }
184
185         if (bytes_per_pixel==1) {
186                 for (i=0; i<count; i++) {
187                         if ((i+y)<screen_height) {
188                                 unsigned char *buf = get_vgaptr(page, 0, i+y);
189                                 for (j=0; j<screen_width; j++)
190                                         *buf++ = color;
191                         }
192                 }
193         } else if (bytes_per_pixel==2) {
194                 for (i=0; i<count; i++) {
195                         if ((i+y)<screen_height) {
196                                 unsigned short *buf = get_vgaptr(page, 0, i+y);
197                                 for (j=0; j<screen_width; j++)
198                                         *buf++ = color;
199                         }
200                 }
201         } else {
202                 for (i=0; i<count; i++) {
203                         if ((i+y)<screen_height) {
204                                 unsigned int *buf = get_vgaptr(page, 0, i+y);
205                                 for (j=0; j<screen_width; j++)
206                                         *buf++ = color;
207                         }
208                 }
209         }
210         count = ((y+count)>>dirty_block_shift) - (y>>dirty_block_shift) + 1;
211         y >>= dirty_block_shift;
212         for (i=0; i<count; i++)
213                 for (j=0; j<25; j++)
214                         dirty_blocks[page][(y+i)*25+j] = 1;
215 }
216
217
218 int get_color(int color, char pal[768])
219 {
220         assert(color<256);
221         assert(pal);
222         return SDL_MapRGB(jnb_surface->format, (Uint8)(pal[color*3+0]<<2), (Uint8)(pal[color*3+1]<<2), (Uint8)(pal[color*3+2]<<2));
223 }
224
225
226 int get_pixel(int page, int x, int y)
227 {
228         assert(drawing_enable==1);
229
230         if (scale_up) {
231                 x *= 2;
232                 y *= 2;
233         }
234
235         assert(x<screen_width);
236         assert(y<screen_height);
237
238         if (bytes_per_pixel==1)
239                 return *(unsigned char *)get_vgaptr(page, x, y);
240         else if (bytes_per_pixel==2)
241                 return *(unsigned short *)get_vgaptr(page, x, y);
242         else
243                 return *(unsigned int *)get_vgaptr(page, x, y);
244 }
245
246
247 void set_pixel(int page, int x, int y, int color)
248 {
249         assert(drawing_enable==1);
250
251         if (scale_up) {
252                 x *= 2;
253                 y *= 2;
254         }
255
256         assert(x<screen_width);
257         assert(y<screen_height);
258
259         dirty_blocks[page][(y>>dirty_block_shift)*25+(x>>dirty_block_shift)] = 1;
260
261         if (bytes_per_pixel==1)
262                 *(unsigned char *)get_vgaptr(page, x, y) = color;
263         else if (bytes_per_pixel==2)
264                 *(unsigned short *)get_vgaptr(page, x, y) = color;
265         else
266                 *(unsigned int *)get_vgaptr(page, x, y) = color;
267 }
268
269
270 static unsigned int colorMask = 0xF7DEF7DE;
271 static unsigned int lowPixelMask = 0x08210821;
272 static unsigned int qcolorMask = 0xE79CE79C;
273 static unsigned int qlowpixelMask = 0x18631863;
274 static unsigned int redblueMask = 0xF81F;
275 static unsigned int greenMask = 0x7E0;
276
277 int Init_2xSaI (unsigned int BitFormat)
278 {
279     if (BitFormat == 565)
280     {
281         colorMask = 0xF7DEF7DE;
282         lowPixelMask = 0x08210821;
283         qcolorMask = 0xE79CE79C;
284         qlowpixelMask = 0x18631863;
285         redblueMask = 0xF81F;
286         greenMask = 0x7E0;
287     }
288     else if (BitFormat == 555)
289     {
290         colorMask = 0x7BDE7BDE;
291         lowPixelMask = 0x04210421;
292         qcolorMask = 0x739C739C;
293         qlowpixelMask = 0x0C630C63;
294         redblueMask = 0x7C1F;
295         greenMask = 0x3E0;
296     }
297     else
298     {
299         return 0;
300     }
301
302 #ifdef MMX
303     Init_2xSaIMMX (BitFormat);
304 #endif
305
306     return 1;
307 }
308
309
310 void Scale2x (unsigned char *src, unsigned int src_pitch, int src_bytes_per_pixel,
311                  unsigned char *dst, unsigned int dst_pitch, int dst_bytes_per_pixel,
312                  int width, int height, int pal[256])
313 {
314 #define GET_COLOR(x) (pal[(x)])
315
316         int x,y;
317         unsigned char *src_line;
318         unsigned char *dst_line[2];
319
320         src_line = src;
321         dst_line[0] = dst;
322         dst_line[1] = dst + dst_pitch;
323         for (y=0; y<height; y++) {
324                 for (x=0; x<width; x++) {
325                         int color;
326
327                         if (src_bytes_per_pixel == 1) {
328                                 color = GET_COLOR(*(((unsigned char*)src_line) + x));
329                         } else if (src_bytes_per_pixel == 2) {
330                                 color = *(((unsigned short*)src_line) + x);
331                         } else {
332                                 color = *(((unsigned int*)src_line) + x);
333                         }
334
335                         if (dst_bytes_per_pixel == 2) {
336                                 *((unsigned long *) (&dst_line[0][x * 4])) = color | (color << 16);
337                                 *((unsigned long *) (&dst_line[1][x * 4])) = color | (color << 16);
338                         } else {
339                                 *((unsigned long *) (&dst_line[0][x * 8])) = color;
340                                 *((unsigned long *) (&dst_line[0][x * 8 + 4])) = color;
341                                 *((unsigned long *) (&dst_line[1][x * 8])) = color;
342                                 *((unsigned long *) (&dst_line[1][x * 8 + 4])) = color;
343                         }
344                 }
345
346                 src_line += src_pitch;
347
348                 if (y < height - 1) {
349                         dst_line[0] += dst_pitch * 2;
350                         dst_line[1] += dst_pitch * 2;
351                 }
352         }
353 }
354
355
356 void Super2xSaI (unsigned char *src, unsigned int src_pitch, int src_bytes_per_pixel,
357                  unsigned char *dst, unsigned int dst_pitch, int dst_bytes_per_pixel,
358                  int width, int height, int pal[256])
359 {
360 #define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))
361
362 #define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask))
363
364 #define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) \
365         + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask)
366
367 #define GET_COLOR(x) (pal[(x)])
368
369         unsigned char *src_line[4];
370         unsigned char *dst_line[2];
371         int x, y;
372         unsigned long color[16];
373
374         if ( (width<2) || (height<2) ) {
375                 Scale2x(src, src_pitch, src_bytes_per_pixel, dst, dst_pitch, dst_bytes_per_pixel, width, height, pal);
376                 return;
377         }
378
379         /* Point to the first 3 lines. */
380         src_line[0] = src;
381         src_line[1] = src;
382         src_line[2] = src + src_pitch;
383         src_line[3] = src + (src_pitch * 2);
384         
385         dst_line[0] = dst;
386         dst_line[1] = dst + dst_pitch;
387         
388         x = 0, y = 0;
389         
390         if (src_bytes_per_pixel == 1) {
391                 unsigned char *sbp;
392                 sbp = src_line[0];
393                 color[0] = GET_COLOR(*sbp);       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
394                 color[4] = color[0];   color[5] = color[0];   color[6] = GET_COLOR(*(sbp + 1));  color[7] = GET_COLOR(*(sbp + 2));
395                 sbp = src_line[2];
396                 color[8] = GET_COLOR(*sbp);     color[9] = color[8];     color[10] = GET_COLOR(*(sbp + 1)); color[11] = GET_COLOR(*(sbp + 2));
397                 sbp = src_line[3];
398                 color[12] = GET_COLOR(*sbp);    color[13] = color[12];   color[14] = GET_COLOR(*(sbp + 1)); color[15] = GET_COLOR(*(sbp + 2));
399         } else if (src_bytes_per_pixel == 2) {
400                 unsigned short *sbp;
401                 sbp = (unsigned short*)src_line[0];
402                 color[0] = *sbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
403                 color[4] = color[0];   color[5] = color[0];   color[6] = *(sbp + 1);  color[7] = *(sbp + 2);
404                 sbp = (unsigned short*)src_line[2];
405                 color[8] = *sbp;     color[9] = color[8];     color[10] = *(sbp + 1); color[11] = *(sbp + 2);
406                 sbp = (unsigned short*)src_line[3];
407                 color[12] = *sbp;    color[13] = color[12];   color[14] = *(sbp + 1); color[15] = *(sbp + 2);
408         } else {
409                 unsigned long *lbp;
410                 lbp = (unsigned long*)src_line[0];
411                 color[0] = *lbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
412                 color[4] = color[0];   color[5] = color[0];   color[6] = *(lbp + 1);  color[7] = *(lbp + 2);
413                 lbp = (unsigned long*)src_line[2];
414                 color[8] = *lbp;     color[9] = color[8];     color[10] = *(lbp + 1); color[11] = *(lbp + 2);
415                 lbp = (unsigned long*)src_line[3];
416                 color[12] = *lbp;    color[13] = color[12];   color[14] = *(lbp + 1); color[15] = *(lbp + 2);
417         }
418
419         for (y = 0; y < height; y++) {
420         
421                 /* Todo: x = width - 2, x = width - 1 */
422                 
423                 for (x = 0; x < width; x++) {
424                         unsigned long product1a, product1b, product2a, product2b;
425
426 //---------------------------------------  B0 B1 B2 B3    0  1  2  3
427 //                                         4  5* 6  S2 -> 4  5* 6  7
428 //                                         1  2  3  S1    8  9 10 11
429 //                                         A0 A1 A2 A3   12 13 14 15
430 //--------------------------------------
431                         if (color[9] == color[6] && color[5] != color[10]) {
432                                 product2b = color[9];
433                                 product1b = product2b;
434                         }
435                         else if (color[5] == color[10] && color[9] != color[6]) {
436                                 product2b = color[5];
437                                 product1b = product2b;
438                         }
439                         else if (color[5] == color[10] && color[9] == color[6]) {
440                                 int r = 0;
441
442                                 r += GET_RESULT(color[6], color[5], color[8], color[13]);
443                                 r += GET_RESULT(color[6], color[5], color[4], color[1]);
444                                 r += GET_RESULT(color[6], color[5], color[14], color[11]);
445                                 r += GET_RESULT(color[6], color[5], color[2], color[7]);
446
447                                 if (r > 0)
448                                         product1b = color[6];
449                                 else if (r < 0)
450                                         product1b = color[5];
451                                 else
452                                         product1b = INTERPOLATE(color[5], color[6]);
453                                         
454                                 product2b = product1b;
455
456                         }
457                         else {
458                                 if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12])
459                                         product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]);
460                                 else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15])
461                                         product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]);
462                                 else
463                                         product2b = INTERPOLATE(color[9], color[10]);
464
465                                 if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0])
466                                         product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]);
467                                 else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3])
468                                         product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]);
469                                 else
470                                         product1b = INTERPOLATE(color[5], color[6]);
471                         }
472
473                         if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14])
474                                 product2a = INTERPOLATE(color[9], color[5]);
475                         else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12])
476                                 product2a = INTERPOLATE(color[9], color[5]);
477                         else
478                                 product2a = color[9];
479
480                         if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2])
481                                 product1a = INTERPOLATE(color[9], color[5]);
482                         else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0])
483                                 product1a = INTERPOLATE(color[9], color[5]);
484                         else
485                                 product1a = color[5];
486         
487                         if (dst_bytes_per_pixel == 2) {
488                                 *((unsigned long *) (&dst_line[0][x * 4])) = product1a | (product1b << 16);
489                                 *((unsigned long *) (&dst_line[1][x * 4])) = product2a | (product2b << 16);
490                         } else {
491                                 *((unsigned long *) (&dst_line[0][x * 8])) = product1a;
492                                 *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b;
493                                 *((unsigned long *) (&dst_line[1][x * 8])) = product2a;
494                                 *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b;
495                         }
496                         
497                         /* Move color matrix forward */
498                         color[0] = color[1]; color[4] = color[5]; color[8] = color[9];   color[12] = color[13];
499                         color[1] = color[2]; color[5] = color[6]; color[9] = color[10];  color[13] = color[14];
500                         color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15];
501                         
502                         if (x < width - 3) {
503                                 x+=3;
504                                 if (src_bytes_per_pixel == 1) {
505                                         color[3] = GET_COLOR(*(((unsigned char*)src_line[0]) + x));
506                                         color[7] = GET_COLOR(*(((unsigned char*)src_line[1]) + x));
507                                         color[11] = GET_COLOR(*(((unsigned char*)src_line[2]) + x));
508                                         color[15] = GET_COLOR(*(((unsigned char*)src_line[3]) + x));
509                                 } else if (src_bytes_per_pixel == 2) {
510                                         color[3] = *(((unsigned short*)src_line[0]) + x);                                       
511                                         color[7] = *(((unsigned short*)src_line[1]) + x);
512                                         color[11] = *(((unsigned short*)src_line[2]) + x);
513                                         color[15] = *(((unsigned short*)src_line[3]) + x);
514                                 } else {
515                                         color[3] = *(((unsigned long*)src_line[0]) + x);
516                                         color[7] = *(((unsigned long*)src_line[1]) + x);
517                                         color[11] = *(((unsigned long*)src_line[2]) + x);
518                                         color[15] = *(((unsigned long*)src_line[3]) + x);
519                                 }
520                                 x-=3;
521                         }
522                 }
523
524                 /* We're done with one line, so we shift the source lines up */
525                 src_line[0] = src_line[1];
526                 src_line[1] = src_line[2];
527                 src_line[2] = src_line[3];              
528
529                 /* Read next line */
530                 if (y + 3 >= height)
531                         src_line[3] = src_line[2];
532                 else
533                         src_line[3] = src_line[2] + src_pitch;
534                         
535                 /* Then shift the color matrix up */
536                 if (src_bytes_per_pixel == 1) {
537                         unsigned char *sbp;
538                         sbp = src_line[0];
539                         color[0] = GET_COLOR(*sbp);     color[1] = color[0];    color[2] = GET_COLOR(*(sbp + 1));  color[3] = GET_COLOR(*(sbp + 2));
540                         sbp = src_line[1];
541                         color[4] = GET_COLOR(*sbp);     color[5] = color[4];    color[6] = GET_COLOR(*(sbp + 1));  color[7] = GET_COLOR(*(sbp + 2));
542                         sbp = src_line[2];
543                         color[8] = GET_COLOR(*sbp);     color[9] = color[8];    color[10] = GET_COLOR(*(sbp + 1)); color[11] = GET_COLOR(*(sbp + 2));
544                         sbp = src_line[3];
545                         color[12] = GET_COLOR(*sbp);    color[13] = color[12];  color[14] = GET_COLOR(*(sbp + 1)); color[15] = GET_COLOR(*(sbp + 2));
546                 } else if (src_bytes_per_pixel == 2) {
547                         unsigned short *sbp;
548                         sbp = (unsigned short*)src_line[0];
549                         color[0] = *sbp;     color[1] = color[0];    color[2] = *(sbp + 1);  color[3] = *(sbp + 2);
550                         sbp = (unsigned short*)src_line[1];
551                         color[4] = *sbp;     color[5] = color[4];    color[6] = *(sbp + 1);  color[7] = *(sbp + 2);
552                         sbp = (unsigned short*)src_line[2];
553                         color[8] = *sbp;     color[9] = color[9];    color[10] = *(sbp + 1); color[11] = *(sbp + 2);
554                         sbp = (unsigned short*)src_line[3];
555                         color[12] = *sbp;    color[13] = color[12];  color[14] = *(sbp + 1); color[15] = *(sbp + 2);
556                 } else {
557                         unsigned long *lbp;
558                         lbp = (unsigned long*)src_line[0];
559                         color[0] = *lbp;     color[1] = color[0];    color[2] = *(lbp + 1);  color[3] = *(lbp + 2);
560                         lbp = (unsigned long*)src_line[1];
561                         color[4] = *lbp;     color[5] = color[4];    color[6] = *(lbp + 1);  color[7] = *(lbp + 2);
562                         lbp = (unsigned long*)src_line[2];
563                         color[8] = *lbp;     color[9] = color[9];    color[10] = *(lbp + 1); color[11] = *(lbp + 2);
564                         lbp = (unsigned long*)src_line[3];
565                         color[12] = *lbp;    color[13] = color[12];  color[14] = *(lbp + 1); color[15] = *(lbp + 2);
566                 }
567                 
568                 if (y < height - 1) {
569                         dst_line[0] += dst_pitch * 2;
570                         dst_line[1] += dst_pitch * 2;
571                 }
572         }
573 }
574
575
576 void flippage(int page)
577 {
578         int x,y;
579         unsigned char *src;
580         unsigned char *dest;
581
582         assert(drawing_enable==0);
583
584         SDL_LockSurface(jnb_surface);
585         if (!jnb_surface->pixels) {
586                 
587                 for (x=0; x<(25*16); x++) {
588                         dirty_blocks[0][x] = 1;
589                         dirty_blocks[1][x] = 1;
590                 }
591
592                 return;
593         }
594 #ifdef SCALE_UP
595         dest=(unsigned char *)jnb_surface->pixels;
596         src=screen_buffer[page];
597         Super2xSaI(src, JNB_WIDTH, 1, dest, jnb_surface->pitch, 2, JNB_WIDTH, JNB_HEIGHT, current_pal);
598 #else
599         dest=(unsigned char *)jnb_surface->pixels;
600         src=screen_buffer[page];
601         for (y=0; y<screen_height; y++) {
602                 //memset(&dest[y*jnb_surface->pitch],0,JNB_SURFACE_WIDTH*bytes_per_pixel);
603                 for (x=0; x<25; x++) {
604                         int count;
605                         int test_x;
606
607                         count=0;
608                         test_x=x;
609                         while ( (test_x<25) && (dirty_blocks[page][(y>>dirty_block_shift)*25+test_x]) ) {
610                                 count++;
611                                 test_x++;
612                         }
613                         if (count) {
614                                 memcpy( &dest[y*jnb_surface->pitch+(x<<dirty_block_shift)*bytes_per_pixel],
615                                         &src[y*screen_pitch+((x<<dirty_block_shift)*bytes_per_pixel)],
616                                         ((16<<dirty_block_shift)>>4)*bytes_per_pixel*count);
617                                 //*((pixel_t *)(&dest[(y>>dirty_block_shift)*jnb_surface->pitch+x*bytes_per_pixel]))=0xe0e0;
618                         }
619                         x = test_x;
620                 }
621         }
622         memset(&dirty_blocks[page], 0, sizeof(int)*25*16);
623 #endif
624         SDL_UnlockSurface(jnb_surface);
625         SDL_Flip(jnb_surface);
626 }
627
628
629 void draw_begin(void)
630 {
631         assert(drawing_enable==0);
632
633         drawing_enable = 1;
634         if (background_drawn == 0) {
635                 if (background) {
636                         put_block(0, 0, 0, JNB_WIDTH, JNB_HEIGHT, background);
637                         put_block(1, 0, 0, JNB_WIDTH, JNB_HEIGHT, background);
638                         //put_block(0, 0, 0, rabbit_gobs.width[1], rabbit_gobs.height[1], rabbit_gobs.data[1]);
639                         //put_block(1, 0, 0, rabbit_gobs.width[1], rabbit_gobs.height[1], rabbit_gobs.data[1]);
640                 } else {
641                         clear_page(0, 0);
642                         clear_page(1, 0);
643                 }
644                 background_drawn = 1;
645         }
646 }
647
648
649 void draw_end(void)
650 {
651         assert(drawing_enable==1);
652
653         drawing_enable = 0;
654 }
655
656
657 void setpalette(int index, int count, char *palette)
658 {
659         SDL_Color colors[256];
660         int i;
661
662         assert(drawing_enable==0);
663
664         for (i = 0; i < count; i++) {
665                 colors[i+index].r = palette[i * 3 + 0] << 2;
666                 colors[i+index].g = palette[i * 3 + 1] << 2;
667                 colors[i+index].b = palette[i * 3 + 2] << 2;
668                 current_pal[i+index] = SDL_MapRGB(jnb_surface->format, colors[i+index].r, colors[i+index].g, colors[i+index].b);
669         }
670         if (!scale_up)
671                 SDL_SetColors(jnb_surface, &colors[index], index, count);
672 }
673
674
675 void fillpalette(int red, int green, int blue)
676 {
677         SDL_Color colors[256];
678         int i;
679
680         assert(drawing_enable==0);
681
682         for (i = 0; i < 256; i++) {
683                 colors[i].r = red << 2;
684                 colors[i].g = green << 2;
685                 colors[i].b = blue << 2;
686                 current_pal[i] = SDL_MapRGB(jnb_surface->format, colors[i].r, colors[i].g, colors[i].b);
687         }
688         if (!scale_up)
689                 SDL_SetColors(jnb_surface, colors, 0, 256);
690 }
691
692
693 void get_block(int page, int x, int y, int width, int height, void *buffer)
694 {
695         unsigned char *buffer_ptr, *vga_ptr;
696         int h;
697
698         assert(drawing_enable==1);
699
700         if (scale_up) {
701                 x *= 2;
702                 y *= 2;
703                 width *= 2;
704                 height *= 2;
705         }
706
707         if (x < 0)
708                 x = 0;
709         if (y < 0)
710                 y = 0;
711         if (y + height >= screen_height)
712                 height = screen_height - y;
713         if (x + width >= screen_width)
714                 width = screen_width - x;
715         if (width<=0)
716                 return;
717         if(height<=0)
718                 return;
719
720         vga_ptr = get_vgaptr(page, x, y);
721         buffer_ptr = buffer;
722         for (h = 0; h < height; h++) {
723                 memcpy(buffer_ptr, vga_ptr, width * bytes_per_pixel);
724                 vga_ptr += screen_pitch;
725                 buffer_ptr += width * bytes_per_pixel;
726         }
727
728 }
729
730
731 void put_block(int page, int x, int y, int width, int height, void *buffer)
732 {
733         int h;
734         unsigned char *vga_ptr, *buffer_ptr;
735
736         assert(drawing_enable==1);
737
738         if (scale_up) {
739                 x *= 2;
740                 y *= 2;
741                 width *= 2;
742                 height *= 2;
743         }
744
745         if (x < 0)
746                 x = 0;
747         if (y < 0)
748                 y = 0;
749         if (y + height >= screen_height)
750                 height = screen_height - y;
751         if (x + width >= screen_width)
752                 width = screen_width - x;
753         if (width<=0)
754                 return;
755         if(height<=0)
756                 return;
757
758         vga_ptr = get_vgaptr(page, x, y);
759         buffer_ptr = buffer;
760         for (h = 0; h < height; h++) {
761                 memcpy(vga_ptr, buffer_ptr, width * bytes_per_pixel);
762                 vga_ptr += screen_pitch;
763                 buffer_ptr += width * bytes_per_pixel;
764         }
765         width = ((x+width)>>dirty_block_shift) - (x>>dirty_block_shift) + 1;
766         height = ((y+height)>>dirty_block_shift) - (y>>dirty_block_shift) + 1;
767         x >>= dirty_block_shift;
768         y >>= dirty_block_shift;
769         while (width--)
770                 for (h=0; h<height; h++)
771                         dirty_blocks[page][(y+h)*25+(x+width)] = 1;
772 }
773
774
775 void put_text(int page, int x, int y, char *text, int align)
776 {
777         int c1;
778         int t1;
779         int width;
780         int cur_x;
781         int image;
782
783         assert(drawing_enable==1);
784
785         if (text == NULL || strlen(text) == 0)
786                 return;
787         if (font_gobs.num_images == 0)
788                 return;
789
790         width = 0;
791         c1 = 0;
792         while (text[c1] != 0) {
793                 t1 = text[c1];
794                 c1++;
795                 if (t1 == ' ') {
796                         width += 5;
797                         continue;
798                 }
799                 if (t1 >= 33 && t1 <= 34)
800                         image = t1 - 33;
801
802                 else if (t1 >= 39 && t1 <= 41)
803                         image = t1 - 37;
804
805                 else if (t1 >= 44 && t1 <= 59)
806                         image = t1 - 39;
807
808                 else if (t1 >= 64 && t1 <= 90)
809                         image = t1 - 43;
810
811                 else if (t1 >= 97 && t1 <= 122)
812                         image = t1 - 49;
813
814                 else if (t1 == '~')
815                         image = 74;
816
817                 else if (t1 == 0x84)
818                         image = 75;
819
820                 else if (t1 == 0x86)
821                         image = 76;
822
823                 else if (t1 == 0x8e)
824                         image = 77;
825
826                 else if (t1 == 0x8f)
827                         image = 78;
828
829                 else if (t1 == 0x94)
830                         image = 79;
831
832                 else if (t1 == 0x99)
833                         image = 80;
834
835                 else
836                         continue;
837                 width += pob_width(image, &font_gobs) + 1;
838         }
839
840         switch (align) {
841         case 0:
842                 cur_x = x;
843                 break;
844         case 1:
845                 cur_x = x - width;
846                 break;
847         case 2:
848                 cur_x = x - width / 2;
849                 break;
850         default:
851                 cur_x = 0;      /* this should cause error? -Chuck */
852                 break;
853         }
854         c1 = 0;
855
856         while (text[c1] != 0) {
857                 t1 = text[c1];
858                 c1++;
859                 if (t1 == ' ') {
860                         cur_x += 5;
861                         continue;
862                 }
863                 if (t1 >= 33 && t1 <= 34)
864                         image = t1 - 33;
865
866                 else if (t1 >= 39 && t1 <= 41)
867                         image = t1 - 37;
868
869                 else if (t1 >= 44 && t1 <= 59)
870                         image = t1 - 39;
871
872                 else if (t1 >= 64 && t1 <= 90)
873                         image = t1 - 43;
874
875                 else if (t1 >= 97 && t1 <= 122)
876                         image = t1 - 49;
877
878                 else if (t1 == '~')
879                         image = 74;
880
881                 else if (t1 == 0x84)
882                         image = 75;
883
884                 else if (t1 == 0x86)
885                         image = 76;
886
887                 else if (t1 == 0x8e)
888                         image = 77;
889
890                 else if (t1 == 0x8f)
891                         image = 78;
892
893                 else if (t1 == 0x94)
894                         image = 79;
895
896                 else if (t1 == 0x99)
897                         image = 80;
898
899                 else
900                         continue;
901                 put_pob(page, cur_x, y, image, &font_gobs, 1, mask_pic);
902                 cur_x += pob_width(image, &font_gobs) + 1;
903         }
904 }
905
906
907 void put_pob(int page, int x, int y, int image, gob_t *gob, int use_mask, void *mask_pic)
908 {
909         int c1, c2;
910         int pob_x, pob_y;
911         int width, height;
912         int draw_width, draw_height;
913         int colour;
914
915         assert(drawing_enable==1);
916         assert(gob);
917         assert(image>=0);
918         assert(image<gob->num_images);
919
920         if (scale_up) {
921                 x *= 2;
922                 y *= 2;
923                 width = draw_width = gob->width[image]*2;
924                 height = draw_height = gob->height[image]*2;
925                 x -= gob->hs_x[image]*2;
926                 y -= gob->hs_y[image]*2;
927         } else {
928                 width = draw_width = gob->width[image];
929                 height = draw_height = gob->height[image];
930                 x -= gob->hs_x[image];
931                 y -= gob->hs_y[image];
932         }
933
934         if ((x + width) <= 0 || x >= screen_width)
935                 return;
936         if ((y + height) <= 0 || y >= screen_height)
937                 return;
938
939         pob_x = 0;
940         pob_y = 0;
941         if (x < 0) {
942                 pob_x -= x;
943                 draw_width += x;
944                 x = 0;
945         }
946         if ((x + width) > screen_width)
947                 draw_width -= x + width - screen_width;
948         if (y < 0) {
949                 pob_y -= y;
950                 draw_height += y;
951                 y = 0;
952         }
953         if ((y + height) > screen_height)
954                 draw_height -= y + height - screen_height;
955
956
957         if (bytes_per_pixel==1) {
958                 unsigned char *vga_ptr;
959                 unsigned char *pob_ptr;
960                 unsigned char *mask_ptr;
961
962                 vga_ptr = get_vgaptr(page, x, y);
963                 pob_ptr = ((unsigned char *)gob->data[image]) + ((pob_y * width) + pob_x);
964                 mask_ptr = ((unsigned char *)mask) + ((y * screen_pitch) + (x*bytes_per_pixel));
965                 for (c1 = 0; c1 < draw_height; c1++) {
966                         for (c2 = 0; c2 < draw_width; c2++) {
967                                 colour = *mask_ptr;
968                                 if (use_mask == 0 || (use_mask == 1 && colour == 0)) {
969                                         colour = *pob_ptr;
970                                         if (colour != 0) {
971                                                 *vga_ptr = colour;
972                                         }
973                                 }
974                                 vga_ptr++;
975                                 pob_ptr++;
976                                 mask_ptr++;
977                         }
978                         pob_ptr += width - c2;
979                         vga_ptr += (screen_width - c2);
980                         mask_ptr += (screen_width - c2);
981                 }
982         } else if (bytes_per_pixel==2) {
983                 unsigned short *vga_ptr;
984                 unsigned short *pob_ptr;
985                 unsigned short *mask_ptr;
986
987                 vga_ptr = get_vgaptr(page, x, y);
988                 pob_ptr = (unsigned short *)(((unsigned char *)gob->data[image]) + ((pob_y * width) + pob_x));
989                 mask_ptr = (unsigned short *)(((unsigned char *)mask) + ((y * screen_pitch) + (x*bytes_per_pixel)));
990                 for (c1 = 0; c1 < draw_height; c1++) {
991                         for (c2 = 0; c2 < draw_width; c2++) {
992                                 colour = *mask_ptr;
993                                 if (use_mask == 0 || (use_mask == 1 && colour == 0)) {
994                                         colour = *pob_ptr;
995                                         if (colour != 0) {
996                                                 *vga_ptr = colour;
997                                         }
998                                 }
999                                 vga_ptr++;
1000                                 pob_ptr++;
1001                                 mask_ptr++;
1002                         }
1003                         pob_ptr += width - c2;
1004                         vga_ptr += (screen_width - c2);
1005                         mask_ptr += (screen_width - c2);
1006                 }
1007         } else {
1008                 unsigned int *vga_ptr;
1009                 unsigned int *pob_ptr;
1010                 unsigned int *mask_ptr;
1011
1012                 vga_ptr = get_vgaptr(page, x, y);
1013                 pob_ptr = (unsigned int *)(((unsigned char *)gob->data[image]) + ((pob_y * width) + pob_x));
1014                 mask_ptr = (unsigned int *)(((unsigned char *)mask) + ((y * screen_pitch) + (x*bytes_per_pixel)));
1015                 for (c1 = 0; c1 < draw_height; c1++) {
1016                         for (c2 = 0; c2 < draw_width; c2++) {
1017                                 colour = *mask_ptr;
1018                                 if (use_mask == 0 || (use_mask == 1 && colour == 0)) {
1019                                         colour = *pob_ptr;
1020                                         if (colour != 0) {
1021                                                 *vga_ptr = colour;
1022                                         }
1023                                 }
1024                                 vga_ptr++;
1025                                 pob_ptr++;
1026                                 mask_ptr++;
1027                         }
1028                         pob_ptr += width - c2;
1029                         vga_ptr += (screen_width - c2);
1030                         mask_ptr += (screen_width - c2);
1031                 }
1032         }
1033         draw_width = ((x+draw_width)>>dirty_block_shift) - (x>>dirty_block_shift) + 1;
1034         draw_height = ((y+draw_height)>>dirty_block_shift) - (y>>dirty_block_shift) + 1;
1035         x >>= dirty_block_shift;
1036         y >>= dirty_block_shift;
1037         while (draw_width--)
1038                 for (c1=0; c1<draw_height; c1++)
1039                         dirty_blocks[page][(y+c1)*25+(x+draw_width)] = 1;
1040 }
1041
1042
1043 int pob_width(int image, gob_t *gob)
1044 {
1045         assert(gob);
1046         assert(image>=0);
1047         assert(image<gob->num_images);
1048         return gob->width[image];
1049 }
1050
1051
1052 int pob_height(int image, gob_t *gob)
1053 {
1054         assert(gob);
1055         assert(image>=0);
1056         assert(image<gob->num_images);
1057         return gob->height[image];
1058 }
1059
1060
1061 int pob_hs_x(int image, gob_t *gob)
1062 {
1063         assert(gob);
1064         assert(image>=0);
1065         assert(image<gob->num_images);
1066         return gob->hs_x[image];
1067 }
1068
1069
1070 int pob_hs_y(int image, gob_t *gob)
1071 {
1072         assert(gob);
1073         assert(image>=0);
1074         assert(image<gob->num_images);
1075         return gob->hs_y[image];
1076 }
1077
1078
1079 int read_pcx(FILE * handle, void *buf, int buf_len, char *pal)
1080 {
1081         unsigned char *buffer=buf;
1082         short c1;
1083         short a, b;
1084         long ofs1;
1085         if (buffer != 0) {
1086                 fseek(handle, 128, SEEK_CUR);
1087                 ofs1 = 0;
1088                 while (ofs1 < buf_len) {
1089                         a = fgetc(handle);
1090                         if ((a & 0xc0) == 0xc0) {
1091                                 b = fgetc(handle);
1092                                 a &= 0x3f;
1093                                 for (c1 = 0; c1 < a && ofs1 < buf_len; c1++)
1094                                         buffer[ofs1++] = (char) b;
1095                         } else
1096                                 buffer[ofs1++] = (char) a;
1097                 }
1098                 if (pal != 0) {
1099                         fseek(handle, 1, SEEK_CUR);
1100                         for (c1 = 0; c1 < 768; c1++)
1101                                 pal[c1] = fgetc(handle) >> 2;
1102                 }
1103         }
1104         return 0;
1105 }
1106
1107
1108 void register_background(char *pixels, char pal[768])
1109 {
1110         if (background) {
1111                 free(background);
1112                 background = NULL;
1113         }
1114         background_drawn = 0;
1115         if (!pixels)
1116                 return;
1117         assert(pal);
1118         if (scale_up) {
1119                 int int_pal[256];
1120                 int i;
1121
1122                 for (i=0; i<256; i++)
1123                         int_pal[i] = SDL_MapRGB(jnb_surface->format, (Uint8)(pal[i*3+0]<<2), (Uint8)(pal[i*3+1]<<2), (Uint8)(pal[i*3+2]<<2));
1124                 background = malloc(screen_pitch*screen_height);
1125                 assert(background);
1126                 Super2xSaI(pixels, JNB_WIDTH, 1, (unsigned char *)background, screen_pitch, bytes_per_pixel, JNB_WIDTH, JNB_HEIGHT, int_pal);
1127         } else {
1128                 background = malloc(JNB_WIDTH*JNB_HEIGHT);
1129                 assert(background);
1130                 memcpy(background, pixels, JNB_WIDTH*JNB_HEIGHT);
1131         }
1132 }
1133
1134 int register_gob(FILE *handle, gob_t *gob, int len)
1135 {
1136         unsigned char *gob_data;
1137         int i;
1138
1139         gob_data = malloc(len);
1140         fread(gob_data, 1, len, handle);
1141
1142         gob->num_images = (short)((gob_data[0]) + (gob_data[1] << 8));
1143
1144         gob->width = malloc(gob->num_images*sizeof(int));
1145         gob->height = malloc(gob->num_images*sizeof(int));
1146         gob->hs_x = malloc(gob->num_images*sizeof(int));
1147         gob->hs_y = malloc(gob->num_images*sizeof(int));
1148         gob->data = malloc(gob->num_images*sizeof(void *));
1149         gob->orig_data = malloc(gob->num_images*sizeof(void *));
1150         for (i=0; i<gob->num_images; i++) {
1151                 int image_size;
1152                 int offset;
1153
1154                 offset = (gob_data[i*4+2]) + (gob_data[i*4+3] << 8) + (gob_data[i*4+4] << 16) + (gob_data[i*4+5] << 24);
1155
1156                 gob->width[i]  = (short)((gob_data[offset]) + (gob_data[offset+1] << 8)); offset += 2;
1157                 gob->height[i] = (short)((gob_data[offset]) + (gob_data[offset+1] << 8)); offset += 2;
1158                 gob->hs_x[i]   = (short)((gob_data[offset]) + (gob_data[offset+1] << 8)); offset += 2;
1159                 gob->hs_y[i]   = (short)((gob_data[offset]) + (gob_data[offset+1] << 8)); offset += 2;
1160
1161                 image_size = gob->width[i] * gob->height[i];
1162                 gob->orig_data[i] = malloc(image_size);
1163                 memcpy(gob->orig_data[i], &gob_data[offset], image_size);
1164                 if (scale_up) {
1165                         image_size = gob->width[i] * gob->height[i] * 4 * bytes_per_pixel;
1166                         gob->data[i] = malloc(image_size);
1167                 } else {
1168                         gob->data[i] = (unsigned short *)gob->orig_data[i];
1169                 }
1170         }
1171         free(gob_data);
1172         return 0;
1173 }
1174
1175
1176 void recalculate_gob(gob_t *gob, char pal[768])
1177 {
1178         int int_pal[256];
1179         int i;
1180
1181         if (!scale_up)
1182                 return;
1183
1184         for (i=1; i<256; i++) {
1185                 int_pal[i] = SDL_MapRGB(jnb_surface->format, (Uint8)(pal[i*3+0]<<2), (Uint8)(pal[i*3+1]<<2), (Uint8)(pal[i*3+2]<<2));
1186                 if (int_pal[i] == 0)
1187                         int_pal[i] = SDL_MapRGB(jnb_surface->format, 8, 8, 8);
1188         }
1189         int_pal[0] = 0;
1190
1191         for (i=0; i<gob->num_images; i++) {
1192                 Super2xSaI(gob->orig_data[i], gob->width[i], 1, (unsigned char *)gob->data[i], gob->width[i]*2*bytes_per_pixel, bytes_per_pixel, gob->width[i], gob->height[i], int_pal);
1193         }
1194 }
1195
1196 void register_mask(void *pixels)
1197 {
1198         if (mask) {
1199                 free(mask);
1200                 mask = NULL;
1201         }
1202         assert(pixels);
1203         if (scale_up) {
1204                 int int_pal[256];
1205                 int i;
1206
1207                 int_pal[0] = 0;
1208                 for (i=1; i<256; i++)
1209                         int_pal[i] = 0xffffffff;
1210                 mask = malloc(screen_pitch*screen_height);
1211                 assert(mask);
1212                 Scale2x(pixels, JNB_WIDTH, 1, (unsigned char *)mask, screen_pitch, bytes_per_pixel, JNB_WIDTH, JNB_HEIGHT, int_pal);
1213         } else {
1214                 mask = malloc(JNB_WIDTH*JNB_HEIGHT);
1215                 assert(mask);
1216                 memcpy(mask, pixels, JNB_WIDTH*JNB_HEIGHT);
1217         }
1218 }