myoung@ingr.UUCP (Mark Young) (01/02/88)
Good News (for me it was good news) ! for a while now, I've watched several requests get battered back and forth about information on the hercules graphics card. I kept waiting for some kind soul to fill me in on the why and wheres of programming the darn thing. well, this last week I mentioned it to a friend who steered me to a copy of "Micro Cornucopia", issue #39, Jan-Feb 1988. It has an article in it that seemed to cover most of my questions. sooo, if you were looking for the info too, look here. it may answer some of your questions too! ...myoung --- ingr!myoung!myoung@uunet.uu.net | mark allan young | where {uunet,ihnp4}!ingr!myoung!myoung | intergraph corp, cr1105 | do I WARNING: all postings from this node | one madison industrial pk | put the are monitored, so I guess I have to | huntsville, al 35807 | usual be responsible (hi dave...;-) | (205) 772-6094 | disclaimer
jsin@CS.UCLA.EDU (01/05/88)
In article <1866@ingr.UUCP> myoung@ingr.UUCP (Mark Young) writes: > >well, this last week I mentioned it to a friend who steered me to a copy of >"Micro Cornucopia", issue #39, Jan-Feb 1988. It has an article in it that >seemed to cover most of my questions. > I've spent some time typing this into my computer. It seems to work pretty well with my Herc-compatible clone card. If anyone wants a copy, send me e-mail. John (Jonghoon) Sin UCLA SEASnet Facilities InterNet: jsin@seas.ucla.edu 2567 Boelter Hall UUCP: ...!{ihnp4,ucbvax,{hao!cepu}}!ucla-cs!jsin Los Angeles, CA. 90025 VoiceNet: (213) 206-6864
jsin@CS.UCLA.EDU (01/06/88)
Hi Folks! I've received enough request for this, so I'm posting it on the net. I also included the Mandelbrot function which appeared in the same issue of MC. I thought of posting this on one of the 'sources' newsgroup, but decided against it. Sorry if that causes problem for you. Anyway, Here it is, enjoy and have fun! John Sin ------------------------------------------------------------------ /* * Graphics Routine for the Hercules Graphics Card * * Following routines were obtained from the article _A Hercules Primer_, * by Larry Fogg. (Micro Cornucopia, Issue No. 39, Jan/Feb 1988, pp 24-29.) * * Entered and Modified by John Sin, January 1988. * * * ---> 6845 Registers <--- * * Register Function Settings in Hex * (Text) (Graphics) * * 0 Total Horizontal characters 61 35 * 1 Displayed horizontal characters 50 2d * 2 Horizontal sync position 52 2e * 3 Sync width 0f 07 * 4 Total Vertical rows 19 5b * 5 Vertical total adjust 06 02 * 6 Vertical rows displayed 19 57 * 7 Vertical sync position 19 57 * 8 Interlace mode and skew 02 02 * 9 Maximum scan line address 0d 03 * 10 Cursor's starting scan line 0b 00 * 11 Cursor's ending scan line 0c 00 * * * ---> Hercules Card Ports <--- * * Register Function * * 3b8 Mode Control * 3ba Status * 3bf Configuration * 3b4 CRTC Index Register * 3b5 CRTC Data Register * */ #include <stdio.h> #include <stdlib.h> #include <dos.h> #define boolean char #define yes 1 #define no 0 #define index 0x3b4 /* 6845 ports */ #define data 0x3b5 #define mode 0x3b8 /* Herc ports */ #define status 0x3ba #define config 0x3bf /* char attributes for direct memory screen writes */ const char normal = 0x07; const char reverse = 0x70; const char under_line = 0x01; const char normal_blink = 0x87; const char reverse_blink = 0xf0; const char under_blink = 0x81; const int page0 = 0xb000; /* base address of video page */ const int page1 = 0xb800; const int text_base = 0xb000; /* base address of text pages */ const int max_col = 719; const int max_row = 347; const int screen_size = 0x800; /* bytes per page */ int page_drawn, page_viewed; /* current drawing and viewing pages */ void init() /* set initial values for global variables */ { page_drawn = page0; page_viewed = page1; } boolean herc_there() /* test for presence of Herc card */ { int i; geninterrupt (0x11); if ((_AX & 0x30) == 0x30) /* check for mono card presence */ for (i=0; i<0x800; i++) /* is it Herc Card? */ if (inportb(status) & 0x80) /* watch bit 7 */ return (yes); return (no); } void screen_off() { outportb(mode, 2); } void set_page_viewed (int page) { if (page == page0) outportb (mode, 0x0a); else outportb (mode, 0x8a); page_viewed = page; } void set_page_drawn (int page) { page_drawn = page; } void clear_gr_scr (int page) { int i; if (page_viewed == page) screen_off(); /* turn off screen if page is displayed */ for (i=0; i<0x3fff; i++) poke (page, 2*i, 0); /* reset all bits in page */ if (page_viewed == page) /* turn screen on again */ set_page_viewed (page); } void clear_txt_scr () { int i; for (i=0; i<=0x3fff; i++) /* fill text page with nuls & attribute 7*/ poke (text_base, 2*i, 0x0700); } void scr_write (int X, int Y, char str[81], char attrib) { /* direct memory write of text */ int i, offset; i = 0; offset = 2 * (80 * Y + X); /* find memory offset of first char in str */ while (str[i] != '\0') { /* poke each char/attrib pair */ pokeb (text_base, offset, str[i]); pokeb (text_base, ++offset, attrib); i++; offset++; } } void set_graphics () { char i; char params[12] = {0x35, 0x2d, 0x2e, 0x07, 0x5b, 0x02, 0x57, 0x57, 0x02, 0x03, 0x00, 0x00}; outportb (config, 3); /* allows both graphics pages */ screen_off (); for (i=0; i<12; i++) { /* program 6845 registers for graphics */ outportb (index, i); outportb (data, params[i]); } clear_gr_scr (page0); /* clear and turn on screen */ clear_gr_scr (page1); } void set_text() { char i; char params[12] = {0x61, 0x50, 0x52, 0x0f, 0x19, 0x06, 0x19, 0x19, 0x02, 0x0d, 0x0b, 0x0c}; outportb (config,0); /* lock out graphics mode */ outportb (mode, 0); /* set text mode and blank screen */ for (i=1; i<12; i++) { /* program 6845 for text */ outportb (index, i); outportb (data, params[i]); } clear_txt_scr(); outportb (mode, 0x28); /* enable blink and turn on screen */ } void save_screen (char fname[13], int page) { /* write to disk */ FILE *f; char far *screen; screen = page*0x10000; /* weird, but it works */ f = fopen (fname, "w"); fwrite (screen, screen_size, 1, f); fclose (f); } void get_screen (char fname[13], int page) { /* read from disk */ FILE *f; char far *screen; screen = page*0x10000; f = fopen (fname, "r"); screen_off(); fread (screen, screen_size, 1, f); set_page_viewed (page); /* turn the screen back on */ fclose (f); } void draw_point (int col, int row, boolean fill) { int byte_ofs; /* offset within page for byte containing the point */ char mask; /* locates point within the byte */ mask = 1 << (7 - (col % 8)); byte_ofs = 0x2000 * (row % 4) + 90 * (row/4) + (col/8); if (fill) /* draw the point */ pokeb (page_drawn, byte_ofs, peekb (page_drawn, byte_ofs) | mask); else /* erase the point */ pokeb (page_drawn, byte_ofs, peekb (page_drawn, byte_ofs) & ~mask); } void draw_line (int X1, int Y1, int X2, int Y2, boolean on) { /* use Bresenham's algorithm to draw a line */ boolean pos_slope; int dX, dY, /* vector components */ row, col, final, /* final row or col number */ G, /* used to test for new row or column */ inc1, /* G increment when row or column doesn't change */ inc2; /* G increment when row or column does change */ dX = X2 - X1; dY = Y2 - Y1; /* find vector component */ pos_slope = (dX > 0); /* is slope positive? */ if (dY < 0) pos_slope = !pos_slope; if (abs(dX) > abs(dY)) { /* shallow line case */ if (dX > 0) { /* determine start point and last column */ col = X1; row = Y1; final = X2; } else { col = X1; row = Y2; final = X1; } inc1 = 2*abs(dY); /* determine increments and initial G */ G = inc1 - abs(dX); inc2 = 2 * (abs(dY) - abs(dX)); if (pos_slope) while (col<=final) { /* step thru cols. checking for new row */ draw_point (col, row, on); col++; if (G >= 0) { /* it's time to change rows */ row++; G+= inc2; /* positive slope, so inc thru rows */ } else /* stay at the same row */ G += inc1; } /* while */ else while (col<=final) { /* step thru cols, check for new row */ draw_point (col, row, on); col++; if (G > 0) { /* time to change the rows */ row--; G+= inc2; /* negative slope, dec thru rows */ } else G += inc1; /* stay at the same row */ } /* while */ } /* if |dX| > |dY| */ else { if (dY > 0) { /* steep line case, angle > 45 degree */ col = X1; row = Y1; final = Y2; /* find start point and last row */ } else { col = X2; row = Y2; final = Y1; } inc1 = 2 * abs(dX); /* determine increments and initial G */ G = inc1 - abs(dY); inc2 = 2 * (abs(dX) - abs(dY)); if (pos_slope) while (row <= final) { /* step thru rows - check for new column */ draw_point (col, row, on); row++; if (G >= 0) { /* it's time to change columns */ col++; G+= inc2; /* pos. slope, increment thru cols. */ } else G += inc1; /* stay at the same column */ } /* while */ else while (row <= final) {/* step thru rows, checking for new column */ draw_point (col, row, on); row++; if (G > 0) { /* it's time to change columns */ col--; G+= inc2; /* neg slope, so decrement thru columns */ } else G += inc1; /* stay at the same column */ } /* while */ } /* if |dY| > |dX| */ } /**************************************************************************/ /* Subroutine MANDEL() from the same issue */ #define sqr(x) (x*x) #define MAX_ITERATIONS 100 #define MAX_SIZE 4 const int max_colors = 2; void mandel (float Pmax, float Pmin, float Qmax, float Qmin) { int color, row, col; float P, Q, modulus, deltaP, deltaQ, Xcur, Xlast, Ycur, Ylast; deltaP = (Pmax - Pmin) / (max_col - 1); deltaQ = (Qmax - Qmin) / (max_row - 1); for (col = 0; col <= max_col; col++) for (row = 0; row <= max_row; row++) { P = Pmin + col * deltaP; Q = Qmin + row * deltaQ; Xlast = Ylast = modulus = 0.0; color = 0; while ( (modulus < MAX_SIZE) && (color < MAX_ITERATIONS) ) { Xcur = sqr (Xlast) - sqr (Ylast) + P; Ycur = 2 * Xlast * Ylast + Q; color++; Xlast = Xcur; Ylast = Ycur; modulus = sqr (Xcur) + sqr (Ycur); } /* while */ draw_point (col, row, (color % max_colors)); } /* for */ } /* mandel */ /****************************************************************************/ John (Jonghoon) Sin UCLA SEASnet Facilities InterNet: jsin@seas.ucla.edu 2567 Boelter Hall UUCP: ...!{ihnp4,ucbvax,{hao!cepu}}!ucla-cs!jsin Los Angeles, CA. 90025 VoiceNet: (213) 206-6864