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