// //+----------------------------------------------------------------------+ //+ Program STRANGE.CPP - By Fausto A. A. Barbuto, + //+ E-Mail: BJ06@C53000.PETROBRAS.ANRJ.BR, barbuto@ax.ibase.org.br + //+ and Michael E. Sargent, msargent@moose.uvm.edu + //+ + //+ Uses Michael E. Sargent's graphics functions and Robert Munafo's + //+ formulae for Period 1 (Main Cardiod) and Period 2 (Main Circle) + //+ detection. + //+ + //+ Plots strange Mandelbrot Sets with decomposed outer layers (similar + //+ to binary decomposition, but quite different at a first sight). + //+ Periods 1 & 2 are also decomposed in colourful levels. + //+ + //+ Press the '+' key at anytime to rotate palettes; any other key + //+ will fade the screen out. + //+----------------------------------------------------------------------+ // #include #include #include #include #include #include int initvesa(void); void SetMode(int mode); void plot(int i, int j, int color); int selectmode(void); void floatscreen(int y1, int y2, int foreground, int shadow); void quit(void); void setVGAreg(int, int, int, int); void GetPalette(void); void cycle(void); void fade(void); union REGS reg; struct SREGS seg; int xres, yres, mode, colors, vesaflag, activebank, bankshift, locationshift, memoryblocks, (*winfuncptr)(); unsigned int modetable[12]; long int banksize, linetable[1024]; char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; char palette[256][3]; void main() { double pmin=-2.25, pmax=0.75, qmin=-1.125, qmax=1.125; double ypy, x, y, p, q, p1, q1, ya, xkp1, ykp1, r; double deltap, deltaq, r1=8.9138e-3, r2=5.88e-2; double test1, test2, test3, test4; register int kk, k, np, nq, npy, ipen; unsigned long maxiter=512; int initc, iopt, mistake; complex c; char ch, choicekey; clrscr(); _setcursortype(_NOCURSOR); printf("\n Program STRANGE\n"); printf("\n By Fausto A. A. Barbuto, BJ06@C53000.PETROBRAS.ANRJ.BR"); printf("\n barbuto@ax.ibase.org.br"); printf("\n\n Graphics routines by Michael E. Sargent, "); printf("msargent@moose.uvm.edu"); printf("\n\n INSTRUCTIONS: hit ESC to fade the screen out and quit;"); printf("\n or press '+' to rotate palettes."); printf("\n\n\n Select an option:"); printf("\n\n 1 - Study in Blue "); printf("\n 2 - Study in Red "); printf("\n 3 - Study in Green "); printf("\n 4 - Study in Gray "); printf("\n 5 - Graphite "); do { mistake = 0; // Reset the mistake flag choicekey = getch(); iopt = ("%d", choicekey) - 48; if (iopt < 1 || iopt > 5) // Check for valid choices { printf("%c%c",0x07,0x07); // Sound some warning beeps mistake = 1; } } while (mistake !=0); // Repeat until valid selection textcolor(YELLOW + BLINK); // Indicate the choice gotoxy(2, iopt + 14); cprintf("%c", choicekey); textcolor(LIGHTGRAY); delay(1000); vesaflag = initvesa(); if (selectmode()) quit(); clrscr(); printf("\n Wait a few seconds, please..."); printf("\n Espere um pouco, por favor..."); delay(950); SetMode(mode); initc = 28; if (iopt == 1) { for (kk=1;kk<64;kk++) setVGAreg(kk,0,0,kk); for (kk=64;kk<127;kk++) setVGAreg(kk,0,0,127-kk); } if (iopt == 2) { for (kk=1;kk<64;kk++) setVGAreg(kk,kk,0,0); for (kk=64;kk<127;kk++) setVGAreg(kk,127-kk,0,0); } if (iopt == 3) { for (kk=1;kk<64;kk++) setVGAreg(kk,0,kk,0); for (kk=64;kk<127;kk++) setVGAreg(kk,0,127-kk,0); } if (iopt == 4) { for (kk=1;kk<64;kk++) setVGAreg(kk,0,kk,kk); for (kk=64;kk<127;kk++) setVGAreg(kk,0,127-kk,127-kk); } if (iopt == 5) { for (kk=1;kk<64;kk++) setVGAreg(kk,0,kk,kk); for (kk=64;kk<127;kk++) setVGAreg(kk,0,127-kk,127-kk); initc = 14; } setVGAreg(127,0,0,32); // use attribute #127 for blue instead of #1 ypy = (double)yres - 0.5; deltap = (pmax-pmin)/(xres-1); deltaq = (qmax-qmin)/(yres-1); if(qmin==-qmax) npy = yres/2; else npy = yres; for (np=0; np<=xres-1; np++) { p = pmin + (double)np*deltap; for (nq=0; nq<=npy-1; nq++) { q = qmin + (double)nq*deltaq; k = 0; x = 0.0; y = 0.0; c = complex(p,q); // //-------Checks limits for Period 1. // test1 = 2.0; if ((p >= -7.55e-1) && (p <= 4.0e-1)) { if (fabs(q) <= 6.6e-1) test1 = abs(1.0 - sqrt(1.0-4.0*c)); } // //-------Checks limits for Period 2. // test2 = 2.0; if ((p >= -1.255e0) && (p <= -7.45e-1)) { if (fabs(q) <= 2.55e-1) test2 = 4.0*sqrt((p+1.0)*(p+1.0) + q*q); } // //-------Checks limits for Period Bud 3. // test3 = 2.0; if ((p >= -2.4e-1) && (p <= 0.0e0)) { if (fabs(q) <= 8.5e-1) { p1 = p + 1.2486e-1; q1 = fabs(q) - 7.4396e-1; test3 = p1*p1 + q1*q1; } } // //-------Checks limits for Period 4. // test4 = 2.0; if ((p >= -1.37e0) && (p <= -1.245e0)) { if (fabs(q) <= 6.1e-2) test4 = sqrt((p+1.309)*(p+1.309) + q*q); } // if((test1<=1.0) || (test2<=1.0) || (test3<=r1) || (test4<=r2)) { if (test3<=r1) ipen = 0; if (test4<=r2) ipen = 0; if (test1<=1.0) ipen = 42 - (int)(35.0*test1); if (test2<=1.0) ipen = 42 - (int)(31.0*test2); if (qmin == -qmax) { plot(np,nq,ipen); plot(np,(int)(yres-nq-1.0),ipen); } else plot(np,nq,ipen); } else { do { xkp1 = (x+y)*(x-y) + p; ya = x*y; ykp1 = ya + ya + q; asm { fld xkp1 fld xkp1 FMULP fld ykp1 fld ykp1 FMULP FADDP fstp r } k++; // // If R > M, points escape towards infinity. // if (r >= maxiter) { ipen = (int)(initc + 2.0*(log(xkp1*xkp1)-log(ykp1*ykp1))); if (ipen <= 4) ipen = 0; if (qmin == -qmax) { plot(np,nq,ipen); plot(np,(int)(yres-nq-1.0),ipen); } else plot(np,nq,ipen); } // // Points which do not belong to any period: Colour=0 (Black) // if (k == maxiter) { if (qmin == -qmax) { ypy = double(yres) - nq - 0.5; plot(np,(int)ypy,0); plot(np,nq,0); } else plot(np,nq,ipen); } // // Returns if no convergence is achieved on either escape or atraction. // x = xkp1; y = ykp1; } while (r <= maxiter && k<=maxiter); } } if(kbhit()) break; } ch = getch(); if (ch == '+') { //* Rotate palettes *// GetPalette(); cycle(); } else fade(); quit(); } //=========================================================================== // 1 - Initialize VESA for SVGA functions // Returns 1 if successful, or 0 if VESA BIOS not present. //=========================================================================== int initvesa(void) { typedef struct { char vesasig[4]; unsigned int version; char *oemstring; char capabilities[4]; unsigned int *videomode; unsigned int memory; char reserved[242]; } VESABLOCK; VESABLOCK vb; typedef struct { unsigned int attrib; char wina_attrib; char winb_attrib; unsigned int wingran; unsigned int winsize; unsigned int wina_seg; unsigned int winb_seg; int (*winfuncptr)(); int moreints[3]; char morechars[8]; } VESAMODE; VESAMODE vm; int ratio, count=0, modenumber; reg.x.ax = 0x4F00; reg.x.di = FP_OFF((char *)&vb); seg.es = FP_SEG((char *)&vb); int86x(0x10,®,®,&seg); if (reg.x.ax != 0x004F) /* Returns 4FH if VESA present */ { return(0); } memoryblocks = vb.memory; /* Size of video memory in 64K blocks */ while (*vb.videomode != 0xFFFF) /* Make table of all supported modes */ { /* using pointer to VESA BIOS list */ modenumber = *vb.videomode; if (modenumber > 0x99 && modenumber < 0x10A) { modetable[count] = modenumber; count++; } (vb.videomode)++; } modetable[count] = 0xFFFF; reg.x.ax = 0x4f01; reg.x.cx = 0x101; seg.es = FP_SEG((char *)&vm); reg.x.di = FP_OFF((char *)&vm); int86x(0x10,®,®,&seg); /* Now get additional information */ winfuncptr = vm.winfuncptr; /* Pointer to bank-switching function */ banksize = (long)vm.winsize << 10; /* Get bank size in bytes */ switch (banksize) { /* In case banks are < 64K */ case 65536L: locationshift = 16; break; case 16384L: locationshift = 14; break; case 4096L: locationshift = 12; } ratio = vm.winsize / vm.wingran; /* Set shift factor if necessary */ switch (ratio) { case 0x40: bankshift = 0x06; break; case 0x20: bankshift = 0x05; break; case 0x10: bankshift = 0x04; break; case 0x08: bankshift = 0x03; break; case 0x04: bankshift = 0x02; break; case 0x02: bankshift = 0x01; break; case 0x01: bankshift = 0x00; } return(1); } //=========================================================================== // 2 - Set video mode; set linetable[] array //=========================================================================== void SetMode(int mode) { int i; if (mode <= 0x13) /* VGA modes */ reg.x.ax = mode; else { reg.x.ax = 0x4F02; /* VESA SVGA modes */ reg.x.bx = mode; activebank = -1; /* For switching banks for plotting */ } int86(0x10,®,®); colors = 256; switch(mode) /* Set the flags */ { case 0x03: return; case 0x13: xres = 320; yres = 200; break; case 0x101: xres = 640; yres = 480; break; case 0x103: xres = 800; yres = 600; break; case 0x105: xres = 1024; yres = 768; break; case 0x107: xres = 1280; yres = 1024; } for (i=0;i> locationshift; offset = location - ((long)bank << locationshift); if (bank != activebank) { activebank = bank; bank = bank << bankshift; asm mov dx,[bank]; asm mov bx,0000h; asm call dword ptr [winfuncptr]; } } address = (char far *)(0xA0000000L + offset); *address = color; } //=========================================================================== // 4 - Choose 256-color video mode; check for support for chosen mode. // Returns 1 to signal quit request. //=========================================================================== int selectmode(void) { char choicekey; int mistake, count; if (!vesaflag) { mode = 0x13; return(0); } SetMode(0x03); floatscreen(7,19,LIGHTBLUE,BLUE); do /* Select graphics mode */ { mistake = 0; textcolor(BLUE); textbackground(LIGHTGRAY); _setcursortype(_NOCURSOR); gotoxy(13,7); cprintf(" 浜様様様様様様様様様様様裕突様様様様様様様様様様様様 "); gotoxy(13,8); cprintf(" SELECT GRAPHICS MODE: (Esc to quit program) "); gotoxy(13,9); cprintf(" 把陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳超 "); gotoxy(13,10); cprintf(" Make sure your monitor supports selected mode! "); gotoxy(13,11); cprintf(" 麺様様様様様様様様様様様様様様様様様様様様様様様様様郵 "); gotoxy(13,12); cprintf(" a: VGA 13H ( 320 x 200 x 256) "); gotoxy(13,13); cprintf(" b: SVGA VESA 101H ( 640 x 480 x 256) "); gotoxy(13,14); cprintf(" c: SVGA VESA 103H ( 800 x 600 x 256) "); gotoxy(13,15); cprintf(" d: SVGA VESA 105H (1024 x 768 x 256) "); gotoxy(13,16); cprintf(" e: SVGA VESA 107H (1280 x 1024 x 256) "); gotoxy(13,17); cprintf(" 把陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳超 "); gotoxy(13,18); cprintf(" "); gotoxy(13,19); cprintf(" 藩様様様様様様様様様様様様様様様様様様様様様様様様様夕 "); do { mistake = 0; /* Reset the mistake flag */ choicekey = getch(); if (choicekey > 64 && choicekey < 70) choicekey += 32; /* Caps */ if (choicekey==0x1B) return(1); /* Esc to quit */ mode = ("%d", choicekey) - 96; if (mode < 1 || mode > 5) /* Check for valid choices */ { printf("%c%c",0x07,0x07); /* Sound some warning beeps */ mistake = 1; } } while (mistake !=0); /* Repeat until valid selection */ textcolor(YELLOW + BLINK); /* Indicate the choice */ gotoxy(21, mode + 11); cprintf("%c", choicekey); textcolor(BLUE); delay(1000); switch(mode) /* Set the actual flag */ { case 1: mode = 0x13; break; case 2: mode = 0x101; break; case 3: mode = 0x103; break; case 4: mode = 0x105; break; case 5: mode = 0x107; } if (mode >= 0x100) /* Check for mode/memory support */ { count = 0; while (modetable[count] != 0xFFFF) { if (modetable[count] == mode) break; count++; } if (modetable[count] == 0xFFFF) /* Won't get to FFFFH if supported */ { gotoxy(21,18); cprintf("Mode %XH is not supported :-(", mode); delay(2000); mistake = 1; } if ((mode>0x100&&memoryblocks<8) || (mode==0x105&&memoryblocks<12) || (mode==0x107&&memoryblocks<20)) { gotoxy(21,18); cprintf("Not enough video memory for mode %XH", mode); delay(2000); mistake = 1; } } } while (mistake !=0); /* Repeat until valid selection */ textbackground(BLACK); return(0); } //=========================================================================== // 5 - Display floating input screen with ASCII block texture //=========================================================================== void floatscreen(int y1, int y2, int foreground, int shadow) { int step; textcolor(foreground); textbackground(BLACK); _setcursortype(_NOCURSOR); clrscr(); for (step=1;step<26;step++) { gotoxy(2,step); cprintf("旭旭旭旭旭旭旭葦臼臼臼臼臼臼臼渦臆臆臆臆臆臆臆"); cprintf("臼臼臼臼臼臼臼臼旭旭旭旭旭旭旭"); } textcolor(shadow); for (step=y1+1;step 126) y -= 126; outportb(0x3C8, z); outportb(0x3C9, palette[y][0]); outportb(0x3C9, palette[y][1]); outportb(0x3C9, palette[y][2]); } x += 1; if (x==126) x=0; delay(100); //* Originally, delay(50) *// } while (kbhit() == 0); getch(); getch(); fade(); } //+=================+ // Fade-out routine + //==================+ void fade(void) { int a, b, p1, p2, p3; for (a=0; a<64; a++) { while ((inportb(0x3da) & 0x08)); // Wait for vertical retrace while (!(inportb(0x3da) & 0x08)); for (b=0; b<256; b++) { outportb(0x3C7, b); p1 = inportb(0x3C9); p2 = inportb(0x3C9); p3 = inportb(0x3C9); outportb (0x3C8, b); if (p1 > 0) outportb(0x3C9, p1 - 1); else outportb(0x3C9, 0); if (p2 > 0) outportb(0x3C9, p2 - 1); else outportb(0x3C9, 0); if (p3 > 0) outportb(0x3C9, p3 - 1); else outportb(0x3C9, 0); } delay(85); } } //+============================================+ // Function to obtain current palette in array + //+============================================+ void GetPalette(void) { int p, a, b; for (a=0; a<256; a++) { outportb(0x3C7, a); for (b=0; b<3; b++) { p = inportb(0x3C9); palette[a][b] = p; } } }