|
|
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:
15: #include "main.h"
16: #include "debug.h"
17: #include "decode.h"
18: #include "int.h"
19: #include "screen.h"
20: #include "spec512.h"
21: #include "video.h"
22:
1.1.1.2 root 23:
24: CYCLEPALETTE CyclePalettes[(SCANLINES_PER_FRAME+1)*MAX_CYCLEPALETTES_PERLINE]; /* 314k; 1024-bytes per line */
1.1 root 25: CYCLEPALETTE *pCyclePalette;
1.1.1.2 root 26: int nCyclePalettes[(SCANLINES_PER_FRAME+1)]; /* Number of entries in above table for each scanline */
27: int nPalettesAccess[(SCANLINES_PER_FRAME+1)]; /* Number of times accessed palette register 'x' in this scan line */
1.1 root 28: unsigned short int CycleColour;
29: int CycleColourIndex;
30: int nScanLine, ScanLineCycleCount;
31: BOOL bIsSpec512Display;
32:
1.1.1.2 root 33:
34: /*-----------------------------------------------------------------------*/
1.1 root 35: /*
36: Return TRUE if this frame is a Spectrum 512 style image(MUST be low res/non-mix)
37: */
38: BOOL Spec512_IsImage(void)
39: {
1.1.1.2 root 40: /* Normal Low res screen? */
1.1 root 41: if ( (STRes==ST_LOW_RES) && (bIsSpec512Display) )
42: return(TRUE);
43:
44: return(FALSE);
45: }
46:
1.1.1.2 root 47:
48: /*-----------------------------------------------------------------------*/
1.1 root 49: /*
50: We store every palette access in a table to perform Spectrum 512 colour effects
51: This is cleared on each VBL
52: */
53: void Spec512_StartVBL(void)
54: {
1.1.1.2 root 55: /* Clear number of cycle palettes on each frame */
1.1 root 56: memset(nCyclePalettes,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2 root 57: /* Clear number of times accessed on entry in palette (used to check if is true Spectrum 512 image) */
1.1 root 58: memset(nPalettesAccess,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2 root 59: /* Set as not Spectrum 512 displayed image */
1.1 root 60: bIsSpec512Display = FALSE;
61: }
62:
1.1.1.2 root 63:
64: /*-----------------------------------------------------------------------*/
1.1 root 65: /*
66: Store 'bx' colour into 'CyclePalettes[]' according to cycles into frame
67: Address is passed in 'ecx', eg 0xff8240
68: */
69: void Spec512_StoreCyclePalette_Execute(void)
70: {
71: CYCLEPALETTE *pCyclePalette;
72: int FrameCycles,ScanLine;
73:
1.1.1.2 root 74: /* Find number of cycles into frame */
1.1 root 75: FrameCycles = Int_FindFrameCycles();
76:
1.1.1.2 root 77: /* Find scan line we are currently on and get index into cycle-palette table */
1.1 root 78: ScanLine = (FrameCycles/CYCLES_PER_LINE);
79: pCyclePalette = &CyclePalettes[ (ScanLine*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[ScanLine] ];
1.1.1.2 root 80: /* 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 81: if (nCyclePalettes[ScanLine]>0) {
82: if ((pCyclePalette-1)->LineCycles==(FrameCycles&511))
1.1.1.2 root 83: FrameCycles += 4; /* Colours are staggered by [4,20] when writing a long word! */
1.1 root 84: }
85:
1.1.1.2 root 86: /* Store palette access */
87: pCyclePalette->LineCycles = FrameCycles&511; /* Cycles into scanline */
88: pCyclePalette->Colour = CycleColour&0x777; /* Store ST colour RGB */
89: pCyclePalette->Index = CycleColourIndex; /* And Index (0...15) */
90: /* Increment count(this can never overflow as you cannot write to the palette more than 'MAX_CYCLEPALETTES_PERLINE' times per scanline) */
1.1 root 91: nCyclePalettes[ScanLine]++;
92:
1.1.1.2 root 93: /* Check if program wrote to certain palette entry multiple times on a single scan-line */
94: /* If we did then we must be using a Spectrum512 image or some kind of colour cycling... */
1.1 root 95: nPalettesAccess[ScanLine]++;
96: if (nPalettesAccess[ScanLine]>=32)
97: bIsSpec512Display = TRUE;
98: }
99:
100: void Spec512_StoreCyclePalette(unsigned short col, unsigned long addr)
101: {
102: CycleColour = col;
103: CycleColourIndex = (addr-0xff8240)>>1;
104: Spec512_StoreCyclePalette_Execute(); /* Store it in table for screen conversion */
105: }
106:
1.1.1.2 root 107:
108: /*-----------------------------------------------------------------------*/
1.1 root 109: /*
110: Begin palette calculation for Spectrum 512 style images,
111: */
112: void Spec512_StartFrame(void)
113: {
114: int i;
115:
1.1.1.2 root 116: /* Set so screen gets full-update when returns from Spectrum 512 display */
1.1 root 117: Screen_SetFullUpdate();
118:
1.1.1.2 root 119: /* Set terminators on each line, so when scan during conversion we know when to stop */
1.1 root 120: for(i=0; i<(SCANLINES_PER_FRAME+1); i++) {
121: pCyclePalette = &CyclePalettes[ (i*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[i] ];
1.1.1.2 root 122: pCyclePalette->LineCycles = -1; /* Term */
1.1 root 123: }
124:
1.1.1.2 root 125: /* Copy first line palette, kept in 'HBLPalettes' and store to 'STRGBPalette' */
1.1 root 126: for(i=0; i<16; i++)
127: STRGBPalette[i] = ST2RGB[HBLPalettes[i]&0x777];
128:
1.1.1.2 root 129: /* Ready for first call to 'Spec512_ScanLine' */
1.1 root 130: nScanLine = 0;
131:
1.1.1.2 root 132: /* Skip to first line(where start to draw screen from) */
1.1 root 133: for (i=0; i<(STScreenStartHorizLine+(nStartHBL-OVERSCAN_TOP)); i++)
134: Spec512_ScanWholeLine();
135: }
136:
1.1.1.2 root 137:
138: /*-----------------------------------------------------------------------*/
1.1 root 139: /*
140: Scan whole line and build up palette - need to do this so when get to screen line we have
141: the correct 16 colours set
142: */
143: void Spec512_ScanWholeLine(void)
144: {
1.1.1.2 root 145: /* Store pointer to line of palette cycle writes */
1.1 root 146: pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 root 147: /* Ready for next scan line */
1.1 root 148: nScanLine++;
149:
1.1.1.2 root 150: /* Update palette entries until we reach start of displayed screen */
1.1 root 151: ScanLineCycleCount = 0;
1.1.1.2 root 152: Spec512_EndScanLine(); /* Read whole line of palettes and update 'STRGBPalette' */
1.1 root 153: }
154:
1.1.1.2 root 155:
156: /*-----------------------------------------------------------------------*/
1.1 root 157: /*
158: Build up palette for this scan line and store in 'ScanLinePalettes'
159: */
160: void Spec512_StartScanLine(void)
161: {
162: int i;
163:
1.1.1.2 root 164: /* Store pointer to line of palette cycle writes */
1.1 root 165: pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 root 166: /* Ready for next scan line */
1.1 root 167: nScanLine++;
168:
1.1.1.2 root 169: /* Update palette entries until we reach start of displayed screen */
1.1 root 170: ScanLineCycleCount = 0;
1.1.1.2 root 171: for(i=0; i<((SCREEN_START_CYCLE-8)/4); i++) /* This '8' is as we've already added in the 'move' instruction timing */
172: Spec512_UpdatePaletteSpan(); /* Update palette for this 4-cycle period */
173: /* And skip for left border is not using overscan display to user */
174: for (i=0; i<(STScreenLeftSkipBytes/2); i++) /* Eg, 16 bytes = 32 pixels or 8 palette periods */
1.1 root 175: Spec512_UpdatePaletteSpan();
176: }
177:
1.1.1.2 root 178:
179: /*-----------------------------------------------------------------------*/
1.1 root 180: /*
181: Run to end of scan line looking up palettes so 'STRGBPalette' is up-to-date
182: */
183: void Spec512_EndScanLine(void)
184: {
1.1.1.2 root 185: /* Continue to reads palette until complete so have correct version for next line */
1.1 root 186: while(ScanLineCycleCount<CYCLES_PER_LINE)
187: Spec512_UpdatePaletteSpan();
188: }
189:
1.1.1.2 root 190:
191: /*-----------------------------------------------------------------------*/
1.1 root 192: /*
193: Update palette for 4-pixels span, storing to 'STRGBPalette'
194: */
195: void Spec512_UpdatePaletteSpan(void)
196: {
1.1.1.2 root 197: if( pCyclePalette->LineCycles == ScanLineCycleCount )
198: {
199: /* Need to update palette with new entry */
200: STRGBPalette[pCyclePalette->Index] = ST2RGB[pCyclePalette->Colour&0x777];
201: pCyclePalette += 1;
202: }
203: ScanLineCycleCount += 4; /* Next 4 cycles */
1.1 root 204: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.