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