]> Shamusworld >> Repos - thunder/blob - src/screen.cpp
bc733601fa4eda7620ce1030ddcd4e65a6ee897e
[thunder] / src / screen.cpp
1 //
2 // Screen Handler
3 //
4 // This sets screen to VESA 320x240 LFB so we can use the WHOLE laptop screen
5 // Now with VESA2 support!
6 // Also, support routines for video hardware emulation are included
7 //
8 // by James Hammons
9 //
10 // (C) 2003 Underground Software
11 //
12 // JLH = James Hammons <jlhamm@acm.org>
13 //
14 // Who  When        What
15 // ---  ----------  -----------------------------------------------------------
16 // JLH  03/12/2003  Ported this steaming pile of crap from VESA to SDL
17 //
18
19 #include "screen.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string>                     // For memset()
24 #include "gui.h"
25 #include "video.h"
26
27 // Private function prototypes
28
29 void DrawSprites(uint8_t priority);
30 int FindPCXName(void);
31 //static void DrawChar(uint8_t * chr, uint8_t * ram, uint8_t sx, uint8_t sy, uint16_t scp, uint32_t baseAddr, uint32_t scrollOffset, bool transparent = true);
32 static void DrawChar(uint8_t * chr, uint8_t * ram, uint8_t sx, uint8_t sy, uint16_t scp, uint32_t baseAddr, uint32_t xScroll = 0, uint32_t yScroll = 0, bool transparent = true);
33 void Sprite(uint32_t sprnum, uint16_t x, uint16_t y, uint8_t flip, uint8_t horiz_bl, uint8_t vert_bl);
34
35 // Private global variables
36
37 uint8_t my_scr[0x14000];                        // Screen buffer...
38 //uint8_t palette[768];                         // Screen palette
39 uint32_t palette[256];                          // Screen palette
40 uint8_t ccolor[256][8];                         // Character colors
41 uint8_t scolor[128][16];                        // Sprite colors
42 bool charbase;                                          // Character base pointer...
43 uint8_t hScrollOffset;                          // Horizontal scroll offset
44 uint8_t vScrollOffset;                          // Vertical scroll offset
45 uint8_t spr_color_index;                        // Sprite color index
46 uint32_t hoffsets[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };// Scroll offsets...
47 //uint32_t voffsets[8] = { 0, 320, 640, 960, 1280, 1600, 1920, 2240 };
48 uint32_t voffsets[8] = { 288*0, 288*1, 288*2, 288*3, 288*4, 288*5, 288*6, 288*7 };
49 //n.b.: 320 = $140
50 // $000, $140, $280, $3C0, $500, $640, $780, $8C0
51
52 extern bool show_text;                          // Whether or not to show text
53 extern bool show_scr;                           // Whether or not to show screen
54
55
56 //
57 // Render the NAMCO screen
58 //
59 void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram)
60 {
61         // Screen structure:
62         // Screen is 288 x 224 pixels, with character and independent sprites.
63         // Tiles are 36 x 28. There are four tile planes, three of them affected by
64         // the h/vscroll values, the last one is a static display (also has highest
65         // priority). Screens are 128 bytes wide by 32 bytes high.
66
67         if (show_scr)
68         {
69                 uint32_t sc_base = ((ram[0x9000] << 8) | ram[0x9001]) + 4;      // Adjust hscroll val
70                 hScrollOffset = sc_base & 0x07;         // Horiz. fine scroll offset
71                 sc_base = (sc_base & 0xFFF8) >> 2;      // Skip odds..
72                 uint8_t vsc_base = ((ram[0x9002] + 1) & 0xF8) >> 3;// Vertical scroll addr adjust
73                 vScrollOffset = ((ram[0x9002] + 1) & 0x07);     // Vertical fine scroll amount
74
75                 uint32_t scp0 = 0x0180 | ((sc_base + 0x04) & 0x7F);     /*0x0188;*/
76                 uint32_t scp1 = 0x1180 | ((sc_base + 0x04) & 0x7F);     /*0x1188;*/
77                 uint32_t scp2 = 0x2180 | ((sc_base + 0x04) & 0x7F);     /*0x2188;*/
78                 uint32_t scp3 = 0x3208;
79
80                 scp0 += vsc_base * 0x80;
81                 scp0 &= 0x0FFF;                                         // Set vertical scroll addr
82                 scp1 += vsc_base * 0x80;
83                 scp1 = 0x1000 | (scp1 & 0x0FFF);        // Set vertical scroll addr
84                 scp2 += vsc_base * 0x80;
85                 scp2 = 0x2000 | (scp2 & 0x0FFF);        // Set vertical scroll addr
86
87                 // Layer 0 (bottom layer)
88                 for(uint8_t sy=0; sy<29; sy++)
89                 {
90                         for(uint8_t sx=0; sx<37; sx++)
91 #if 0
92                                 DrawChar(chr, ram, sx, sy, scp0, (charbase ? 0x20000 : 0x00000), 0, false);
93 #else
94                                 DrawChar(chr, ram, sx, sy, scp0, (charbase ? 0x20000 : 0x00000), hScrollOffset, vScrollOffset, false);
95 #endif
96
97                         scp0 += 0x80;
98                         scp0 = 0x0000 | (scp0 & 0x0FFF);
99                 }
100
101                 // Draw sprites at lowest layer...
102                 DrawSprites(0x40);
103
104                 // Layer 1
105                 for(uint8_t sy=0; sy<29; sy++)
106                 {
107                         for(uint8_t sx=0; sx<37; sx++)
108 #if 0
109                                 DrawChar(chr, ram, sx, sy, scp1, (charbase ? 0x30000 : 0x10000), 0);
110 #else
111                                 DrawChar(chr, ram, sx, sy, scp1, (charbase ? 0x30000 : 0x10000), hScrollOffset, vScrollOffset);
112 #endif
113
114                         scp1 += 0x80;
115                         scp1 = 0x1000 | (scp1 & 0x0FFF);
116                 }
117
118                 // Draw sprites under layer #2...
119                 DrawSprites(0x80);
120
121                 // Layer 2
122                 for(uint8_t sy=0; sy<29; sy++)
123                 {
124                         for(uint8_t sx=0; sx<37; sx++)
125 #if 0
126                                 DrawChar(chr, ram, sx, sy, scp2, 0x40000, 0);
127 #else
128                                 DrawChar(chr, ram, sx, sy, scp2, 0x40000, hScrollOffset, vScrollOffset);
129 #endif
130
131                         scp2 += 0x80;
132                         scp2 = 0x2000 | (scp2 & 0x0FFF);
133                 }
134
135                 // Draw highest priority sprites...
136                 DrawSprites(0xC0);
137
138                 // Layer 3 (top layer)
139                 for(uint8_t sy=0; sy<28; sy++)
140                 {
141                         for(uint8_t sx=0; sx<36; sx++)
142 #if 0
143                                 DrawChar(chr, ram, sx, sy, scp3, 0x50000, hScrollOffset + voffsets[vScrollOffset]);
144 #else
145                                 DrawChar(chr, ram, sx, sy, scp3, 0x50000);
146 #endif
147
148                         scp3 += 0x80;
149                 }
150         }
151
152         // Draw a msg if needed...
153         if (show_text)
154                 DrawText();
155
156         // Show GUI if active...
157         if (ShowGUI())
158                 DrawGUI();
159
160 #if 0
161         if (SDL_LockSurface(scr) < 0)
162         {
163 //              fprintf(stderr, "Couldn't lock the display surface: %s\n", SDL_GetError());
164 //              exit(2);
165         }
166 #endif
167
168         // Rolling Thunder screen size is 288 x 224. Virtual is this, real may not be...
169
170         uint32_t src = 0;//(uint32_t)(hoffsets[hScrollOffset] + voffsets[vScrollOffset]);
171 //      uint32_t srcAdd = 320 - VIRTUAL_SCREEN_WIDTH;
172
173         for(int i=0; i<VIRTUAL_SCREEN_HEIGHT; i++)
174         {
175                 for (int j=0; j<VIRTUAL_SCREEN_WIDTH; j++)
176                 {
177                         scrBuffer[(i * VIRTUAL_SCREEN_WIDTH) + j] = palette[my_scr[src++]];
178                 }
179
180 //              src += srcAdd;
181         }
182
183         RenderScreenBuffer();
184 }
185
186
187 //
188 // Draw character on screen
189 //
190 //static inline void DrawChar(uint8_t * chr, uint8_t * ram, uint8_t sx, uint8_t sy, uint16_t scp, uint32_t baseAddr, uint32_t scrollOffset, bool transparent/*= true*/)
191 static inline void DrawChar(uint8_t * chr, uint8_t * ram, uint8_t sx, uint8_t sy, uint16_t scp, uint32_t baseAddr, uint32_t xScroll/*= 0*/, uint32_t yScroll/*= 0*/, bool transparent/*= true*/)
192 {
193         uint8_t scp_lo = (scp + (sx << 1)) & 0x7F;// Let LO byte wrap only...
194         uint16_t sp2 = (scp & 0xFF80) | scp_lo;
195         uint8_t tile  = ram[sp2++];
196         uint8_t index = ram[sp2] & 0x03;
197         uint8_t color = ram[sp2];
198         uint32_t chind = baseAddr + (((index << 8) + tile) * 64);
199 //      uint32_t sc_addr = (sx * 8) + (sy * 2560) + scrollOffset;       // Start addr in my_scr[]
200 //      uint32_t sc_addr = (sx * 8) + (sy * 288 * 8);// + scrollOffset;
201
202         int xStart = (int)(sx * 8) - xScroll;
203         int yStart = (int)(sy * 8) - yScroll;
204
205 //      int32_t sc_addr = ((sx * 8) - xScroll) + ((sy * 8 * 288) - (yScroll * 288));
206         int32_t sc_addr = xStart + (yStart * 288);
207
208         for(int y=0; y<8; y++)
209         {
210                 for(int x=0; x<8; x++)
211                 {
212                         if (((xStart + x) < 0) || ((xStart + x) >= 288)
213                                 || ((yStart + y) < 0) || ((yStart + y) >= 224))
214                         {
215                                 sc_addr++;
216                                 chind++;
217                                 continue;
218                         }
219
220                         if (transparent)
221                         {
222                                 if (chr[chind] != 7)
223                                         my_scr[sc_addr] = ccolor[color][chr[chind]];
224                         }
225                         else
226                                 my_scr[sc_addr] = ccolor[color][chr[chind]];
227
228                         sc_addr++;
229                         chind++;
230                 }
231
232                 sc_addr += (288 - 8);           // Do next line of char...
233         }
234 }
235
236
237 //
238 // Draw sprites at priority level (new code)
239 //
240 void DrawSprites(uint8_t priority)
241 {
242 // Sprite blocks:
243 //
244 // Offset  Note
245 // ------  --------------------------------------------------------------------
246 // 4       h.fb .nnn (f = horz. flip, h = horz. expand, b = sprite offset lo
247 //         bit, nnn = upper bits of sprite #)
248 // 5       Lower 7 bits of sprite #
249 // 6       Sprite color index (top 7 bits only), bottom bit is bit 8 of X
250 //         position
251 // 7       Sprite X position (bits 0-7)
252 // 8       Top two bits are sprite priority, bits 4 & 2 are sprite offset hi
253 //         bit, vert. expand
254 // 9       Sprite Y position (192 - value)
255
256         extern uint8_t gram1[];                                                 // Game RAM space
257
258         for(uint16_t i=0x5800; i<0x6000; i+=0x10)
259         {
260                 if ((gram1[i + 8] & 0xC0) == priority)          // Check for correct layer...
261                 {
262                         spr_color_index = gram1[i + 6] >> 1;    // Set color...
263                         uint16_t x = ((gram1[i + 6] & 0x01) << 8) | gram1[i + 7];
264
265                         if (x > 512 - 32)
266                                 x -= 512;                                                       // Handle neg x values
267
268                         uint16_t y = 192 - gram1[i + 9];
269                         uint8_t flip = gram1[i + 4] & 0x20;             // Horizontal flip
270                         uint32_t spr_num = ((gram1[i + 4] & 0x07) << 9)
271                                 | ((gram1[i + 5] & 0x7F) << 2)
272                                 | ((gram1[i + 4] & 0x10) >> 4)
273                                 | ((gram1[i + 8] & 0x10) >> 3);
274
275                         // Draw sprite...
276                         Sprite(spr_num, x, y, flip, gram1[i + 4] & 0x80, gram1[i + 8] & 0x04);
277                 }
278         }
279 }
280
281
282 static inline void DrawSpriteBlock(uint32_t & sprnum, uint16_t x, uint16_t y, uint16_t xStart, uint16_t xEnd, int16_t xInc)
283 {
284         extern uint8_t spr_rom[];
285 //      uint32_t sc_addr;
286
287         for(uint16_t sy=0; sy<16; sy++)
288         {
289 //              for(uint16_t sx=0; sx<16; sx+=2)
290                 for(uint16_t sx=xStart; sx<xEnd; sx+=xInc)
291                 {
292                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
293                         uint16_t spy = y + sy, spx = x + sx;    // Need to optimize this clipping! [eh?]
294
295                         // This handles negative values, by casting as unsigned
296                         uint32_t sc_addr = ((spy >= 224) || (spx >= 288) ? 0x13FFE : spx + (spy * 288));
297
298                         if (b1 != 15)
299                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
300
301                         sc_addr++;
302
303                         if (b2 != 15)
304                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
305                 }
306         }
307 }
308
309
310 static inline void DrawSpriteBlock2(uint32_t & sprnum, uint16_t x, uint16_t y, uint16_t xStart, uint16_t xEnd, int16_t xInc)
311 {
312         extern uint8_t spr_rom[];
313 //      uint32_t sc_addr;
314
315         for(uint16_t sy=0; sy<16; sy++)
316         {
317 //              for(uint16_t sx=0; sx<16; sx+=2)
318                 for(uint16_t sx=xStart; sx!=xEnd; sx+=xInc)
319                 {
320                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
321                         uint16_t spy = y + sy, spx = x + sx;    // Need to optimize this clipping! [eh?]
322
323                         // This handles negative values, by casting as unsigned
324                         uint32_t sc_addr = ((spy >= 224) || (spx >= 288) ? 0x13FFE : spx + (spy * 288));
325
326                         if (b2 != 15)
327                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
328
329                         sc_addr++;
330
331                         if (b1 != 15)
332                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
333                 }
334         }
335 }
336
337
338 //
339 // Sprite handler
340 //
341 void Sprite(uint32_t sprnum, uint16_t x, uint16_t y, uint8_t flip,
342         uint8_t horiz_bl, uint8_t vert_bl)
343 {
344         extern uint8_t spr_rom[];
345         uint32_t sc_addr;
346         sprnum <<= 7;                           // 128 bytes per sprite
347
348         if (!vert_bl)
349                 y += 16;
350
351         if (!flip)
352         {
353 #if 0
354                 for(uint16_t sy=0; sy<16; sy++)
355                 {
356                         for(uint16_t sx=0; sx<16; sx+=2)
357                         {
358                                 uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
359                                 uint16_t spy = y + sy, spx = x + sx;    // Need to optimize this clipping!
360
361                                 // This handles negative values, by casting as unsigned
362 #if 0
363 //                              if (spy > 223 || spx > 299)
364                                 if (spy >= 224 || spx >= 288)
365                                         sc_addr = 0x13FFE;
366                                 else
367 //                                      sc_addr = spx + spy * 320;
368                                         sc_addr = spx + (spy * 288);
369 #else
370                                 sc_addr = ((spy >= 224) || (spx >= 288) ? 0x13FFE : spx + (spy * 288));
371 #endif
372                                 if (b1 != 15)
373                                         my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
374
375                                 sc_addr++;
376
377                                 if (b2 != 15)
378                                         my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
379                         }
380                 }
381 #else
382                 DrawSpriteBlock(sprnum, x, y, 0, 16, 2);
383 #endif
384
385                 if (horiz_bl)
386                 {
387 #if 0
388                         for(uint16_t sy=0; sy<16; sy++)
389                         {
390                                 for(uint16_t sx=16; sx<32; sx+=2)
391                                 {
392                                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
393                                         uint16_t spy = y + sy, spx = x + sx;
394
395 //                                      if (spy > 223 || spx > 299)
396                                         if (spy > 223 || spx > 287)
397                                                 sc_addr = 0x13FFE;
398                                         else
399 //                                              sc_addr = spx + spy * 320;
400                                                 sc_addr = spx + (spy * 288);
401
402                                         if (b1 != 15)
403                                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
404
405                                         sc_addr++;
406
407                                         if (b2 != 15)
408                                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
409                                 }
410                         }
411 #else
412                         DrawSpriteBlock(sprnum, x, y, 16, 32, 2);
413 #endif
414                 }
415                 else
416                         sprnum += 128;                                                          // Advance to next...
417
418                 if (vert_bl)
419                 {
420                         y += 16;                                                                        // Do next row...
421
422 #if 0
423                         for(uint16_t sy=0; sy<16; sy++)
424                         {
425                                 for(uint16_t sx=0; sx<16; sx+=2)
426                                 {
427                                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
428                                         uint16_t spy = y + sy, spx = x + sx;
429
430 //                                      if (spy > 223 || spx > 299)
431                                         if (spy > 223 || spx > 287)
432                                                 sc_addr = 0x13FFE;
433                                         else
434 //                                              sc_addr = spx + spy * 320;
435                                                 sc_addr = spx + (spy * 288);
436
437                                         if (b1 != 15)
438                                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
439
440                                         sc_addr++;
441
442                                         if (b2 != 15)
443                                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
444                                 }
445                         }
446 #else
447                         DrawSpriteBlock(sprnum, x, y, 0, 16, 2);
448 #endif
449
450                         if (horiz_bl)
451                         {
452 #if 0
453                                 for(uint16_t sy=0; sy<16; sy++)
454                                 {
455                                         for(uint16_t sx=16; sx<32; sx+=2)
456                                         {
457                                                 uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
458                                                 uint16_t spy = y + sy, spx = x + sx;
459
460 //                                              if (spy > 223 || spx > 299)
461                                                 if (spy > 223 || spx > 287)
462                                                         sc_addr = 0x13FFE;
463                                                 else
464 //                                                      sc_addr = spx + spy * 320;
465                                                         sc_addr = spx + (spy * 288);
466
467                                                 if (b1 != 15)
468                                                         my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
469
470                                                 sc_addr++;
471
472                                                 if (b2 != 15)
473                                                         my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
474                                         }
475                                 }
476 #else
477                                 DrawSpriteBlock(sprnum, x, y, 16, 32, 2);
478 #endif
479                         }
480                 }
481         }
482         else    // Flip
483         {
484                 if (horiz_bl)
485                 {
486 #if 0
487                         for(uint16_t sy=0; sy<16; sy++)
488                         {
489                                 for(uint16_t sx=30; sx!=14; sx-=2)
490                                 {
491                                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
492                                         uint16_t spy = y + sy, spx = x + sx;
493
494 //                                      if ((spy > 223) || (spx > 299))
495                                         if ((spy > 223) || (spx > 287))
496                                                 sc_addr = 0x13FFE;
497                                         else
498 //                                              sc_addr = spx + spy * 320;
499                                                 sc_addr = spx + (spy * 288);
500
501                                         if (b2 != 15)
502                                                 my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
503
504                                         sc_addr++;
505
506                                         if (b1 != 15)
507                                                 my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
508                                 }
509                         }
510 #else
511                         DrawSpriteBlock2(sprnum, x, y, 30, 14, -2);
512 #endif
513                 }
514
515 #if 0
516                 for(uint16_t sy=0; sy<16; sy++)
517                 {
518                         for(uint16_t sx=14; sx!=0xFFFE; sx-=2)
519                         {
520                                 uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
521                                 uint16_t spy = y + sy, spx = x + sx;
522
523 //                              if ((spy > 223) || (spx > 299))
524                                 if ((spy > 223) || (spx > 287))
525                                         sc_addr = 0x13FFE;
526                                 else
527 //                                      sc_addr = spx + spy * 320;
528                                         sc_addr = spx + (spy * 288);
529
530                                 if (b2 != 15)
531                                         my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
532
533                                 sc_addr++;
534
535                                 if (b1 != 15)
536                                         my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
537                         }
538                 }
539 #else
540                 DrawSpriteBlock2(sprnum, x, y, 14, 0xFFFE, -2);
541 #endif
542
543                 if (!horiz_bl)
544                         sprnum += 128;  // If single, skip sprite...
545
546                 if (vert_bl)
547                 {
548                         y += 16;      // Adjust Y coord...
549
550                         if (horiz_bl)
551                         {
552 #if 0
553                                 for(uint16_t sy=0; sy<16; sy++)
554                                 {
555                                         for(uint16_t sx=30; sx!=14; sx-=2)
556                                         {
557                                                 uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
558                                                 uint16_t spy = y + sy, spx = x + sx;
559
560 //                                              if ((spy > 223) || (spx > 299))
561                                                 if ((spy > 223) || (spx > 287))
562                                                         sc_addr = 0x13FFE;
563                                                 else
564 //                                                      sc_addr = spx + spy * 320;
565                                                         sc_addr = spx + (spy * 288);
566
567                                                 if (b2 != 15)
568                                                         my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
569
570                                                 sc_addr++;
571
572                                                 if (b1 != 15)
573                                                         my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
574                                         }
575                                 }
576 #else
577                                 DrawSpriteBlock2(sprnum, x, y, 30, 14, -2);
578 #endif
579                         }
580
581 #if 0
582                         for(uint16_t sy=0; sy<16; sy++)
583                         {
584                                 for(uint16_t sx=14; sx!=0xFFFE; sx-=2)
585                                 {
586                                         uint8_t b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
587                                         uint16_t spy = y + sy, spx = x + sx;
588
589 //                                      if ((spy > 223) || (spx > 299))
590                                         if ((spy > 223) || (spx > 287))
591                                                 sc_addr = 0x13FFE;
592                                         else
593 //                                              sc_addr = spx + spy * 320;
594                                                 sc_addr = spx + (spy * 288);
595
596                                         if (b2 != 15)
597                                                 my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
598
599                                         sc_addr++;
600
601                                         if (b1 != 15)
602                                                 my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
603                                 }
604                         }
605 #else
606                         DrawSpriteBlock2(sprnum, x, y, 14, 0xFFFE, -2);
607 #endif
608                 }
609         }
610 }
611
612
613 int FindPCXName(void)
614 {
615         static int pcxNum = -1; // This needs to go elsewhere... (or does it?)
616         char filename[30];
617         FILE * fr;
618
619         pcxNum++;
620
621         while (pcxNum < 10000)
622         {
623                 sprintf(filename, "thnd%04i.pcx", pcxNum);
624
625                 // file does not exist - we can create it
626                 if ((fr = fopen(filename, "r")) == NULL)
627                         return pcxNum;
628
629                 pcxNum++;
630         }
631
632         return -1;
633 }
634
635
636 void SnapPCX(SDL_Surface * scr)
637 {
638         char filename[30];
639         int i, line;
640         FILE * fw;
641         int XMax = 319;       // Need to adjust this to handle 288 bytes per line
642         int YMax = 223;
643         int bytesPerLine = 320;
644
645         // Return if failed...
646         if ((i = FindPCXName()) < 0)
647                 return;
648
649         sprintf(filename, "thnd%04i.pcx", i);
650
651         if ((fw = fopen(filename, "wb")) == NULL)
652                 return;  // failed...
653
654         // Write the header
655
656         fputc(0xA, fw); // pcx signature
657         fputc(0x5, fw); // version 5
658         fputc(0x1, fw); // RLE encoding
659         fputc(0x8, fw); // bits per pixel
660         fputc(0, fw);
661         fputc(0, fw);
662         fputc(0, fw);
663         fputc(0, fw); // XMin=0,YMin=0
664         fputc(XMax & 0xFF, fw);
665         fputc(XMax >> 8, fw);
666         fputc(YMax & 0xFF, fw);
667         fputc(YMax >> 8, fw);
668         fputc(0, fw);
669         fputc(0, fw);
670         fputc(0, fw);
671         fputc(0,fw); // unknown DPI
672
673         for (i=0; i<48; i++)
674                 fputc(0, fw);                 // EGA color palette
675
676         fputc(0, fw); // reserved
677         fputc(1, fw); // number of bit planes
678         fputc(bytesPerLine & 0xFF, fw);
679         fputc(bytesPerLine >> 8, fw);
680         fputc(1, fw);
681         fputc(0, fw); // palette info - unused
682         fputc((XMax + 1) & 0xFF, fw);
683         fputc((XMax + 1) >> 8, fw);
684         fputc((YMax + 1) & 0xFF, fw);
685         fputc((YMax + 1) >> 8, fw); // screen resolution
686
687         for (i=0; i<54; i++)
688                 fputc(0, fw); // unused
689
690         // Instead of using the screen, we should use our internal buffer...
691         SDL_LockSurface(scr);
692
693         uint32_t mem = scr->pitch * 8; // Skip first line... WAS:320*8;
694
695         for (line=0; line<=YMax; line++)
696         {
697                 int count;
698                 int last;
699                 int xpos;
700                 uint8_t * pMem = (uint8_t *)scr->pixels;
701
702                 xpos = 0;
703
704                 while (xpos < bytesPerLine)
705                 {
706                         last = pMem[mem++];
707                         xpos++;
708                         count = 1;
709
710                         while (pMem[mem] == last && xpos < bytesPerLine && count < 63)
711                         {
712                                 mem++;
713                                 count++;
714                                 xpos++;
715                         }
716
717                         if (count > 1 || (last & 0xC0) == 0xC0)
718                         {
719                                 fputc(0xC0 | (count & 0x3F), fw);
720                                 fputc(last & 0xFF, fw);
721                         }
722                         else
723                                 fputc(last & 0xFF, fw);
724                 }
725
726                 mem += (scr->pitch - 320);  // Handle non-standard line lengths...
727         }
728
729         SDL_UnlockSurface(scr);
730
731         // Write the palette
732         fputc(0x0C, fw);
733
734         for (i=0; i<768; i++)
735                 fputc(palette[i], fw);
736
737         fclose(fw);    // success!
738 }
739