|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - video.c
3:
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: Video hardware handling. This code handling all to do with the video chip.
! 8: So, we handle VBLs, HBLs, copying the ST screen to a buffer to simulate the
! 9: TV raster trace, border removal, palette changes per HBL, the 'video address
! 10: pointer' etc...
1.1 root 11: */
1.1.1.7 ! root 12: char Video_rcsid[] = "Hatari $Id: video.c,v 1.24 2004/06/11 10:04:46 thothy Exp $";
1.1 root 13:
1.1.1.4 root 14: #include <SDL.h>
1.1.1.7 ! root 15: #include <SDL_endian.h>
1.1.1.4 root 16:
1.1 root 17: #include "main.h"
18: #include "debug.h"
1.1.1.6 root 19: #include "configuration.h"
1.1 root 20: #include "fdc.h"
21: #include "int.h"
22: #include "ikbd.h"
1.1.1.4 root 23: #include "keymap.h"
1.1 root 24: #include "m68000.h"
25: #include "memAlloc.h"
26: #include "memorySnapShot.h"
27: #include "mfp.h"
28: #include "screen.h"
29: #include "shortcut.h"
30: #include "sound.h"
31: #include "spec512.h"
32: #include "stMemory.h"
33: #include "vdi.h"
34: #include "video.h"
35: #include "ymFormat.h"
1.1.1.4 root 36:
37:
1.1 root 38: long VideoAddress; /* Address of video display in ST screen space */
1.1.1.7 ! root 39: unsigned char VideoShifterByte; /* VideoShifter (0xff8260) value store in video chip */
1.1.1.2 root 40: BOOL bUseHighRes = FALSE; /* Use hi-res (ie Mono monitor) */
1.1 root 41: int nVBLs, nHBL; /* VBL Counter, HBL line */
42: int nStartHBL,nEndHBL; /* Start/End HBL for visible screen(64 lines in Top border) */
43: int OverscanMode; /* OVERSCANMODE_xxxx for current display frame */
44: unsigned short int HBLPalettes[(NUM_VISIBLE_LINES+1)*16]; /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
45: unsigned long HBLPaletteMasks[NUM_VISIBLE_LINES+1]; /* Bit mask of palette colours changes, top bit set is resolution change */
46: unsigned short int *pHBLPalettes; /* Pointer to current palette lists, one per HBL */
47: unsigned long *pHBLPaletteMasks;
48: unsigned long VideoBase; /* Base address in ST Ram for screen(read on each VBL) */
49: unsigned long VideoRaster; /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
50: int SyncHandler_Value; /* Value to pass to 'Video_SyncHandler_xxxx' functions */
51: int LeftRightBorder; /* BORDERMASK_xxxx used to simulate left/right border removal */
1.1.1.6 root 52: int VBLCounter; /* VBL counter */
53: int nScreenRefreshRate = 50; /* 50 or 60 Hz in color, 70 Hz in mono */
1.1 root 54:
55:
56: /*-----------------------------------------------------------------------*/
57: /*
58: Reset video chip
59: */
60: void Video_Reset(void)
61: {
62: /* NOTE! Must reset all of these register type things here!!!! */
1.1.1.7 ! root 63:
1.1 root 64: /* Are we in high-res? */
65: if (bUseHighRes)
66: VideoShifterByte = ST_HIGH_RES; /* Boot up for mono monitor */
67: else
68: VideoShifterByte = ST_LOW_RES;
1.1.1.4 root 69: if(bUseVDIRes)
70: VideoShifterByte = VDIRes;
1.1 root 71:
72: /* Reset VBL counter */
73: nVBLs = 0;
74: /* Reset addresses */
75: VideoBase = 0L;
76: /* Clear ready for new VBL */
77: Video_ClearOnVBL();
78: }
79:
80: /*-----------------------------------------------------------------------*/
81: /*
82: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
83: */
84: void Video_MemorySnapShot_Capture(BOOL bSave)
85: {
86: /* Save/Restore details */
87: MemorySnapShot_Store(&VideoAddress,sizeof(VideoAddress));
88: MemorySnapShot_Store(&VideoShifterByte,sizeof(VideoShifterByte));
89: MemorySnapShot_Store(&bUseHighRes,sizeof(bUseHighRes));
90: MemorySnapShot_Store(&nVBLs,sizeof(nVBLs));
91: MemorySnapShot_Store(&nHBL,sizeof(nHBL));
92: MemorySnapShot_Store(&nStartHBL,sizeof(nStartHBL));
93: MemorySnapShot_Store(&nEndHBL,sizeof(nEndHBL));
94: MemorySnapShot_Store(&OverscanMode,sizeof(OverscanMode));
95: MemorySnapShot_Store(HBLPalettes,sizeof(HBLPalettes));
96: MemorySnapShot_Store(HBLPaletteMasks,sizeof(HBLPaletteMasks));
97: MemorySnapShot_Store(&VideoBase,sizeof(VideoBase));
98: MemorySnapShot_Store(&VideoRaster,sizeof(VideoRaster));
99: }
100:
101: /*-----------------------------------------------------------------------*/
102: /*
103: Called on VBL, set registers ready for frame
104: */
105: void Video_ClearOnVBL(void)
106: {
107: /* New screen, so first HBL */
108: nHBL = 0;
109: nStartHBL = SCREEN_START_HBL;
110: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL;
111: OverscanMode = OVERSCANMODE_NONE;
112:
113: /* Get screen address pointer, align to 256 bytes(ie ignore lowest byte) */
114: VideoBase = (unsigned long)STMemory_ReadByte(0xff8201)<<16 | (unsigned long)STMemory_ReadByte(0xff8203)<<8;
115: VideoRaster = (unsigned long)STRam+VideoBase;
116: pSTScreen = pFrameBuffer->pSTScreen;
117:
118: Video_StartHBL();
119: Video_SetScreenRasters();
120: Spec512_StartVBL();
121: }
122:
123: /*-----------------------------------------------------------------------*/
124: /*
125: Calculate Video address pointer and store in 'VideoAddress'
126: */
127: void Video_CalculateAddress(void)
128: {
129: int X,Y,FrameCycles,nPixelsIn;
130:
131: /* Find number of cycles passed during frame */
132: FrameCycles = Int_FindFrameCycles();
133:
134: /* Top of screen is usually 64 lines from VBL(64x512=32768 cycles) */
135: if (FrameCycles<(nStartHBL*CYCLES_PER_LINE))
136: VideoAddress = 0;
137: else {
138: /* Now find which pixel we are on(ignore left/right borders) */
139: /* 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
140: nPixelsIn = FrameCycles-(nStartHBL*CYCLES_PER_LINE);
141: /* Convert this to an X,Y pixel on screen */
142: Y = nPixelsIn/512;
143: X = nPixelsIn - (Y*512);
144: if (X<SCREEN_START_CYCLE) /* Limit if in NULL area outside screen */
145: X = SCREEN_START_CYCLE;
146: if (X>(512-SCREEN_START_CYCLE))
147: X = (512-SCREEN_START_CYCLE);
148: /* X is now from 96 to 416(320 pixels), subtract 96 to give X pixel across screen! */
149: X = ((X-SCREEN_START_CYCLE)>>1)&(~1);
1.1.1.6 root 150:
1.1 root 151: if (Y<(nEndHBL-nStartHBL)) /* Limit to end of screen */
152: VideoAddress = (Y*160) + X;
153: else
154: VideoAddress = ((nEndHBL-nStartHBL)*160);
155: }
156:
157: /* Offset from start of screen(MUST use address loading into video display) */
158: VideoAddress += VideoBase;
159: }
160:
161: /*-----------------------------------------------------------------------*/
162: /*
163: Read Video address pointer(from current cycle count), and return 24-bit address in 'ebx'
164: */
165: unsigned long Video_ReadAddress(void)
166: {
167: Video_CalculateAddress(); /* Find address from current cycle count into display frame */
168: return( VideoAddress );
169: }
170:
1.1.1.7 ! root 171:
1.1 root 172: /*-----------------------------------------------------------------------*/
173: /*
174: VBL interrupt, draw screen and reset counters
175: */
176: void Video_InterruptHandler_VBL(void)
177: {
178: int PendingCyclesOver;
1.1.1.6 root 179: int nNewMilliTicks;
180: static int nOldMilliTicks = 0;
181: signed int nDelay;
1.1 root 182:
183: /* Store cycles we went over for this frame(this is our inital count) */
184: PendingCyclesOver = -PendingInterruptCount; /* +ve */
185:
186: /* Remove this interrupt from list and re-order */
187: Int_AcknowledgeInterrupt();
1.1.1.6 root 188: /* Start HBL interrupts - MUST do before add in cycles */
1.1 root 189: Int_AddAbsoluteInterrupt(CYCLES_ENDLINE,INTERRUPT_VIDEO_ENDLINE);
190: Int_AddAbsoluteInterrupt(CYCLES_HBL,INTERRUPT_VIDEO_HBL);
191: Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME,INTERRUPT_VIDEO_VBL);
192:
193: /* Set frame cycles, used for Video Address */
194: nFrameCyclesOver = PendingCyclesOver; /* Number of cycles into frame */
195:
1.1.1.6 root 196: /* Set the screen refresh rate */
197: #if 0
198: if(bUseHighRes)
199: nScreenRefreshRate = 70;
200: else if(STRam[0xff820a] & 2) /* Is it 50Hz or is it 60Hz? */
201: nScreenRefreshRate = 50;
202: else
203: nScreenRefreshRate = 60;
204: #endif
205:
206: VBLCounter += 1;
1.1.1.2 root 207:
1.1.1.3 root 208: /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
209: Keymap_DebounceAllKeys();
1.1.1.7 ! root 210: /* Check shortcut keys */
1.1 root 211: ShortCut_CheckKeys();
1.1.1.7 ! root 212:
1.1 root 213: /* Use extended VDI resolution? If so, just copy whole screen on VBL rather than per HBL */
214: if (bUseVDIRes)
215: Video_CopyVDIScreen();
1.1.1.5 root 216:
1.1 root 217: /* Draw screen, skip frame if need to */
1.1.1.6 root 218: if (ConfigureParams.Screen.bFrameSkip)
1.1.1.5 root 219: {
1.1 root 220: if (nVBLs&1)
221: Screen_Draw();
222: }
223: else
224: Screen_Draw();
1.1.1.5 root 225:
1.1 root 226: /* Update counter for number of screen refreshes per second(for debugging) */
227: nVBLs++;
228: /* Set video registers for frame */
229: Video_ClearOnVBL();
230: /* Store off PSG registers for YM file, is enabled */
231: YMFormat_UpdateRecording();
1.1.1.4 root 232: /* Generate 1/50th second of sound sample data, to be played by sound thread */
1.1 root 233: Sound_Update_VBL();
234:
1.1.1.7 ! root 235: M68000_Exception(EXCEPTION_VBLANK); /* Vertical blank interrupt, level 4! */
1.1 root 236:
1.1.1.5 root 237: /* And handle any messages, check for quit message */
1.1 root 238: Main_EventHandler(); /* Process messages, set 'bQuitProgram' if user tries to quit */
1.1.1.7 ! root 239: if (bQuitProgram)
! 240: {
1.1 root 241: Int_AddAbsoluteInterrupt(4, 0L); /* Pass NULL interrupt function to quit cleanly */
1.1.1.7 ! root 242: set_special(SPCFLAG_BRK); /* Assure that CPU core shuts down */
! 243: }
1.1.1.6 root 244:
1.1.1.7 ! root 245: if (ConfigureParams.System.nMinMaxSpeed != MINMAXSPEED_MAX)
1.1.1.6 root 246: {
1.1.1.7 ! root 247: /* Wait, so we stay in sync with the sound */
! 248: do
1.1.1.6 root 249: {
1.1.1.7 ! root 250: nNewMilliTicks = SDL_GetTicks();
! 251: nDelay = 1000/nScreenRefreshRate - (nNewMilliTicks-nOldMilliTicks);
! 252: if(nDelay > 2)
! 253: {
! 254: /* SDL_Delay seems to be quite inaccurate, so we don't wait the whole time */
! 255: SDL_Delay(nDelay - 1);
! 256: }
1.1.1.6 root 257: }
1.1.1.7 ! root 258: while(nDelay > 0);
! 259: nOldMilliTicks = nNewMilliTicks;
1.1.1.6 root 260: }
1.1 root 261: }
262:
263:
264: /*-----------------------------------------------------------------------*/
265: /*
266: End Of Line interrupt
1.1.1.5 root 267: As this occurs at the end of a line we cannot get timing for START of first
268: line (as in Spectrum 512)
1.1 root 269: */
270: void Video_InterruptHandler_EndLine(void)
271: {
272: /* Remove this interrupt from list and re-order */
273: Int_AcknowledgeInterrupt();
274: /* Generate new HBL, if need to - there are 313 HBLs per frame */
275: if (nHBL<(SCANLINES_PER_FRAME-1))
276: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_ENDLINE);
277:
1.1.1.5 root 278: /* Is this a good place to send the keyboard packets? Done once per frame */
279: if(nHBL == nStartHBL)
280: {
281: /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */
282: IKBD_SendAutoKeyboardCommands();
283: }
284:
1.1 root 285: /* Timer A/B occur at END of first visible screen line in Event Count mode */
286: if ( (nHBL>=nStartHBL) && (nHBL<nEndHBL) )
287: {
288: /* Handle Timers A and B when using Event Count mode(timer taken from HBL) */
1.1.1.2 root 289: if (MFP_TACR==0x08) /* Is timer in Event Count mode? */
1.1 root 290: MFP_TimerA_EventCount_Interrupt();
1.1.1.2 root 291: if (MFP_TBCR==0x08) /* Is timer in Event Count mode? */
1.1 root 292: MFP_TimerB_EventCount_Interrupt();
293: }
294:
1.1.1.2 root 295: FDC_UpdateHBL(); /* Update FDC motion */
296: Video_EndHBL(); /* Increase HBL count, copy line to display buffer and do any video trickery */
1.1 root 297:
298: /* If we don't often pump data into the event queue, the SDL misses events... grr... */
299: if( !(nHBL&63) )
1.1.1.5 root 300: {
1.1 root 301: Main_EventHandler();
1.1.1.5 root 302: }
1.1 root 303: }
304:
305:
1.1.1.2 root 306: /*-----------------------------------------------------------------------*/
1.1 root 307: /*
308: HBL interrupt - this is very inaccurate on ST and appears to occur around 1/3rd way into
309: the display!
310: */
311: void Video_InterruptHandler_HBL(void)
312: {
1.1.1.2 root 313: /* Remove this interrupt from list and re-order */
1.1 root 314: Int_AcknowledgeInterrupt();
1.1.1.7 ! root 315:
1.1.1.2 root 316: /* Generate new Timer AB, if need to - there are 313 HBLs per frame */
1.1.1.7 ! root 317: if(nHBL < (SCANLINES_PER_FRAME-1))
1.1 root 318: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_HBL);
319:
1.1.1.7 ! root 320: M68000_Exception(EXCEPTION_HBLANK); /* Horizontal blank interrupt, level 2! */
1.1 root 321: }
322:
323:
1.1.1.2 root 324: /*-----------------------------------------------------------------------*/
1.1 root 325: /*
1.1.1.7 ! root 326: Write to VideoShifter (0xff8260), resolution bits
1.1 root 327: */
1.1.1.7 ! root 328: void Video_WriteToShifter(Uint8 Byte)
1.1 root 329: {
1.1.1.7 ! root 330: static int nLastHBL = -1, LastByte, nLastCycles;
! 331: int nFrameCycles, nLineCycles;
! 332:
! 333: nFrameCycles = Int_FindFrameCycles();
1.1 root 334:
1.1.1.7 ! root 335: /* We only care for cycle position in the actual screen line */
! 336: nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1 root 337:
1.1.1.7 ! root 338: /*fprintf(stderr,"Shifter=0x%2.2X %d (%d) @ %d\n",
! 339: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 340:
1.1.1.7 ! root 341: /* Check if program tries to open left border.
! 342: * FIXME: This is a very inaccurate test that should be improved,
! 343: * but we probably need better CPU cycles emulation first. There's
! 344: * also no support for sync-scrolling yet :-( */
! 345: if (nHBL == nLastHBL && LastByte == 0x02 && Byte == 0x00
! 346: && nLineCycles <= 48 && nLineCycles-nLastCycles <= 16)
! 347: {
! 348: LeftRightBorder |= BORDERMASK_LEFT;
! 349: }
1.1.1.2 root 350:
1.1.1.7 ! root 351: nLastHBL = nHBL;
! 352: LastByte = Byte;
! 353: nLastCycles = nLineCycles;
1.1 root 354: }
355:
1.1.1.2 root 356:
357: /*-----------------------------------------------------------------------*/
1.1 root 358: /*
1.1.1.7 ! root 359: Write to VideoSync (0xff820a), Hz setting
1.1 root 360: */
1.1.1.7 ! root 361: void Video_WriteToSync(Uint8 Byte)
1.1 root 362: {
1.1.1.7 ! root 363: static int nLastHBL = -1, LastByte, nLastCycles;
! 364: int nFrameCycles, nLineCycles;
! 365:
! 366: nFrameCycles = Int_FindFrameCycles();
1.1 root 367:
1.1.1.7 ! root 368: /* We only care for cycle position in the actual screen line */
! 369: nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1.1.2 root 370:
1.1.1.7 ! root 371: /*fprintf(stderr,"Sync=0x%2.2X %d (%d) @ %d\n",
! 372: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 373:
1.1.1.7 ! root 374: /* Check if program tries to open a border.
! 375: * FIXME: These are very inaccurate tests that should be improved,
! 376: * but we probably need better CPU cycles emulation first. There's
! 377: * also no support for sync-scrolling yet :-( */
! 378: if (LastByte == 0x00 && Byte == 0x02) /* switched from 50 Hz to 60 Hz and back to 50 Hz? */
! 379: {
! 380: if (nHBL >= OVERSCAN_TOP && nHBL <= 39 && nStartHBL > FIRST_VISIBLE_HBL)
! 381: {
! 382: /* Top border */
! 383: OverscanMode |= OVERSCANMODE_TOP; /* Set overscan bit */
! 384: nStartHBL = FIRST_VISIBLE_HBL; /* New start screen line */
! 385: pHBLPaletteMasks -= OVERSCAN_TOP;
! 386: pHBLPalettes -= OVERSCAN_TOP;
1.1 root 387: }
1.1.1.7 ! root 388: else if (nHBL == SCREEN_START_HBL+SCREEN_HEIGHT_HBL)
! 389: {
! 390: /* Bottom border */
! 391: OverscanMode |= OVERSCANMODE_BOTTOM; /* Set overscan bit */
! 392: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM; /* New end screen line */
1.1 root 393: }
394:
1.1.1.7 ! root 395: if (nHBL == nLastHBL && nLineCycles >= 400 && nLineCycles <= 480
! 396: && nLineCycles-nLastCycles <= 16)
! 397: {
! 398: /* Right border */
! 399: LeftRightBorder |= BORDERMASK_RIGHT;
! 400: }
1.1 root 401: }
402:
1.1.1.7 ! root 403: nLastHBL = nHBL;
! 404: LastByte = Byte;
! 405: nLastCycles = nLineCycles;
1.1 root 406: }
407:
1.1.1.2 root 408:
409: /*-----------------------------------------------------------------------*/
1.1 root 410: /*
411: Reset Sync/Shifter table at start of each HBL
412: */
413: void Video_StartHBL(void)
414: {
415: LeftRightBorder = 0;
416: }
417:
1.1.1.2 root 418:
419: /*-----------------------------------------------------------------------*/
1.1 root 420: /*
421: Store whole palette on first line so have reference to work from
422: */
1.1.1.7 ! root 423: static void Video_StoreFirstLinePalette(void)
1.1 root 424: {
425: unsigned short int *pp2;
426: int i;
427:
428: pp2 = (unsigned short int *)((unsigned long)STRam+0xff8240);
429: for(i=0; i<16; i++)
1.1.1.7 ! root 430: HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1.1.2 root 431: /* And set mask flag with palette and resolution */
1.1 root 432: HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((unsigned long)STMemory_ReadByte(0xff8260)&0x3)<<16);
433: }
434:
1.1.1.2 root 435:
436: /*-----------------------------------------------------------------------*/
1.1 root 437: /*
438: Store resolution on each line(used to test if mixed low/medium resolutions)
439: */
1.1.1.7 ! root 440: static void Video_StoreResolution(int y)
1.1 root 441: {
1.1.1.2 root 442: /* Clear resolution, and set with current value */
1.1 root 443: if (!(bUseHighRes || bUseVDIRes) ) {
444: HBLPaletteMasks[y] &= ~(0x3<<16);
445: HBLPaletteMasks[y] |= ((unsigned long)STMemory_ReadByte(0xff8260)&0x3)<<16;
446: }
447: }
448:
1.1.1.2 root 449:
450: /*-----------------------------------------------------------------------*/
1.1 root 451: /*
452: Copy line of screen into buffer for conversion later.
453: Possible lines may be top/bottom border, and/or left/right borders
454: */
1.1.1.7 ! root 455: static void Video_CopyScreenLine(int BorderMask)
1.1 root 456: {
1.1.1.2 root 457: /* Only copy screen line if not doing high VDI resolution */
1.1 root 458: if (!bUseVDIRes) {
459: BorderMask |= LeftRightBorder;
460:
461: if (bUseHighRes) {
1.1.1.2 root 462: /* Copy for hi-res (no overscan) */
1.1 root 463: memcpy(pSTScreen,(char *)VideoRaster,SCREENBYTES_MIDDLE);
464: VideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2 root 465: /* Each screen line copied to buffer is always same length */
1.1 root 466: pSTScreen += SCREENBYTES_MIDDLE;
467: }
468: else {
1.1.1.2 root 469: /* Is total blank line? Ie top/bottom border? */
1.1 root 470: if (BorderMask&(BORDERMASK_TOP|BORDERMASK_BOTTOM)) {
1.1.1.2 root 471: /* Clear line to colour '0' */
1.1 root 472: memset(pSTScreen,0,SCREENBYTES_LINE);
473: }
474: else {
1.1.1.2 root 475: /* Does have left border? If not, clear to colour '0' */
1.1 root 476: if (BorderMask&BORDERMASK_LEFT) {
477: VideoRaster += 24-SCREENBYTES_LEFT;
478: memcpy(pSTScreen,(char *)VideoRaster,SCREENBYTES_LEFT);
479: VideoRaster += SCREENBYTES_LEFT;
480: }
481: else
482: memset(pSTScreen,0,SCREENBYTES_LEFT);
1.1.1.2 root 483: /* Copy middle - always present */
1.1 root 484: memcpy(pSTScreen+SCREENBYTES_LEFT,(char *)VideoRaster,SCREENBYTES_MIDDLE);
485: VideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2 root 486: /* Does have right border? If not, clear to colour '0' */
1.1 root 487: if (BorderMask&BORDERMASK_RIGHT) {
488: memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,(char *)VideoRaster,SCREENBYTES_RIGHT);
489: VideoRaster += 46-SCREENBYTES_RIGHT;
490: VideoRaster += SCREENBYTES_RIGHT;
491: }
492: else
493: memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
494: }
1.1.1.6 root 495:
1.1.1.2 root 496: /* Each screen line copied to buffer is always same length */
1.1 root 497: pSTScreen += SCREENBYTES_LINE;
498: }
499: }
500: }
501:
1.1.1.2 root 502:
503: /*-----------------------------------------------------------------------*/
1.1 root 504: /*
505: Copy extended GEM resolution screen
506: */
507: void Video_CopyVDIScreen(void)
508: {
1.1.1.2 root 509: /* Copy whole screen, don't care about being exact as for GEM only */
510: memcpy(pSTScreen,(char *)VideoRaster,((VDIWidth*VDIPlanes)/8)*VDIHeight); /* 640x400x16colour */
1.1 root 511: }
512:
1.1.1.2 root 513:
514: /*-----------------------------------------------------------------------*/
1.1 root 515: /*
516: Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted
517: */
518: void Video_EndHBL(void)
519: {
1.1.1.2 root 520: /* Are we in possible visible display (including borders)? */
1.1 root 521: if ( (nHBL>=FIRST_VISIBLE_HBL) && (nHBL<(FIRST_VISIBLE_HBL+NUM_VISIBLE_LINES)) ) {
1.1.1.2 root 522: /* Copy line of screen to buffer to simulate TV raster trace - required for mouse cursor display/game updates */
523: /* Eg, Lemmings and The Killing Game Show are good examples */
1.1 root 524:
1.1.1.2 root 525: if (nHBL<nStartHBL) /* Are we in top border blank (ie no top overscan enabled) */
1.1 root 526: Video_CopyScreenLine(BORDERMASK_TOP);
1.1.1.2 root 527: else if (nHBL>=nEndHBL) /* Are we in bottom border blank */
1.1 root 528: Video_CopyScreenLine(BORDERMASK_BOTTOM);
1.1.1.2 root 529: else /* Must be in visible screen(including overscan), ignore left/right borders for now */
1.1 root 530: Video_CopyScreenLine(BORDERMASK_NONE);
531:
1.1.1.2 root 532: if (nHBL==FIRST_VISIBLE_HBL) { /* Very first line on screen - HBLPalettes[0] */
533: /* Store ALL palette for this line into raster table for datum */
1.1 root 534: Video_StoreFirstLinePalette();
535: }
1.1.1.2 root 536: /* Store resolution for every line so can check for mix low/medium screens */
1.1 root 537: Video_StoreResolution(nHBL-FIRST_VISIBLE_HBL);
538: }
539:
1.1.1.2 root 540: /* Finally increase HBL count */
1.1 root 541: nHBL++;
542:
1.1.1.2 root 543: Video_StartHBL(); /* Setup next one */
1.1 root 544: }
545:
1.1.1.2 root 546:
547: /* Clear raster line table to store changes in palette/resolution on a line basic */
548: /* Call once on VBL interrupt */
1.1 root 549: void Video_SetScreenRasters(void)
550: {
551: pHBLPaletteMasks = HBLPaletteMasks;
552: pHBLPalettes = HBLPalettes;
553: Memory_Clear(pHBLPaletteMasks,sizeof(unsigned long)*NUM_VISIBLE_LINES);
554: }
555:
1.1.1.2 root 556:
557: /*-----------------------------------------------------------------------*/
1.1 root 558: /*
559: Set pointers to HBLPalette tables to store correct colours/resolutions
560: */
561: void Video_SetHBLPaletteMaskPointers(void)
562: {
563: int FrameCycles;
564: int Line;
565:
566: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
567: /* Each line is 64+320+64+64(Blank) = 512 pixels per scan line */
568: /* Timer occurs at end of 64+320+64; Display Enable(DE)=Low */
569: /* HBL is incorrect on machine and occurs around 96+ cycles in */
570:
571: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
572: /* Each line is 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
573: FrameCycles = Int_FindFrameCycles();
574:
575: /* Find 'line' into palette - screen starts 64 lines down, less 28 for top overscan */
576: /* And if write to last 96 cycle of line it will count as the NEXT line(needed else games may flicker) */
577: Line = (FrameCycles-(FIRST_VISIBLE_HBL*CYCLES_PER_LINE)+SCREEN_START_CYCLE)/CYCLES_PER_LINE;
578: if (Line<0) /* Limit to top/bottom of possible visible screen */
579: Line = 0;
580: if (Line>=NUM_VISIBLE_LINES)
581: Line = NUM_VISIBLE_LINES-1;
582:
1.1.1.2 root 583: /* Store pointers */
1.1 root 584: pHBLPaletteMasks = &HBLPaletteMasks[Line]; /* Next mask entry */
585: pHBLPalettes = &HBLPalettes[16*Line]; /* Next colour raster list x16 colours */
586: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.