<commit_before>
/* TODO: Add two options
 *
 *       1) runtime enable/disable intercept (if you don't want to force to 480 anymore)
 *
 *       2) disable overscan options
 *
 *          I'm noticing that the PEXHDCAP card is mis-detecting the 8-pixel overscan
 *          as part of the active picture, so what I get is a capture that's missing
 *          8 pixels from the right side and capturing 8 pixels of black on the left
 *          (or depending on the DOS game/demo, whatever color was programmed to be
 *          the overscan color).
 *
 *          So what would be useful is if the user could have us disable the overscan
 *          border entirely, or disable overscan on the sides only, or top/bottom only,
 *          or just leave it alone--whatever the user wants.
 *
 *          I'm guessing modern VGA capture cards like the PEXHDCAP are made for Windows
 *          desktops only where overscan color is never used, and that's why DOS overscan
 *          colors confuse it a bit like that.
 *
 *          On the S3 Virge PCI card I have, even for parts of the picture that are
 *          pure black, the card seems to bias the R,G,B output a bit including overscan
 *          and you can clearly see on the output a dark gray where active picture area
 *          and overscan are rendered, which might have something to do with the shifted
 *          image on capture as well.
 *
 * TODO: Reduce memory footprint. 32KB is a bit much, and it crowds out some of the
 *       stuff you want to capture. */

#include <stdio.h>
#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <math.h>
#include <dos.h>

#include <hw/dos/dos.h>
#include <hw/vga/vga.h>

unsigned char		force89 = 0; /* 0=dont force    8=force 8    9=force 9 */
unsigned char		blanking_fix = 1;
int			blanking_align = 0;
void			(__interrupt __far *old_int10)();

void __interrupt __far new_int10(union INTPACK ip) {
	if (ip.w.ax == 0xDFA0 && ip.w.bx == 0x1AC0) {
		switch (ip.h.cl) {
			case 0: /* install check */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				break;
			case 1: /* change force89 option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				force89 = ip.h.ch;
				break;
			case 2: /* change blanking fix option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				blanking_fix = ip.h.ch;
				break;
			case 3: /* change blanking align option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				if (ip.h.ch & 0x80)
					blanking_align = -1;
				else
					blanking_align = ip.h.ch;
				break;
			default:
				ip.w.ax = 0xDFFF;
				ip.w.bx = 0xCACA;
				break;
		};

		return;
	}
	else if (ip.h.ah == 0x00) {
		unsigned int vtotal = 0x20B; /* NTS: one less than actual scanlines */
		unsigned int vretrace_s = 0x1EA;
		unsigned int vretrace_e = 0x1EC;
		unsigned int vdisplay_e = 0x1E0;
		unsigned int vblank_s = 0x1E8;
		unsigned int vblank_e = 0x204;
		unsigned int mode = ip.h.al;
		unsigned char t,ov=0;
		unsigned int port;

		__asm {
			push	ds
			mov	ax,seg old_int10
			mov	ds,ax
			mov	ax,mode
			pushf
			callf	dword ptr [old_int10]
			pop	ds
		}

		/* mono or color? */
		port = (inp(0x3CC)&1)?0x3D4:0x3B4;

		if (ip.h.al <= 3 || ip.h.al == 7) {
			/* force 8-pixel */
			if (force89 == 8) {
				outp(0x3C4,0x01); /* seq, clocking mode reg */
				t = inp(0x3C5);
				outp(0x3C5,t|0x01); /* select 8 dots/char */

				t = inp(0x3CC); /* then select 25MHz clock */
				outp(0x3C2,t&(~0xC));
			}
			/* force 9-pixel */
			else if (force89 == 9) {
				outp(0x3C4,0x01); /* seq, clocking mode reg */
				t = inp(0x3C5);
				outp(0x3C5,t&0xFE); /* select 9 dots/char */

				t = inp(0x3CC); /* then select 28MHz clock */
				outp(0x3C2,(t&(~0xC)) | (1 << 2));
			}
		}

		if (blanking_fix) {
			unsigned int lines;
			unsigned int extra;

			/* read from the card how many active display lines there are */
			outp(port,0x12); /* display end */
			lines = inp(port+1); /* bits 0-7 */
			outp(port,0x07); /* overflow */
			t = inp(port+1);
			lines += (t&0x02)?0x100:0x000;
			lines += (t&0x40)?0x200:0x000;

			/* how many extra lines will there be? */
			if (lines < vdisplay_e)
				extra = vdisplay_e - lines;
			else
				extra = 0;

			/* now use that count to reprogram the blanking area and display params.
			 * use the extra line count to adjust vertical retrace downward so the
			 * shortened image is centered. if we do not do this, then the image is
			 * "stuck" to the bottom of the screen with black at the top. */
			vdisplay_e = lines;
			vblank_s = lines + 8;
			if (blanking_align < 0) {
				/* align image to top */
				vretrace_s = lines + 10 + extra;
				vretrace_e = lines + 12 + extra;
			}
			else if (blanking_align == 0) {
				/* align to center */
				vretrace_s = lines + 10 + (extra/2);
				vretrace_e = lines + 12 + (extra/2);
			}
			else {
				/* align to bottom */
				vretrace_s = lines + 10;
				vretrace_e = lines + 12;
			}
		}

		/* reprogram the CRTC back to a 480 line mode */
		outp(port,0x11); /* retrace end (also clear protect bit, and preserve whatever the "bandwidth" bit contains) */
		t = inp(port+1);
		outp(port+1,(t&0x70)+(vretrace_e&0xF));

		outp(port,0x17);
		t = inp(port+1);
		outp(port+1,t&0x7F);<commit_msg>correction: vga240.c needs to consider vtotal constant is total - 2, and vdisplay end constant starts out as display end, but is subtracted by 1 before writing, and when reading display end from CRTC, needs to add 1.<commit_after>
/* TODO: Add two options
 *
 *       1) runtime enable/disable intercept (if you don't want to force to 480 anymore)
 *
 *       2) disable overscan options
 *
 *          I'm noticing that the PEXHDCAP card is mis-detecting the 8-pixel overscan
 *          as part of the active picture, so what I get is a capture that's missing
 *          8 pixels from the right side and capturing 8 pixels of black on the left
 *          (or depending on the DOS game/demo, whatever color was programmed to be
 *          the overscan color).
 *
 *          So what would be useful is if the user could have us disable the overscan
 *          border entirely, or disable overscan on the sides only, or top/bottom only,
 *          or just leave it alone--whatever the user wants.
 *
 *          I'm guessing modern VGA capture cards like the PEXHDCAP are made for Windows
 *          desktops only where overscan color is never used, and that's why DOS overscan
 *          colors confuse it a bit like that.
 *
 *          On the S3 Virge PCI card I have, even for parts of the picture that are
 *          pure black, the card seems to bias the R,G,B output a bit including overscan
 *          and you can clearly see on the output a dark gray where active picture area
 *          and overscan are rendered, which might have something to do with the shifted
 *          image on capture as well.
 *
 * TODO: Reduce memory footprint. 32KB is a bit much, and it crowds out some of the
 *       stuff you want to capture. */

#include <stdio.h>
#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <math.h>
#include <dos.h>

#include <hw/dos/dos.h>
#include <hw/vga/vga.h>

unsigned char		force89 = 0; /* 0=dont force    8=force 8    9=force 9 */
unsigned char		blanking_fix = 1;
int			blanking_align = 0;
void			(__interrupt __far *old_int10)();

void __interrupt __far new_int10(union INTPACK ip) {
	if (ip.w.ax == 0xDFA0 && ip.w.bx == 0x1AC0) {
		switch (ip.h.cl) {
			case 0: /* install check */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				break;
			case 1: /* change force89 option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				force89 = ip.h.ch;
				break;
			case 2: /* change blanking fix option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				blanking_fix = ip.h.ch;
				break;
			case 3: /* change blanking align option */
				ip.w.ax = 0xDFAA;
				ip.w.bx = 0xCACA;
				if (ip.h.ch & 0x80)
					blanking_align = -1;
				else
					blanking_align = ip.h.ch;
				break;
			default:
				ip.w.ax = 0xDFFF;
				ip.w.bx = 0xCACA;
				break;
		};

		return;
	}
	else if (ip.h.ah == 0x00) {
		unsigned int vtotal = 0x20B; /* NTS: two less than actual scanlines */
		unsigned int vretrace_s = 0x1EA;
		unsigned int vretrace_e = 0x1EC;
		unsigned int vdisplay_e = 0x1E0; /* NTS: this value is the display end, actual register value is - 1 */
		unsigned int vblank_s = 0x1E8;
		unsigned int vblank_e = 0x204;
		unsigned int mode = ip.h.al;
		unsigned char t,ov=0;
		unsigned int port;

		__asm {
			push	ds
			mov	ax,seg old_int10
			mov	ds,ax
			mov	ax,mode
			pushf
			callf	dword ptr [old_int10]
			pop	ds
		}

		/* mono or color? */
		port = (inp(0x3CC)&1)?0x3D4:0x3B4;

		if (ip.h.al <= 3 || ip.h.al == 7) {
			/* force 8-pixel */
			if (force89 == 8) {
				outp(0x3C4,0x01); /* seq, clocking mode reg */
				t = inp(0x3C5);
				outp(0x3C5,t|0x01); /* select 8 dots/char */

				t = inp(0x3CC); /* then select 25MHz clock */
				outp(0x3C2,t&(~0xC));
			}
			/* force 9-pixel */
			else if (force89 == 9) {
				outp(0x3C4,0x01); /* seq, clocking mode reg */
				t = inp(0x3C5);
				outp(0x3C5,t&0xFE); /* select 9 dots/char */

				t = inp(0x3CC); /* then select 28MHz clock */
				outp(0x3C2,(t&(~0xC)) | (1 << 2));
			}
		}

		if (blanking_fix) {
			unsigned int lines;
			unsigned int extra;

			/* read from the card how many active display lines there are */
			outp(port,0x12); /* display end */
			lines = inp(port+1); /* bits 0-7 */
			outp(port,0x07); /* overflow */
			t = inp(port+1);
			lines += (t&0x02)?0x100:0x000;
			lines += (t&0x40)?0x200:0x000;
			lines++; /* display reg is value - 1 */

			/* how many extra lines will there be? */
			if (lines < vdisplay_e)
				extra = vdisplay_e - lines;
			else
				extra = 0;

			/* now use that count to reprogram the blanking area and display params.
			 * use the extra line count to adjust vertical retrace downward so the
			 * shortened image is centered. if we do not do this, then the image is
			 * "stuck" to the bottom of the screen with black at the top. */
			vdisplay_e = lines;
			vblank_s = lines + 8;
			if (blanking_align < 0) {
				/* align image to top */
				vretrace_s = lines + 10 + extra;
				vretrace_e = lines + 12 + extra;
			}
			else if (blanking_align == 0) {
				/* align to center */
				vretrace_s = lines + 10 + (extra/2);
				vretrace_e = lines + 12 + (extra/2);
			}
			else {
				/* align to bottom */
				vretrace_s = lines + 10;
				vretrace_e = lines + 12;
			}
		}

		/* vertical display end is actually value - 1 */
		vdisplay_e--;

		/* reprogram the CRTC back to a 480 line mode */
		outp(port,0x11); /* retrace end (also clear protect bit, and preserve whatever the "bandwidth" bit contains) */
		t = inp(port+1);
		outp(port+1,(t&0x70)+(vretrace_e&0xF));

		outp(port,0x17);
		t = inp(port+1);
		outp(port+1,t&0x7F);
{'fraction_non_alphanumeric': 0.11624132022725223, 'fraction_numerical': 0.03922806384705564, 'mean_word_length': 2.4753995612660606, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2433172', 'n_tokens_mistral': 4800, 'n_tokens_neox': 3991, 'n_words': 1371}