|
|
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.