]> Shamusworld >> Repos - thunder/blob - src/screen.cpp
353229fb8e3d1cff2416828a5739dc27e97df0e5
[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 L. Hammons
9 //
10 // (C) 2003 Underground Software
11 //
12 // JLH = James L. Hammons <jlhamm@acm.org>
13 //
14 // Who  When        What
15 // ---  ----------  ------------------------------------------------------------
16 // JLH  03/12/2003  Ported this crud to Simple Directmedia Layer
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
26 // Private function prototypes
27
28 void DrawSprites(uint8 priority);
29 int FindPCXName(void);
30
31 // Private global variables
32
33 uint8 my_scr[0x14000];                                                                  // Screen buffer...
34 uint8 palette[768];                                                                             // Screen palette
35 uint8 ccolor[256][8];                                                                   // Character colors
36 uint8 scolor[128][16];                                                                  // Sprite colors
37 bool charbase;                                                                                  // Character base pointer...
38 uint8 hScrollOffset;                                                                            // Horizontal scroll offset
39 uint8 vScrollOffset;                                                                            // Vertical scroll offset
40 uint8 spr_color_index;                                                                  // Sprite color index
41 uint32 offsets[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };                 // Scroll offsets...
42 uint32 voffsets[8] = { 0, 320, 640, 960, 1280, 1600, 1920, 2240 };
43
44 extern bool show_text;                                                                  // Whether or not to show text
45 extern bool show_scr;                                                                   // Whether or not to show screen
46
47 //
48 // Render the NAMCO screen
49 //
50 void BlitChar(SDL_Surface * scr, uint8 * chr, uint8 * ram)
51 {
52         if (show_scr)
53         {
54                 int sx, sy;
55                 uint32 sc_base = ((ram[0x9000] << 8) | ram[0x9001]) + 4;        // Adjust hscroll val
56                 hScrollOffset = sc_base & 0x07;                                 // Horiz. scroll offset
57                 sc_base = (sc_base & 0xFFF8) >> 2;                              // Skip odds..
58                 uint8 vsc_base = ((ram[0x9002] + 1) & 0xF8) >> 3;// Vertical scroll addr adjust
59                 vScrollOffset = ((ram[0x9002] + 1) & 0x07);             // Vertical fine scroll amount
60                 uint32 scp1 = 0x0180 | ((sc_base + 0x04) & 0x7F);       /*0x0188;*/
61                 uint32 scp2 = 0x1180 | ((sc_base + 0x04) & 0x7F);       /*0x1188;*/
62                 uint32 scp3 = 0x2180 | ((sc_base + 0x04) & 0x7F);       /*0x2188;*/
63                 uint32 scp = 0x3208;
64                 scp1 += vsc_base * 0x80;
65                 scp1 &= 0x0FFF;                                                                 // Set vertical scroll addr
66                 scp2 += vsc_base * 0x80;
67                 scp2 = 0x1000 | (scp2 & 0x0FFF);                                // Set vertical scroll addr
68                 scp3 += vsc_base * 0x80;
69                 scp3 = 0x2000 | (scp3 & 0x0FFF);                                // Set vertical scroll addr
70
71                 uint32 chBaseOffset = (charbase ? 0x20000 : 0x00000);
72
73                 for(sy=0; sy<29; sy++)
74                 {
75                         for(sx=0; sx<37; sx++)
76                         {
77                                 uint8 scp_lo = (scp1 + (sx << 1)) & 0x7F;// Let LO byte wrap only...
78                                 uint16 sp2 = (scp1 & 0xFF80) | scp_lo;
79                                 uint8 tile  = ram[sp2++];
80                                 uint8 index = ram[sp2] & 0x03;
81                                 uint8 color = ram[sp2];
82                                 uint32 chind = chBaseOffset + (((index << 8) + tile) * 64);
83                                 uint32 sc_addr = (sx * 8) + (sy * 2560);        // Start addr in my_scr[]
84
85                                 for(int y=0; y<8; y++)
86                                 {
87                                         for(int x=0; x<8; x++)
88                                                 my_scr[sc_addr++] = ccolor[color][chr[chind++]];
89
90                                         sc_addr += 312;                                         // Do next line...
91                                 }
92                         }
93
94                         scp1 += 0x80;
95                         scp1 = 0x0000 | (scp1 & 0x0FFF);
96                 }
97
98                 DrawSprites(0x40);                                                              // Draw sprites at lowest layer...
99
100                 chBaseOffset = (charbase ? 0x30000 : 0x10000);
101
102                 for(sy=0; sy<29; sy++)
103                 {
104                         for(sx=0; sx<37; sx++)
105                         {
106                                 uint8 scp_lo = (scp2 + (sx << 1)) & 0x7F;  // Let LO byte wrap only...
107                                 uint16 sp2 = (scp2 & 0xFF80) | scp_lo;
108                                 uint8 tile   = ram[sp2++];
109                                 uint8 index  = ram[sp2] & 0x03;
110                                 uint8 color  = ram[sp2];
111                                 uint32 chind = chBaseOffset + (((index << 8) + tile) * 64);
112                                 uint32 sc_addr = (sx * 8) + (sy * 2560); // Start addr in my_scr[]
113
114                                 for(int y=0; y<8; y++)
115                                 {
116                                         for(int x=0; x<8; x++)
117                                         {
118                                                 if (chr[chind] != 7)
119                                                         my_scr[sc_addr] = ccolor[color][chr[chind]];
120
121                                                 sc_addr++;
122                                                 chind++;
123                                         }
124
125                                         sc_addr += 312;                                         // Do next line...
126                                 }
127                         }
128
129                         scp2 += 0x80;
130                         scp2 = 0x1000 | (scp2 & 0x0FFF);
131                 }
132
133                 DrawSprites(0x80);                                                              // Draw sprites under layer #2...
134
135                 for(sy=0; sy<29; sy++)
136                 {
137                         for(sx=0; sx<37; sx++)
138                         {
139                                 uint8 scp_lo = (scp3 + (sx << 1)) & 0x7F;  // Let LO byte wrap only...
140                                 uint16 sp2 = (scp3 & 0xFF80) | scp_lo;
141                                 uint8 tile  = ram[sp2++];
142                                 uint8 index = ram[sp2] & 0x03;
143                                 uint8 color = ram[sp2];
144                                 uint32 chind = 0x40000 + (((index << 8) + tile) * 64);
145                                 uint32 sc_addr = (sx * 8) + (sy * 2560); // Start addr in my_scr[]
146
147                                 for(int y=0; y<8; y++)
148                                 {
149                                         for(int x=0; x<8; x++)
150                                         {
151                                                 if (chr[chind] != 7)
152                                                         my_scr[sc_addr] = ccolor[color][chr[chind]];
153
154                                                 sc_addr++;
155                                                 chind++;
156                                         }
157
158                                         sc_addr += 312;  // Do next line...
159                                 }
160                         }
161
162                         scp3 += 0x80;  scp3 = 0x2000|(scp3&0x0FFF);
163                 }
164
165                 DrawSprites(0xC0);                                                              // Draw highest priority sprites...
166
167                 for(sy=0; sy<28; sy++)
168                 {
169                         for(sx=0; sx<36; sx++)
170                         {
171                                 uint16 sp2 = scp + (sx << 1);
172                                 uint8 tile  = ram[sp2++];
173                                 uint8 index = ram[sp2] & 0x03;
174                                 uint8 color = ram[sp2];
175                                 uint32 chind = 0x50000 + (((index << 8) + tile) * 64);
176                                 uint32 sc_addr = (sx * 8) + (sy * 2560) + hScrollOffset + voffsets[vScrollOffset];      // Start addr in my_scr[]
177
178                                 for(int y=0; y<8; y++)
179                                 {
180                                         for(int x=0; x<8; x++)
181                                         {
182                                                 if (chr[chind] != 7)
183                                                         my_scr[sc_addr] = ccolor[color][chr[chind]];
184
185                                                 sc_addr++;
186                                                 chind++;
187                                         }
188
189                                         sc_addr += 312;                                         // Do next line of char...
190                                 }
191                         }
192
193                         scp += 0x80;
194                 }
195         }
196
197         if (show_text)
198                 DrawText();                                                                             // Draw a msg if needed...
199
200         if (ShowGUI())
201                 DrawGUI();                                                                              // Show GUI if active...
202
203         if (SDL_LockSurface(scr) < 0)
204         {
205 //              fprintf(stderr, "Couldn't lock the display surface: %s\n", SDL_GetError());
206 //              exit(2);
207         }
208
209         // Screen size is 288 x 224
210
211         // Fast blit
212 /*      for(int i=0; i<224; i++)
213         {
214                 memcpy((char *)scr->pixels + scr->pitch * i,
215                         my_scr + (uint32)(offsets[hScrollOffset]+voffsets[vScrollOffset]) + i * 320, 320);
216         }//*/
217
218         // Doubled pixel blit (should be faster now!)
219         uint8 * pMem = (uint8 *)scr->pixels + ((scr->pitch * 8 + 16) * 2);
220         uint32 src = (uint32)(offsets[hScrollOffset] + voffsets[vScrollOffset]),
221                 dst1 = 0, dst2 = scr->pitch;
222         uint32 srcAdd = 320 - 288, dstAdd = (scr->pitch * 2) - (288 * 2);
223
224         for(int i=0; i<224; i++)
225         {
226                 for (int j=0; j<288; j++)
227                 {
228                         pMem[dst1] = pMem[dst1 + 1] = pMem[dst2] = pMem[dst2 + 1] = my_scr[src++];
229                         dst1 += 2;
230                         dst2 += 2;
231                 }
232
233                 src += srcAdd;
234                 dst1 += dstAdd;
235                 dst2 += dstAdd;
236         }//*/
237
238         // Scanlined pixel blit
239 /*      uint8 * pMem = (uint8 *)scr->pixels + ((scr->pitch * 8 + 16) * 2);
240         uint32 src = (uint32)(offsets[hScrollOffset] + voffsets[vScrollOffset]),
241                 dst1 = 0, dst2 = scr->pitch;
242         uint32 srcAdd = 320 - 288, dstAdd = (scr->pitch * 2) - (288 * 2);
243
244         for(int i=0; i<224; i++)
245         {
246                 for (int j=0; j<288; j++)
247                 {
248                         pMem[dst1] = pMem[dst1 + 1] = pMem[dst2] = my_scr[src++];
249                         dst1 += 2;
250                         dst2 += 2;
251                 }
252
253                 src += srcAdd;
254                 dst1 += dstAdd;
255                 dst2 += dstAdd;
256         }//*/
257
258         SDL_UnlockSurface(scr);
259         SDL_UpdateRect(scr, 0, 0, 0, 0);
260 }
261
262 //
263 // Draw sprites at priority level (new code)
264 //
265 void DrawSprites(uint8 priority)
266 {
267         extern uint8 * gram1;                                                           // Game RAM space
268
269         for(uint16 i=0x5800; i<0x6000; i+=0x10)
270         {
271                 if ((gram1[i + 8] & 0xC0) == priority)                  // Check for correct layer...
272                 {
273                         spr_color_index = gram1[i + 6] >> 1;            // Set color...
274                         uint16 x = ((gram1[i + 6] & 0x01) << 8) | gram1[i + 7];
275
276                         if (x > 512 - 32)
277                                 x -= 512;                                                               // Handle neg x values
278
279                         uint16 y = 192 - gram1[i + 9];
280                         uint16 hdr = (gram1[i + 4] & 0x90) << 8 | (gram1[i + 8] & 0x14);
281                         uint8 flip = gram1[i + 4] & 0x20;                       // Horizontal flip
282                         uint32 spr_num = ((gram1[i + 4] & 0x07) << 9) | ((gram1[i + 5] & 0x7F) << 2);
283
284                         Sprite(spr_num, x, y, flip, hdr);                       // Draw sprite...
285                 }
286         }
287 }
288
289 //
290 // Sprite handler
291 //
292 void Sprite(uint32 sprnum, uint16 x, uint16 y, uint8 flip, uint16 spr_id)
293 {
294         extern uint8 * spr_rom;
295         // To show or not to show a 16x16 block in the 4x4 grid...
296         bool horiz_bl = false, vert_bl = false;
297         uint32 sc_addr;
298
299         x += hScrollOffset;                                                                     // Adjust x-coord
300         y += vScrollOffset;                                                                     // Adjust y-coord
301
302         if (spr_id == 0x8004)
303         {
304                 horiz_bl = true;  vert_bl = true;
305         }
306         if (spr_id == 0x8000)
307         {
308                 horiz_bl = true;  y += 16;
309         }
310         if (spr_id == 0x8010)
311         {
312                 horiz_bl = true;  y += 16;  sprnum += 2;
313         }
314         if (spr_id == 0x0004)
315         {
316                 vert_bl = true;
317         }
318         if (spr_id == 0x1004)
319         {
320                 vert_bl = true;  sprnum++;
321         }
322         if (spr_id == 0x0000)
323         {
324                 y += 16;
325         }
326         if (spr_id == 0x1000)
327         {
328                 y += 16;  sprnum++;
329         }
330         if (spr_id == 0x0010)
331         {
332                 y += 16;  sprnum += 2;
333         }
334         if (spr_id == 0x1010)
335         {
336                 y += 16;  sprnum += 3;
337         }
338
339         sprnum <<= 7;                                                                   // 128 bytes per sprite
340
341         if (!flip)
342         {
343                 for(uint16 sy=0; sy<16; sy++)
344                 {
345                         for(uint16 sx=0; sx<16; sx+=2)
346                         {
347                                 uint8 b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
348                                 uint16 spy = y + sy, spx = x + sx;      // Need to optimize this clipping!
349
350                                 if (spy > 223 || spx > 299)
351                                         sc_addr = 0x13FFE;
352                                 else
353                                         sc_addr = spx + spy * 320;
354
355                                 if (b1 != 15)
356                                         my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
357
358                                 sc_addr++;
359
360                                 if (b2 != 15)
361                                         my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
362                         }
363                 }
364
365                 if (horiz_bl)
366                 {
367                         for(uint16 sy=0; sy<16; sy++)
368                         {
369                                 for(uint16 sx=16; sx<32; sx+=2)
370                                 {
371                                         uint8 b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
372                                         uint16 spy = y + sy, spx = x + sx;
373
374                                         if (spy > 223 || spx > 299)
375                                                 sc_addr = 0x13FFE;
376                                         else
377                                                 sc_addr = spx + spy * 320;
378
379                                         if (b1 != 15)
380                                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
381
382                                         sc_addr++;
383
384                                         if (b2 != 15)
385                                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
386                                 }
387                         }
388                 }
389                 else
390                         sprnum += 128;                                                          // Advance to next...
391
392                 if (vert_bl)
393                 {
394                         y += 16;                                                                        // Do next row...
395
396                         for(uint16 sy=0; sy<16; sy++)
397                         {
398                                 for(uint16 sx=0; sx<16; sx+=2)
399                                 {
400                                         uint8 b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
401                                         uint16 spy = y + sy, spx = x + sx;
402
403                                         if (spy > 223 || spx > 299)
404                                                 sc_addr = 0x13FFE;
405                                         else
406                                                 sc_addr = spx + spy * 320;
407
408                                         if (b1 != 15)
409                                                 my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
410
411                                         sc_addr++;
412
413                                         if (b2 != 15)
414                                                 my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
415                                 }
416                         }
417
418                         if (horiz_bl)
419                         {
420                                 for(uint16 sy=0; sy<16; sy++)
421                                 {
422                                         for(uint16 sx=16; sx<32; sx+=2)
423                                         {
424                                                 uint8 b1 = spr_rom[sprnum] >> 4, b2 = spr_rom[sprnum++] & 0x0F;
425                                                 uint16 spy = y + sy, spx = x + sx;
426
427                                                 if (spy > 223 || spx > 299)
428                                                         sc_addr = 0x13FFE;
429                                                 else
430                                                         sc_addr = spx + spy * 320;
431
432                                                 if (b1 != 15)
433                                                         my_scr[sc_addr] = scolor[spr_color_index][b1];  // Store it
434
435                                                 sc_addr++;
436
437                                                 if (b2 != 15)
438                                                         my_scr[sc_addr] = scolor[spr_color_index][b2];  // Store it
439                                         }
440                                 }
441                         }
442                 }
443         }
444         else    // Flip
445         {
446     if (horiz_bl)
447     {
448       for(uint16 sy=0; sy<16; sy++)
449       {
450         for(uint16 sx=30; sx!=14; sx-=2)
451         {
452           uint8 b1 = spr_rom[sprnum]>>4, b2 = spr_rom[sprnum++]&0x0F;
453         uint16 spy = y+sy, spx = x+sx;
454         if ((spy>223) || (spx>299))
455           sc_addr = 0x13FFE;
456         else
457           sc_addr = spx+spy*320;
458           if (b2 != 15)
459             my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
460           sc_addr++;
461           if (b1 != 15)
462             my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
463         }
464       }
465     }
466     for(uint16 sy=0; sy<16; sy++)
467     {
468       for(uint16 sx=14; sx!=0xFFFE; sx-=2)
469       {
470         uint8 b1 = spr_rom[sprnum]>>4, b2 = spr_rom[sprnum++]&0x0F;
471         uint16 spy = y+sy, spx = x+sx;
472         if ((spy>223) || (spx>299))
473           sc_addr = 0x13FFE;
474         else
475           sc_addr = spx+spy*320;
476         if (b2 != 15)
477           my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
478         sc_addr++;
479         if (b1 != 15)
480           my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
481       }
482     }
483     if (!horiz_bl)  sprnum += 128;  // If single, skip sprite...
484     if (vert_bl)
485     {
486       y += 16;      // Adjust Y coord...
487       if (horiz_bl)
488       {
489         for(uint16 sy=0; sy<16; sy++)
490         {
491           for(uint16 sx=30; sx!=14; sx-=2)
492           {
493             uint8 b1 = spr_rom[sprnum]>>4, b2 = spr_rom[sprnum++]&0x0F;
494         uint16 spy = y+sy, spx = x+sx;
495         if ((spy>223) || (spx>299))
496           sc_addr = 0x13FFE;
497         else
498           sc_addr = spx+spy*320;
499             if (b2 != 15)
500               my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
501             sc_addr++;
502             if (b1 != 15)
503                my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
504           }
505         }
506       }
507       for(uint16 sy=0; sy<16; sy++)
508       {
509         for(uint16 sx=14; sx!=0xFFFE; sx-=2)
510         {
511           uint8 b1 = spr_rom[sprnum]>>4, b2 = spr_rom[sprnum++]&0x0F;
512         uint16 spy = y+sy, spx = x+sx;
513         if ((spy>223) || (spx>299))
514           sc_addr = 0x13FFE;
515         else
516           sc_addr = spx+spy*320;
517           if (b2 != 15)
518             my_scr[sc_addr] = scolor[spr_color_index][b2]; // Store it
519           sc_addr++;
520           if (b1 != 15)
521             my_scr[sc_addr] = scolor[spr_color_index][b1]; // Store it
522         }
523       }
524     }
525   }
526 }
527
528 int FindPCXName()
529 {
530         static int pcxNum = -1;                                                         // This needs to go elsewhere... (or does it?)
531         char filename[30];
532         FILE * fr;
533
534         pcxNum++;
535
536         while (pcxNum < 10000)
537         {
538                 sprintf(filename, "thnd%04i.pcx", pcxNum);
539
540                 if ((fr = fopen(filename, "r")) == NULL)
541                         return pcxNum;                                                          // file does not exist - we can create it
542
543                 pcxNum++;
544         }
545
546         return -1;
547 }
548
549 void SnapPCX(SDL_Surface * scr)
550 {
551         char filename[30];
552         int i, line;
553         FILE * fw;
554         int XMax = 319;       // Need to adjust this to handle 288 bytes per line
555         int YMax = 223;
556         int bytesPerLine = 320;
557
558         if ((i = FindPCXName()) < 0)
559                 return;               // failed...
560
561         sprintf(filename, "thnd%04i.pcx", i);
562
563         if ((fw = fopen(filename, "wb")) == NULL)
564                 return;  // failed...
565
566         // Write the header
567
568         fputc(0xA, fw); // pcx signature
569         fputc(0x5, fw); // version 5
570         fputc(0x1, fw); // RLE encoding
571         fputc(0x8, fw); // bits per pixel
572         fputc(0, fw);  fputc(0, fw);  fputc(0, fw);  fputc(0, fw); // XMin=0,YMin=0
573         fputc(XMax&0xFF, fw);  fputc(XMax>>8, fw);
574         fputc(YMax&0xFF, fw);  fputc(YMax>>8, fw);
575         fputc(0, fw);  fputc(0, fw);  fputc(0, fw);  fputc(0,fw); // unknown DPI
576         for (i=0; i<48; i++)  fputc(0, fw);                 // EGA color palette
577         fputc(0, fw); // reserved
578         fputc(1, fw); // number of bit planes
579         fputc(bytesPerLine&0xFF, fw);  fputc(bytesPerLine>>8, fw);
580         fputc(1, fw);  fputc(0, fw); // palette info - unused
581         fputc((XMax+1)&0xFF, fw);  fputc((XMax+1)>>8, fw);
582         fputc((YMax+1)&0xFF, fw);  fputc((YMax+1)>>8, fw); // screen resolution
583         for (i=0; i<54; i++)  fputc(0, fw); // unused
584
585         // Instead of using the screen, we should use our internal buffer...
586         SDL_LockSurface(scr);
587
588         uint32 mem = scr->pitch * 8; // Skip first line... WAS:320*8;
589         for (line=0; line<=YMax; line++)
590         {
591                 int count;
592                 int last;
593                 int xpos;
594                 uint8 * pMem = (uint8 *)scr->pixels;
595
596                 xpos = 0;
597                 while (xpos < bytesPerLine)
598                 {
599                         last = pMem[mem++];
600                         xpos++;
601                         count = 1;
602                         while (pMem[mem] == last && xpos < bytesPerLine && count < 63)
603                         {
604                                 mem++;  count++;  xpos++;
605                         }
606
607                         if (count > 1 || (last&0xC0) == 0xC0)
608                         {
609                                 fputc(0xC0 | (count & 0x3F), fw);  fputc(last & 0xFF, fw);
610                         }
611                         else fputc(last & 0xFF, fw);
612                 }
613                 mem += (scr->pitch - 320);  // Handle non-standard line lengths...
614         }
615
616         SDL_UnlockSurface(scr);
617
618         // Write the palette
619
620         fputc(0x0C, fw);
621         for (i=0; i<768; i++)
622                 fputc(palette[i], fw);
623
624         fclose(fw);    // success!
625 }