|
|
1.1 root 1: /*
2: Hatari
3:
4: Handle storing of writes to ST palette using clock-cycle counts. We can use this to accurately any form
5: of Spectrum512 style images - even down to the way the screen colours change on decompression routines in menus!
6:
7: As the 68000 has a 4-clock cycle increment we can only change palette every 4 cycles. This means that on one
8: scanline(512 cycles) we have just 512/4=128 places where palette writes can take place. We keep track of
9: this in a table(storing on each scanline and colour writes and the cycles on the scanline where they happen).
10: When we draw the screen we simply keep a cycle-count on the line and check this with our table and update
11: the 16-colour palette with each change. As the table is already ordered this makes things very simple. Speed
12: is a problem, though, as the palette can change once every 4 pixels - that's a lot of processing.
13: */
14:
1.1.1.4 root 15: #include <SDL_byteorder.h>
16:
1.1 root 17: #include "main.h"
18: #include "debug.h"
19: #include "decode.h"
20: #include "int.h"
21: #include "screen.h"
22: #include "spec512.h"
23: #include "video.h"
24:
1.1.1.2 root 25:
26: CYCLEPALETTE CyclePalettes[(SCANLINES_PER_FRAME+1)*MAX_CYCLEPALETTES_PERLINE]; /* 314k; 1024-bytes per line */
1.1 root 27: CYCLEPALETTE *pCyclePalette;
1.1.1.2 root 28: int nCyclePalettes[(SCANLINES_PER_FRAME+1)]; /* Number of entries in above table for each scanline */
29: int nPalettesAccess[(SCANLINES_PER_FRAME+1)]; /* Number of times accessed palette register 'x' in this scan line */
1.1 root 30: unsigned short int CycleColour;
31: int CycleColourIndex;
32: int nScanLine, ScanLineCycleCount;
33: BOOL bIsSpec512Display;
1.1.1.5 ! root 34: int nb_spc512lines,last_spc512line;
1.1 root 35:
1.1.1.4 root 36: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
37: static const int STRGBPalEndianTable[16] = {0,2,1,3,8,10,9,11,4,6,5,7,12,14,13,15};
38: #endif
39:
1.1.1.2 root 40:
41: /*-----------------------------------------------------------------------*/
1.1 root 42: /*
43: Return TRUE if this frame is a Spectrum 512 style image(MUST be low res/non-mix)
44: */
45: BOOL Spec512_IsImage(void)
46: {
1.1.1.2 root 47: /* Normal Low res screen? */
1.1 root 48: if ( (STRes==ST_LOW_RES) && (bIsSpec512Display) )
49: return(TRUE);
50:
51: return(FALSE);
52: }
53:
1.1.1.2 root 54:
55: /*-----------------------------------------------------------------------*/
1.1 root 56: /*
57: We store every palette access in a table to perform Spectrum 512 colour effects
58: This is cleared on each VBL
59: */
60: void Spec512_StartVBL(void)
61: {
1.1.1.2 root 62: /* Clear number of cycle palettes on each frame */
1.1 root 63: memset(nCyclePalettes,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2 root 64: /* Clear number of times accessed on entry in palette (used to check if is true Spectrum 512 image) */
1.1.1.5 ! root 65: memset(nPalettesAccess,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2 root 66: /* Set as not Spectrum 512 displayed image */
1.1 root 67: bIsSpec512Display = FALSE;
1.1.1.5 ! root 68: last_spc512line = -1;
! 69: nb_spc512lines = 0;
1.1 root 70: }
71:
1.1.1.2 root 72:
73: /*-----------------------------------------------------------------------*/
1.1 root 74: /*
1.1.1.4 root 75: Store color into table 'CyclePalettes[]' for screen conversion according
76: to cycles into frame.
1.1 root 77: */
1.1.1.4 root 78: void Spec512_StoreCyclePalette(unsigned short col, unsigned long addr)
1.1 root 79: {
80: CYCLEPALETTE *pCyclePalette;
81: int FrameCycles,ScanLine;
82:
1.1.1.4 root 83: CycleColour = col;
84: CycleColourIndex = (addr-0xff8240)>>1;
85:
1.1.1.2 root 86: /* Find number of cycles into frame */
1.1 root 87: FrameCycles = Int_FindFrameCycles();
88:
1.1.1.2 root 89: /* Find scan line we are currently on and get index into cycle-palette table */
1.1 root 90: ScanLine = (FrameCycles/CYCLES_PER_LINE);
91: pCyclePalette = &CyclePalettes[ (ScanLine*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[ScanLine] ];
1.1.1.2 root 92: /* Do we have a previous entry at the same cycles? If so, 68000 have used a 'move.l' instruction so stagger writes */
1.1 root 93: if (nCyclePalettes[ScanLine]>0) {
94: if ((pCyclePalette-1)->LineCycles==(FrameCycles&511))
1.1.1.2 root 95: FrameCycles += 4; /* Colours are staggered by [4,20] when writing a long word! */
1.1 root 96: }
97:
1.1.1.2 root 98: /* Store palette access */
99: pCyclePalette->LineCycles = FrameCycles&511; /* Cycles into scanline */
100: pCyclePalette->Colour = CycleColour&0x777; /* Store ST colour RGB */
101: pCyclePalette->Index = CycleColourIndex; /* And Index (0...15) */
102: /* Increment count(this can never overflow as you cannot write to the palette more than 'MAX_CYCLEPALETTES_PERLINE' times per scanline) */
1.1 root 103: nCyclePalettes[ScanLine]++;
104:
1.1.1.2 root 105: /* Check if program wrote to certain palette entry multiple times on a single scan-line */
106: /* If we did then we must be using a Spectrum512 image or some kind of colour cycling... */
1.1 root 107: nPalettesAccess[ScanLine]++;
1.1.1.5 ! root 108: if (nPalettesAccess[ScanLine]>=32) {
! 109: /* This code has obviously something wrong. It detects the grav44 disk
! 110: demo as a spc512 image because the scroller at the bottom of the screen
! 111: uses more than 1 palette... But doing so, it ruins the colours of the
! 112: rest of the screen. I should review all this code, but later.
! 113: For now, I just make sure it chosses this mode only when most of the
! 114: screen is a spc512 screen (at least 150 lines ! */
! 115: if (last_spc512line != ScanLine) {
! 116: last_spc512line = ScanLine;
! 117: nb_spc512lines++;
! 118: if (nb_spc512lines >= 150)
! 119: bIsSpec512Display = TRUE;
! 120: }
! 121: }
1.1 root 122: }
123:
1.1.1.2 root 124:
125: /*-----------------------------------------------------------------------*/
1.1 root 126: /*
1.1.1.5 ! root 127: Begin palette calculation for Spectrum 512 style images,
1.1 root 128: */
129: void Spec512_StartFrame(void)
130: {
131: int i;
132:
1.1.1.2 root 133: /* Set so screen gets full-update when returns from Spectrum 512 display */
1.1 root 134: Screen_SetFullUpdate();
135:
1.1.1.2 root 136: /* Set terminators on each line, so when scan during conversion we know when to stop */
1.1.1.4 root 137: for(i=0; i<(SCANLINES_PER_FRAME+1); i++)
138: {
1.1 root 139: pCyclePalette = &CyclePalettes[ (i*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[i] ];
1.1.1.2 root 140: pCyclePalette->LineCycles = -1; /* Term */
1.1 root 141: }
142:
1.1.1.2 root 143: /* Copy first line palette, kept in 'HBLPalettes' and store to 'STRGBPalette' */
1.1 root 144: for(i=0; i<16; i++)
1.1.1.4 root 145: {
146: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.5 ! root 147: STRGBPalette[STRGBPalEndianTable[i]] = ST2RGB[pHBLPalettes[i]&0x777];
1.1.1.4 root 148: #else
1.1.1.5 ! root 149: STRGBPalette[i] = ST2RGB[pHBLPalettes[i]&0x777];
1.1.1.4 root 150: #endif
151: }
1.1 root 152:
1.1.1.2 root 153: /* Ready for first call to 'Spec512_ScanLine' */
1.1 root 154: nScanLine = 0;
1.1.1.5 ! root 155: if (OverscanMode & OVERSCANMODE_TOP)
! 156: nScanLine += OVERSCAN_TOP;
1.1 root 157:
1.1.1.2 root 158: /* Skip to first line(where start to draw screen from) */
1.1 root 159: for (i=0; i<(STScreenStartHorizLine+(nStartHBL-OVERSCAN_TOP)); i++)
160: Spec512_ScanWholeLine();
161: }
162:
1.1.1.2 root 163:
164: /*-----------------------------------------------------------------------*/
1.1 root 165: /*
166: Scan whole line and build up palette - need to do this so when get to screen line we have
167: the correct 16 colours set
168: */
169: void Spec512_ScanWholeLine(void)
170: {
1.1.1.2 root 171: /* Store pointer to line of palette cycle writes */
1.1 root 172: pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 root 173: /* Ready for next scan line */
1.1 root 174: nScanLine++;
175:
1.1.1.2 root 176: /* Update palette entries until we reach start of displayed screen */
1.1 root 177: ScanLineCycleCount = 0;
1.1.1.2 root 178: Spec512_EndScanLine(); /* Read whole line of palettes and update 'STRGBPalette' */
1.1 root 179: }
180:
1.1.1.2 root 181:
182: /*-----------------------------------------------------------------------*/
1.1 root 183: /*
184: Build up palette for this scan line and store in 'ScanLinePalettes'
185: */
186: void Spec512_StartScanLine(void)
187: {
188: int i;
189:
1.1.1.2 root 190: /* Store pointer to line of palette cycle writes */
1.1 root 191: pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 root 192: /* Ready for next scan line */
1.1 root 193: nScanLine++;
194:
1.1.1.2 root 195: /* Update palette entries until we reach start of displayed screen */
1.1 root 196: ScanLineCycleCount = 0;
1.1.1.2 root 197: for(i=0; i<((SCREEN_START_CYCLE-8)/4); i++) /* This '8' is as we've already added in the 'move' instruction timing */
198: Spec512_UpdatePaletteSpan(); /* Update palette for this 4-cycle period */
199: /* And skip for left border is not using overscan display to user */
200: for (i=0; i<(STScreenLeftSkipBytes/2); i++) /* Eg, 16 bytes = 32 pixels or 8 palette periods */
1.1 root 201: Spec512_UpdatePaletteSpan();
202: }
203:
1.1.1.2 root 204:
205: /*-----------------------------------------------------------------------*/
1.1 root 206: /*
207: Run to end of scan line looking up palettes so 'STRGBPalette' is up-to-date
208: */
209: void Spec512_EndScanLine(void)
210: {
1.1.1.2 root 211: /* Continue to reads palette until complete so have correct version for next line */
1.1 root 212: while(ScanLineCycleCount<CYCLES_PER_LINE)
213: Spec512_UpdatePaletteSpan();
214: }
215:
1.1.1.2 root 216:
217: /*-----------------------------------------------------------------------*/
1.1 root 218: /*
219: Update palette for 4-pixels span, storing to 'STRGBPalette'
220: */
221: void Spec512_UpdatePaletteSpan(void)
222: {
1.1.1.2 root 223: if( pCyclePalette->LineCycles == ScanLineCycleCount )
224: {
225: /* Need to update palette with new entry */
1.1.1.4 root 226: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
227: STRGBPalette[STRGBPalEndianTable[pCyclePalette->Index]] = ST2RGB[pCyclePalette->Colour&0x777];
228: #else
1.1.1.2 root 229: STRGBPalette[pCyclePalette->Index] = ST2RGB[pCyclePalette->Colour&0x777];
1.1.1.4 root 230: #endif
1.1.1.2 root 231: pCyclePalette += 1;
232: }
233: ScanLineCycleCount += 4; /* Next 4 cycles */
1.1 root 234: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.