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