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