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