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