Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!uwm.edu!spool.mu.edu!munnari.oz.au!manuel!csis!anucsd!pdact!dbell From: dbell@pdact.pd.necisa.oz.au (David I. Bell) Newsgroups: comp.os.minix Subject: MINI-X graphics package (part 6/9) Message-ID: <997@pdact.pd.necisa.oz.au> Date: 22 Apr 91 00:55:33 GMT Organization: NEC Information Systems Australia, Canberra Lines: 1318 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'mini-x/README' <<'END_OF_FILE' X MINI-X GRAPHICS NOTES X David I. Bell X 22 Apr 91 X XThis is my mini-X graphics package for MINIX 1.5. It has been designed to Xwork for various types of machines, but the only low level support routines Xprovided are for the IBM PC running a 386 in 32-bit protected mode. If Xsomeone writes the device routines for other machines such as Amiga or Mac, Xthen this code could work on them too. This code is also only written for Xa serial mouse accessed using a normal tty line. If you have a bus mouse, Xor have a mouse device driver, then you will have to modify the mouse code Xappropriately. X XThis code is not TOO large, and doesn't require TOO much table space. Even Xso, it will probably not run on machines with 64K limits. So before trying Xthis package, you MUST first install Bruce Evan's 32-bit patches since some Xof the code assumes this. (If someone wants to try, I am sure that it would Xfit in 64K if the graphics code ran in its own address space, like mm and fs. XHowever, this requires much more kernel hacking than I wanted to do.) X XI have also installed the virtual console code in my kernel, but I do not Xthink that this is required. I have done nothing to make the virtual Xconsole code and the graphics code aware of each other (but this would Xbe nice someday). What interactions there are between the two will be Xdiscussed under the bugs section. The virtual console code will only Xaffect the device number used for /dev/graphics, and the name of the tty Xport used for the serial mouse. X XI am also running shoelace, but this should not affect things either except Xfor the manner in which you back up old kernels when building new ones. X XYou must also have a version of CPP which works. The one I got from the XMINIX archives works, but required several patches to make it useable for Xbuilding the MINIX kernel. This CPP is from "cpp.tar.Z", written by Martin XMinow. It needed patches to disable errors for unquoted strings, and errors Xwhen #if SYMBOL was used where SYMBOL was not defined. If you have already Xrebuilt your own kernels in 32-bit mode, you must have already gotten around Xthese problems. If not, then I have included patches to this version of CPP Xfor the above problems if you need them. X XThe graphics code consists of two parts. The first part is kernel code, Xwhich implements a new device type of /dev/graphics. There are small Xpatches to several files in order to make the device accessible to the Xrest of the system. There are one or two small assembly routines needed Xto support the main graphics code. Everything else is in new files in the Xkernel directory. I have deliberately avoided changing existing code as Xmuch as possible for this first release. Therefore, I expect that you Xshould not have much trouble installing this code into the operating system, Xexcept for the known problems with using CPP. X XThe second part is the graphics server code. Eventually, the graphics Xserver will be a process by itself, and will just be a program that you Xstart up, and then run clients which open connections to it. But in this Xrelease, the server code must be loaded with each client. Therefore, Xthe graphics server is built into a library that you just search when Xloading your client program. The server code is self-contained, and is Xin its own directory called "/usr/src/graphics/server". X XFor clients, the built server library "libgraph.a" must be moved into the Xlibrary directory (/usr/local/lib/i386) and the include file "graphics.h" Xmust be put into /usr/include for clients to use. I expect that client Xprograms (whenever they are written) would be placed into the directory X"/usr/src/graphics/clients". The only clients I have provided are a demo Xprogram and a program to reset the terminal back into text mode. X XThe demo program is simple and doesn't do much, but it shows how to open the Xgraphics device, determine the size of the screen and what black and white Xcolor values are, create windows and graphics contexts, draw lines, circles, Xand text, change graphics contexts in order to change colors, read keyboard Xand mouse events, handle several other types of events, and catch fatal Xerrors. It also demonstrates how to set input focus, how to draw rubber- Xbanded lines, how to track the mouse constantly, and how to perform Xbackground calculations while waiting for events. This should be enough Xexamples to get you started writing your own stuff. X XI have also written a simple tutorial on the use of the graphics functions, Xand some concepts that you need to know if you don't know X-style graphics. XThis is called TUTORIAL. X X XINSTALLATION INSTRUCTIONS X XDetailed instructions on installing and testing the graphics routines follow. XIn all the following, you are logged in as root. X XYou should first copy the mini-X package into a temporary directory where Xyou can examine and play with the files without harming anything. XNOTE: The following instructions assume that you are using the directory X"/mini-x" for your temporary directory. X X XUnpacking the mini-X package creates the following directories: X include include files for /usr/include and /usr/include/minix X kernel changes to /usr/src/kernel X fs changes to /usr/src/fs X server server library to be put into /usr/src/graphics/server X clients client programs to be put in /usr/src/graphics/clients X cpp patches for Martin Minow's CPP program X X XPART A, BUILDING THE KERNEL: X X1. If you have a working version of CPP that doesn't complain about X misquoted strings or undefined symbols, then skip this step. X Otherwise, you can get the CPP from the MINIX archives, and apply X the patches from the cpp directory to it. These are for the X files "cpp5.c" and "cpp6.c". Install the new CPP for use. X X2. Copy the two include files from the include directory to the X system include directories. One belongs in /usr/include, and the X other belongs in /usr/include/minix. X cd /mini-x/include X cp graphics.h /usr/include X cp graph_msg.h /usr/include/minix X chmod 644 /usr/include/graphics.h X chmod 644 /usr/include/minix/graph_msg.h X X3. Copy or backup the following files in your kernel and fs directory X so that you can undo the changes to them if required. Even better, X if you have disk space, then copy ALL of the current kernel and fs X directories to make sure they are safe. X fs/table.c X kernel/cstart.c X kernel/glo.h X kernel/klib386.x X kernel/makefile.cpp X kernel/makefile X kernel/proto.h X kernel/start.x X kernel/table.c X kernel/tty.c X X4. Copy the existing minix image onto a bootable diskette so in case X the new one doesn't work, you can still bring the old MINIX back up. X If you are running shoelace like I am, then you can just copy the X kernel and fs into backup files in /etc/system. For example: X cd /etc/system X cp kernel old_kernel X cp fs old_fs X X5. Copy the cdiff file from fs/table.c into /usr/src/fs, and X apply it. Then build a new fs. X cd /usr/src/fs X cp /mini-x/fs/table.c.cdif . X patch table.c table.c.cdif X make X X6. Copy the files from the kernel directory into /usr/src/kernel. X Some of these files are cdiff files and some are new files. X cd /usr/src/kernel X cp /mini-x/kernel/* . X X7. Patch some of the files in the kernel directory. X cd /usr/src/kernel X patch cstart.c cstart.c.cdif X patch glo.h glo.h.cdif X patch klib386.x klib386.x.cdif X patch proto.h proto.h.cdif X patch start.x start.x.cdif X patch table.c table.c.cdif X patch tty.c tty.c.cdif X X8. You must now manually edit start.x, and insert the routine which X is in start.x.insert into it. The reason for this is that cdiff X (and diff) gave the wrong results when I attempted to build patch X files, and so this part must be done manually. In start.x, after X the routine get_ega, and before the routine get_ext_memsize, read in X the file start.x.insert (containing the routine get_rom_char_addr). X Leave two blank lines before and after the new routine. X X9. You must now create a correct makefile. I have given you cdiffs X for the original makefile source, "makefile.cpp.cdif", and for the X resulting file "makefile.cdif". You can try using these to patch X makefile.cpp and makefile. Alternatively, I have also given you X complete new copies of makefile.cpp and makefile with the patches X already applied, as "makefile.new" and "makefile.cpp.n". Make use X of these however you can. The reason I have given you all these X versions is because of the CPP problems. Assuming that the new X makefile I supply is correct as is, then simply do the following: X cp makefile.cpp.n makefile.cpp X cp makefile.new makefile X X If you must rebuild a new makefile from makefile.cpp, then as X described in the original porting notes for the 32-bit kernel, X you must do the following. Edit out extraneous # lines from the X makefile.cpp file, then run a version of CPP on the makefile.cpp X to produce makefile. Then you must edit that makefile and again X remove the # lines, and convert the string "/usr/include/1" back X to "/usr/include/minix", and restore the leading tabs on the build X lines. If you have already tried playing with rebuilding your X kernel in 32-bit mode, then you know these problems already. X X10. Run Bruce Evan's config script in /usr/src/kernel to produce a new X klib.x from the modified klib386.x. Alternatively, just copy it. X As I mentioned above, I have patches only for the 32-bit kernel. X cd /usr/src/kernel X cp klib386.x klib.x X X11. Build the kernel. There should be no more warning messages during X the load than there used to be. X cd /usr/src/kernel X make X X12. Make the new /dev/graphics file which is a character device. If X you have added extra devices to your system, then you must use the X correct major device number (instead of 7) in the mknod command. X Examine dmap in /usr/src/fs/table.c to make sure of the number. X mknod /dev/graphics c 7 0 X chmod 666 /dev/graphics X X13. Sync and Reboot the system and verify that the system works correctly. X Then you can try copying a file to /dev/graphics if you want, and X nothing should happen except that you should get an I/O error. This X is normal, since the format of the data sent to the graphics device X includes a magic number which is validated. For example: X cp /etc/passwd /dev/graphics X cp: I/O error X X X XPART B, BUILDING THE GRAPHICS SERVER: X X1. Create the directories /usr/src/graphics and /usr/src/graphics/server. X cd /usr/src X mkdir graphics X chmod 755 graphics X cd graphics X mkdir server X chmod 755 server X X2. Copy the files from the server directory to /usr/src/graphics/server. X cd /usr/src/graphics/server X cp /mini-x/server/* . X X3. Examine the configuration of your machine, and define the mouse X type and mouse port names appropriately. This is in the file X "mousedev.c", and the defines are MOUSE_TYPE and MOUSE_PORT. X MOUSE_TYPE specifies the type of mouse, where "ms" is a Microsoft X mouse (two buttons), and "pc" is a PC mouse (three buttons). X The default is "ms". MOUSE_PORT specifies the tty device name X which the mouse is plugged into. Since I am running the virtual X console code, the default value is "/dev/tty64". If your mouse is X plugged into a different tty, then change MOUSE_PORT to use it. X X4. Examine the makefile to determine where the graphics library X should go. The default library directory is /usr/local/lib/i386, X and is the directory that Bruce Evan's 32-bit patches uses. If X you have changed this, then edit LIBDIR in the makefile to point X at the correct library directory. X X5. Build the graphics server library by typing make. The library X name is called "libgraph.a". X cd /usr/src/graphics/server X make X X6. Copy the built library into the library directory. X make install X X X XPART C, BUILDING THE DEMO PROGRAM AND THE TERMINAL RESET MODE PROGRAM: X X1. Create the /usr/src/graphics/clients directory, and copy the X files from the clients directory into it. X cd /usr/src/graphics X mkdir clients X chmod 755 clients X cd clients X cp /mini-x/clients/* . X X2. Build the clients demo and tm. Demo is the demonstration graphics X program, and tm is the "text mode" program, which is used to reset X the console back into text mode if a graphics program bombs out. X make X X3. Try demo. It should bring up several colored windows, with circles X being constantly drawn in the upper left one. Move the mouse, and X a cursor should track its motion. Moving the mouse into the small X grey window at the top middle should leave a trail of colored dots. X Using the button in the window at the upper right should let you X draw lines. Moving the mouse into or out of the left window should X cause it to raise or lower itself, and change its border color. X Moving the mouse into or out of the large window should cause the X window to change it border color. Clicking the mouse in the large X window should raise it to the top. Typing characters while the mouse X is in the window should display them in the window. The large window X should contain a filled rectangle and a filled triangle. Clicking X the button in the small top window should take a snapshot of the X circles being drawn and display that in the upper left of the large X window, blown up by a factor of 2. The cursor should change its X shape when it enters or exits the circles window, or the large window. X Releasing a button while the mouse in in the circles window exits X from the demo. Alternatively, pressing more than one button when X the mouse is in the root window should cause a purposely generated X fatal error. X X4. Install the demo program and tm program into /bin. If you wish a X different destination directory then /bin, then edit makefile and X change BINDIR as appropriate. Also change LIBRARIES in the makefile X if your library directory is not /usr/local/lib/i386. X make install X X XThat's it! X X XPORTING NOTES FOR OTHER MACHINES X XI do not understand how MINIX runs on Macs or Amigas, so I cannot say much Xhere, except to point out which files probably need changing, and what Xthose changes are likely to be. X XThe files graph_ega.c and ega.x are the only files which reference the Xgraphics hardware. The first file is the high level code which interfaces Xto the rest of the device driver, and the second is the low level graphics Xroutines in assembly. All calls to the graphics device are made through Xprocedure variables in the gr_dev structure, which is typedef'd in the Xfile graph_dev.h, and defined in graph_ega.c. A typical call looks like X(*gr_dev.drawpoint)(x, y, color). X XThe procedure variables can call either the device specific routines, Xor the general routines. The general routines are all in graph_gen.c. XThe general routines call other lower-level routines, also through the Xgr_dev structure. Eventually, the lowest level routine is reached which Xis the drawing of a single pixel. This routine cannot be a general Xroutine, it must be a device specific routine. X XIn order to implement a new graphics device, copy graph_ega.c into a new Xfile (say, graph_foo.c), and modify it as required. For those functions Xwhich can be done by the general routines (such as drawing lines), make Xthe entries in the gr_dev structure point at the general routines. For those Xfunctions which you can do in your hardware specific code, make the entries Xpoint to your own function. You MUST have certain functions implemented as Xyour own routines. These are the init, term, setmode, drawpoint, drawtext, Xsizetext, readpoint, getcharbits, getscreeninfo, and getfontinto functions. XThe other functions can use the generic routines in graph_gen, if desired. XLater, you can replace the generic routines with device specific routines Xfor performance gains (especially drawing of lines and filling of areas). X XThe gr_dev structure also contains parameters which give the configuration Xof the graphics screen, such as the number of rows, columns, and colors. XIf these are constant, you can just define them as initialized data in the Xstructure definition. However, if they vary (you may have more than one Xgraphics mode available), then you can set them dynamically when the init Xroutine is called. The init routine is called with the requested number of Xrows, columns, and colors. If any value is 0, then you can choose it. XOtherwise, you should honor the request, returning an error from the init Xroutine if this is impossible. (The current ega_init routine is such an Xexample, but it only accepts the 640x350 16 color mode. It could be Xenhanced to support other modes too.) X XNote that the device level routines do not need to know about clipping. XHowever, it is probably a good idea to put in checks to make sure that Xthe arguments are within the screen area, just to be safe. You can Xignore drawing requests which attempt to go off of the screen, since Xthey should not happen. X XOnce you have made your new module, just change the makefile to build Xyour graph_foo module, and any other new modules you made, and remove Xthe use of graph_ega.c and ega.x. Your gr_dev structure will then be Xused instead of the EGA one, and the higher level graphics functions Xwill call your code. X XI cannot say much about interfacing the mouse, or returning modifiers from Xthe keyboard. One of you will have to investigate this. X X XBUGS X XThe following is a list of things which do not work as I desire. Maybe Xsomeone can send me (or post) fixes or code for some of these things. X X1. One line is missing at the bottom of the screen. I don't know why, X but the screen resolution is actually 640 by 349 on my EGA. X X2. If the client or any other process outputs normally to the screen, X this will mess up the screen with rubbish. This is because the X console code and the graphics code know nothing about each other. X Someday the console should be told to leave the screen alone, or X else it can send messages to the graphics server to draw characters X for it. (This is an argument to keep the graphics code in the X kernel, instead of moving it out to user space.) X X3. When the graphics program closes the screen, it is blanked, but X previous text and the cursor do not reappear. When running the X virtual console code, typing a few returns to cause the screen X to scroll will fix things. Once again, this is because the X console and graphics know nothing about each other. Someday the X graphics code should send a message to the console driver to fix X the screen. X X4. The graphics device needs to know about the last close for it, so X that it can automatically reset the console back into text mode. X Then the tm program would be unnecessary. X X5. The graphics device really should be a once-open device, to prevent X attempts by multiple clients to open it. If multiple clients do X open it, they will interfere with each other. X X6. There is no way to obtain the state of the the modifiers from the X keyboard. These are SHIFT, CTRL, and ALT. So currently there are X no modifiers available for clients to use. The keyboard driver X knows these things, what is required is a way of obtaining them. X A simple way is to just make an IOCTL which returns the state. X Races can occur with this, so to do it right requires much more X extensive hacking in the keyboard driver to make sure the modifiers X are correct for each character read. X X7. All the graphics programs busy loop. So while events are being X waited for, the program constantly tries to read the newest status X from the mouse and keyboard. Fixing this requires some form of X poll or select. X X XFUTURES X XI have not thought much about window managers. There is no code to support Xthem at present. For mini-X, I do not really see the need for an external Xwindow manager, with all of its complications. It seems better to have a Xbuilt-in window manager in the server. However, it must interact with the Xrest of the server code in a small number of well-defined ways. The reason Xfor this is to allow multiple versions of the window mananger to be built, Xso that everyone can run the one they want. If the interface was correct, Xthen you could replace the window manager code with your own window manager Xwith no problems. As I said, I think this is adequate for mini-X. X XChanging the server code to run with multiple clients is needed. This Xrequires some form of cross-process communication, and POLL to be able to Xselect on the clients. The amoeba routines are not adequate, because Xthey assume an RPC-type network call. The server must be able to read and Xwrite from multiple clients, in any order, so that there can be many Xoutstanding replies. Named pipes could be used, but they are rather ugly. X XPoll is needed even without multiple clients, in order to stop the busy Xloop that the server does. For a single user machine, a busy loop is not Xtoo bad, but it still slows down compiles and such. It is better to fix it. X XPixmaps would be useful. Without them, doing redraws when exposures occur Xbecomes very hard. The code currently has stubs for the pixmap routines, Xso adding them would not be very difficult. X XLoadable fonts would be nice. Currently the only fonts are the ones known Xby the device driver (and there is only 1 of those!). The server would Xread a font from a file into memory, and then use the bitmap drawing Xprimitives to draw the characters. The bitmap drawing routines would Xthen need some performance enhancements, such as adding a low level device Xfunction to do it. X XPtys would be needed for building xterms. X XHigher resolution modes for the VGA would be nice to have. X XRoutines are needed to convert color names into color values. I have Xstarted this, but don't have it ready for this posting. Hardwiring Xconstants into client programs for colors is not good. X XLots of client programs to do nifty graphics would be nice. Some games Xusing them would be fun. I plan to post some later. X XSpeedups for various operations would be nice. Some operations are much Xslower and uglier than they need to be. X XFinally, I do **NOT** want to implement everything that the real X has. XIf you want all that, then buy some more memory, run UNIX, and run the Xreal thing. What I do want are the smallest changes that do the most Xgood. In other words, weigh the cost of a feature with the usefulness Xof the feature. The best features are the ones which win real big with Xonly a little bit of effort. I am sure that you all will argue for hours Xabout which features are the really necessary ones... X X XI hope this stuff will be as fun and useful to you as it is for me. I Xwill answer questions and coordinate changes and bug fixes to the code as Xpeople request it (as long as I am not TOO swamped with them). However, Xif someone else wants to volunteer to do this, then that is OK by me too. X(Especially for non-IBM machines, which I know nothing about.) X X XDavid I. Bell NEC Information Systems Australia Xdbell@pdact.pd.necisa.oz.au SDC Canberra END_OF_FILE if test 22803 -ne `wc -c <'mini-x/README'`; then echo shar: \"'mini-x/README'\" unpacked with wrong size! fi # end of 'mini-x/README' fi if test -f 'mini-x/kernel/graph_main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mini-x/kernel/graph_main.c'\" else echo shar: Extracting \"'mini-x/kernel/graph_main.c'\" \(21918 characters\) sed "s/^X//" >'mini-x/kernel/graph_main.c' <<'END_OF_FILE' X/* Copyright (c) 1991 David I. Bell X * Permission is granted to use, distribute, or modify this source, X * provided that this copyright notice remains intact. X * X * Top level drawing primitives. X * These routines do the necessary range checking, clipping, and cursor X * overwriting checks, and then call the lower level device dependent X * routines to actually do the drawing. The lower level routines are X * only called when it is known that all the pixels to be drawn are X * within the device area and are visible. X */ X X#include "kernel.h" X#include "graph_dev.h" X X X/* Global symbols used throughout the graphics code. */ XGR_COLOR gr_foreground; /* current foreground color */ XGR_COLOR gr_background; /* current background color */ XGR_BOOL gr_usebg; /* TRUE if background drawn in pixmaps */ XGR_BOOL gr_error; /* true if error occurred */ XGR_MODE gr_mode; /* drawing mode */ X X X#define min(a,b) ((a) < (b) ? (a) : (b)) X XFORWARD void drawrow(); XFORWARD void drawcol(); XFORWARD void draw4points(); XFORWARD void extendrow(); X X X/*===========================================================================* X * fillellipse * X *===========================================================================*/ XPUBLIC void fillellipse(x, y, rx, ry) XGR_COORD x, y; /* coordinates of center of ellipse */ XGR_SIZE rx; /* radius along x axis */ XGR_SIZE ry; /* radius along y axis */ X{ X/* Fill an ellipse in the foreground color, applying clipping if necessary. */ X int xp, yp; /* current point (based on center) */ X long Asquared; /* square of x semi axis */ X long TwoAsquared; X long Bsquared; /* square of y semi axis */ X long TwoBsquared; X long d; X long dx, dy; X X if ((rx < 0) || (ry < 0)) return; X X /* See if the ellipse is either totally visible or totally invisible. X * If so, then the ellipse drawing is easy. X */ X switch (cliparea(x - rx, y - ry, x + rx, y + ry)) { X case GR_CLIP_VISIBLE: X (*gr_dev.fillellipse) (x, y, rx, ry, gr_foreground); X /* Fall into return */ X case GR_CLIP_INVISIBLE: return; X} X X xp = 0; X yp = ry; X Asquared = rx * rx; X TwoAsquared = 2 * Asquared; X Bsquared = ry * ry; X TwoBsquared = 2 * Bsquared; X d = Bsquared - Asquared * ry + (Asquared >> 2); X dx = 0; X dy = TwoAsquared * ry; X X while (dx < dy) { X drawrow(x - xp, x + xp, y - yp); X drawrow(x - xp, x + xp, y + yp); X if (d > 0) { X yp--; X dy -= TwoAsquared; X d -= dy; X } X xp++; X dx += TwoBsquared; X d += (Bsquared + dx); X } X d += ((3L * (Asquared - Bsquared) / 2L - (dx + dy)) >> 1); X while (yp >= 0) { X drawrow(x - xp, x + xp, y - yp); X drawrow(x - xp, x + xp, y + yp); X if (d < 0) { X xp++; X dx += TwoBsquared; X d += dx; X } X yp--; X dy -= TwoAsquared; X d += (Asquared - dy); X } X} X X X/*===========================================================================* X * drawpoint * X *===========================================================================*/ XPUBLIC void drawpoint(x, y) XGR_COORD x; XGR_COORD y; X{ X/* Draw an individual point in the foreground color, applying X * clipping if necessary. X */ X if (clippoint(x, y)) (*gr_dev.drawpoint) (x, y, gr_foreground); X} X X X/*===========================================================================* X * drawline * X *===========================================================================*/ XPUBLIC void drawline(x1, y1, x2, y2) XGR_COORD x1; XGR_COORD y1; XGR_COORD x2; XGR_COORD y2; X{ X/* Draw an arbitrary line in the foreground color, applying X * clipping if necessary. X */ X int xdelta; /* width of rectangle around line */ X int ydelta; /* height of rectangle around line */ X int xinc; /* increment for moving x coordinate */ X int yinc; /* increment for moving y coordinate */ X int rem; /* current remainder */ X X /* See if the line is horizontal or vertical. If so, then call X * special routines. X */ X if (y1 == y2) { X drawrow(x1, x2, y1); X return; X } X if (x1 == x2) { X drawcol(x1, y1, y2); X return; X } X X /* See if the line is either totally visible or totally invisible. If X * so, then the line drawing is easy. X */ X switch (cliparea(x1, y1, x2, y2)) { X case GR_CLIP_VISIBLE: X (*gr_dev.drawline) (x1, y1, x2, y2, gr_foreground); X /* Fall into return */ X case GR_CLIP_INVISIBLE: return; X} X X /* The line may be partially obscured. Do the draw line algorithm X * checking each point against the clipping regions. X */ X xdelta = x2 - x1; X ydelta = y2 - y1; X if (xdelta < 0) xdelta = -xdelta; X if (ydelta < 0) ydelta = -ydelta; X xinc = (x2 > x1) ? 1 : -1; X yinc = (y2 > y1) ? 1 : -1; X if (clippoint(x1, y1)) (*gr_dev.drawpoint) (x1, y1, gr_foreground); X if (xdelta >= ydelta) { X rem = xdelta / 2; X do { X x1 += xinc; X rem += ydelta; X if (rem >= xdelta) { X rem -= xdelta; X y1 += yinc; X } X if (clippoint(x1, y1)) X (*gr_dev.drawpoint) (x1, y1, gr_foreground); X } while (x1 != x2); X } else { X rem = ydelta / 2; X do { X y1 += yinc; X rem += xdelta; X if (rem >= ydelta) { X rem -= ydelta; X x1 += xinc; X } X if (clippoint(x1, y1)) X (*gr_dev.drawpoint) (x1, y1, gr_foreground); X } while (y1 != y2); X } X} X X X/*===========================================================================* X * drawrow * X *===========================================================================*/ XPRIVATE void drawrow(x1, x2, y) XGR_COORD x1; XGR_COORD x2; XGR_COORD y; X{ X/* Draw a horizontal line in the foreground color, applying X * clipping if necessary. X */ X GR_COORD temp; X X if (x1 > x2) { X temp = x1; X x1 = x2; X x2 = temp; X } X if (x1 < 0) x1 = 0; X if (x2 >= gr_dev.cols) x2 = gr_dev.cols - 1; X X (*gr_dev.checkcursor) (x1, y, x2, y); X X while (x1 <= x2) { X if (clippoint(x1, y)) { X temp = min(clipmaxx, x2); X (*gr_dev.drawrow) (x1, temp, y, gr_foreground); X } else X temp = min(clipmaxx, x2); X x1 = temp + 1; X } X} X X X/*===========================================================================* X * drawcol * X *===========================================================================*/ XPRIVATE void drawcol(x, y1, y2) XGR_COORD x; XGR_COORD y1; XGR_COORD y2; X{ X/* Draw a vertical line in the foreground color, applying X * clipping if necessary. X */ X GR_COORD temp; X X if (y1 > y2) { X temp = y1; X y1 = y2; X y2 = temp; X } X if (y1 < 0) y1 = 0; X if (y2 >= gr_dev.rows) y2 = gr_dev.rows - 1; X X (*gr_dev.checkcursor) (x, y1, x, y2); X X while (y1 <= y2) { X if (clippoint(x, y1)) { X temp = min(clipmaxy, y2); X (*gr_dev.drawcol) (x, y1, temp, gr_foreground); X } else X temp = min(clipmaxy, y2); X y1 = temp + 1; X } X} X X X/*===========================================================================* X * drawrect * X *===========================================================================*/ XPUBLIC void drawrect(x, y, width, height) XGR_COORD x; XGR_COORD y; XGR_COORD width; XGR_COORD height; X{ X/* Draw a rectangle in the foreground color, applying clipping if necessary. X * This is careful to not draw points multiple times in case the rectangle X * is being drawn using XOR. X */ X GR_COORD maxx; X GR_COORD maxy; X X if ((width <= 0) || (height <= 0)) return; X maxx = x + width - 1; X maxy = y + height - 1; X drawline(x, y, maxx, y); X if (height > 1) drawline(x, maxy, maxx, maxy); X if (height < 3) return; X y++; X maxy--; X drawline(x, y, x, maxy); X if (width > 1) drawline(maxx, y, maxx, maxy); X} X X X/*===========================================================================* X * fillrect * X *===========================================================================*/ XPUBLIC void fillrect(x1, y1, x2, y2) XGR_COORD x1; XGR_COORD y1; XGR_COORD x2; XGR_COORD y2; X{ X/* Draw a filled in rectangle in the foreground color, applying X * clipping if necessary. X */ X GR_COORD temp; X X if (y1 == y2) { X drawrow(x1, x2, y1); X return; X } X if (x1 == x2) { X drawcol(x1, y1, y2); X return; X } X if (x1 > x2) { X temp = x1; X x1 = x2; X x2 = temp; X } X if (y1 > y2) { X temp = y1; X y1 = y2; X y2 = temp; X } X X /* See if the rectangle is either totally visible or totally X * invisible. If so, then the rectangle drawing is easy. X */ X switch (cliparea(x1, y1, x2, y2)) { X case GR_CLIP_VISIBLE: X (*gr_dev.fillrect) (x1, y1, x2, y2, gr_foreground); X /* Fall into return */ X case GR_CLIP_INVISIBLE: return; X} X X /* The rectangle may be partially obstructed. So do it line by line. */ X while (y1 <= y2) drawrow(x1, x2, y1++); X} X X X/*===========================================================================* X * drawpoly * X *===========================================================================*/ XPUBLIC void drawpoly(points, count) XGR_POINT *points; XGR_COUNT count; X{ X/* Draw a polygon in the foreground color, applying clipping if necessary. X * The polygon is only closed if the first point is repeated at the end. X * Some care is taken to plot the endpoints correctly if the current X * drawing mode is XOR. However, internal crossings are not handled X * correctly. X */ X GR_COORD firstx; X GR_COORD firsty; X GR_BOOL didline; X X if (count < 2) return; X firstx = points->x; X firsty = points->y; X didline = GR_FALSE; X X while (count-- > 1) { X if (didline && (gr_mode == GR_MODE_XOR)) X drawpoint(points->x, points->y); X drawline(points[0].x, points[0].y, points[1].x, points[1].y); X points++; X didline = GR_TRUE; X } X if (gr_mode != GR_MODE_XOR) return; X points--; X if ((points->x == firstx) && (points->y == firsty)) X drawpoint(points->x, points->y); X} X X X/*===========================================================================* X * fillpoly * X *===========================================================================*/ XPUBLIC void fillpoly(points, count) XGR_POINT *points; XGR_COUNT count; X{ X/* Fill a polygon in the foreground color, applying clipping if necessary. X * Note: this routine currently only correctly fills convex polygons. X */ X GR_POINT *pp; /* current point */ X GR_COORD miny; /* minimum row */ X GR_COORD maxy; /* maximum row */ X GR_COORD minx; /* minimum column */ X GR_COORD maxx; /* maximum column */ X GR_COUNT i; /* counter */ X X if (count <= 0) return; X X /* First determine the minimum and maximum rows for the polygon. */ X pp = points; X miny = pp->y; X maxy = pp->y; X for (i = count; i-- > 0; pp++) { X if (miny > pp->y) miny = pp->y; X if (maxy < pp->y) maxy = pp->y; X } X if (miny < 0) miny = 0; X if (maxy >= gr_dev.rows) maxy = gr_dev.rows - 1; X if (miny > maxy) return; X X /* Now for each row, scan the list of points and determine the X * minimum and maximum x coordinate for each line, and plot the row. X * The last point connects with the first point automatically. X */ X for (; miny <= maxy; miny++) { X minx = GR_COORD_MAX; X maxx = GR_COORD_MIN; X pp = points; X for (i = count; --i > 0; pp++) { X extendrow(miny, pp[0].x, pp[0].y, pp[1].x, X pp[1].y, &minx, &maxx); X } X extendrow(miny, pp[0].x, pp[0].y, points[0].x, X points[0].y, &minx, &maxx); X X if (minx <= maxx) drawrow(minx, maxx, miny); X } X} X X X/*===========================================================================* X * extendrow * X *===========================================================================*/ XPRIVATE void extendrow(y, x1, y1, x2, y2, minxptr, maxxptr) XGR_COORD y; /* row to check for intersection */ XGR_COORD x1; /* x coordinate of first endpoint */ XGR_COORD y1; /* y coordinate of first endpoint */ XGR_COORD x2; /* x coordinate of second endpoint */ XGR_COORD y2; /* y coordinate of second endpoint */ XGR_COORD *minxptr; /* address of current minimum x */ XGR_COORD *maxxptr; /* address of current maximum x */ X{ X/* Utility routine for filling polygons. Find the intersection point (if X * any) of a horizontal line with an arbitrary line, and extend the current X * minimum and maximum x values as needed to include the intersection point. X */ X GR_COORD x; /* x coordinate of intersection */ X long num; /* numerator of fraction */ X X /* First make sure the specified line segment includes the specified X * row number. If not, then there is no intersection. X */ X if (((y < y1) || (y > y2)) && ((y < y2) || (y > y1))) return; X X /* If a horizontal line, then check the two endpoints. */ X if (y1 == y2) { X if (*minxptr > x1) *minxptr = x1; X if (*minxptr > x2) *minxptr = x2; X if (*maxxptr < x1) *maxxptr = x1; X if (*maxxptr < x2) *maxxptr = x2; X return; X } X X /* If a vertical line, then check the x coordinate. */ X if (x1 == x2) { X if (*minxptr > x1) *minxptr = x1; X if (*maxxptr < x1) *maxxptr = x1; X return; X } X X /* An arbitrary line. Calculate the intersection point using the X * formula x = x1 + (y - y1) * (x2 - x1) / (y2 - y1). X */ X num = ((long) (y - y1)) * ((long) (x2 - x1)); X x = x1 + num / (y2 - y1); X if (*minxptr > x) *minxptr = x; X if (*maxxptr < x) *maxxptr = x; X} X X X/*===========================================================================* X * drawellipse * X *===========================================================================*/ XPUBLIC void drawellipse(x, y, rx, ry) XGR_COORD x, y; /* coordinates of center of ellipse */ XGR_SIZE rx; /* radius along x axis */ XGR_SIZE ry; /* radius along y axis */ X{ X/* Draw the boundary of an ellipse in the foreground color, applying X * clipping if necessary. X */ X int xp, yp; /* current point (based on center) */ X long Asquared; /* square of x semi axis */ X long TwoAsquared; X long Bsquared; /* square of y semi axis */ X long TwoBsquared; X long d; X long dx, dy; X X if ((rx < 0) || (ry < 0)) return; X /* See if the ellipse is either totally visible or totally invisible. X * If so, then the ellipse drawing is easy. X */ X switch (cliparea(x - rx, y - ry, x + rx, y + ry)) { X case GR_CLIP_VISIBLE: X (*gr_dev.drawellipse) (x, y, rx, ry, gr_foreground); X /* Fall into return */ X case GR_CLIP_INVISIBLE: return; X} X X xp = 0; X yp = ry; X Asquared = rx * rx; X TwoAsquared = 2 * Asquared; X Bsquared = ry * ry; X TwoBsquared = 2 * Bsquared; X d = Bsquared - Asquared * ry + (Asquared >> 2); X dx = 0; X dy = TwoAsquared * ry; X X while (dx < dy) { X draw4points(x, y, xp, yp); X if (d > 0) { X yp--; X dy -= TwoAsquared; X d -= dy; X } X xp++; X dx += TwoBsquared; X d += (Bsquared + dx); X } X d += ((3L * (Asquared - Bsquared) / 2L - (dx + dy)) >> 1); X while (yp >= 0) { X draw4points(x, y, xp, yp); X if (d < 0) { X xp++; X dx += TwoBsquared; X d += dx; X } X yp--; X dy -= TwoAsquared; X d += (Asquared - dy); X } X} X X X/*===========================================================================* X * draw4points * X *===========================================================================*/ XPRIVATE void draw4points(x, y, px, py) XGR_COORD x, y; /* center of the points */ XGR_SIZE px, py; /* point to plot (based on center) */ X{ X/* Set four points symmetrically situated around a point. */ X drawpoint(x + px, y + py); X drawpoint(x - px, y + py); X drawpoint(x + px, y - py); X drawpoint(x - px, y - py); X} X X X/*===========================================================================* X * copyarea * X *===========================================================================*/ XPUBLIC void copyarea(srcx, srcy, width, height, destx, desty) X{ X/* Copy a rectangular area from one screen area to another. X * This bypasses clipping. X */ X GR_COORD srcx; /* leftmost column of area to copy */ X GR_COORD srcy; /* topmost row of area to copy */ X GR_SIZE width; /* width of area to copy */ X GR_SIZE height; /* height of area to copy */ X GR_COORD destx; /* leftmost column of destination */ X GR_COORD desty; /* topmost row of destination */ X X if ((width <= 0) || (height <= 0)) return; X if ((srcx == destx) && (srcy == desty)) return; X (*gr_dev.checkcursor) (srcx, srcy, srcx + width - 1, srcy + height - 1); X (*gr_dev.checkcursor) (destx, desty, destx + width - 1, desty + height - 1); X (*gr_dev.copyarea) (srcx, srcy, width, height, destx, desty); X} X X X/*===========================================================================* X * drawarea8 * X *===========================================================================*/ XPUBLIC void drawarea8(x, y, width, height, table) XGR_COORD x; /* leftmost column of area */ XGR_COORD y; /* topmost row of area */ XGR_SIZE width; /* width of area */ XGR_SIZE height; /* height of area */ XGR_COLOR8 *table; /* table of 8 bit color values */ X{ X/* Draw a rectangle of color values, clipping if necessary. X * The rectangle is composed of 8 bit color values so that each color X * only uses one character. If a color matches the background color, X * that that pixel is only drawn if the gr_usebg flag is set. X */ X long cellstodo; /* remaining number of cells */ X long count; /* number of cells of same color */ X long cc; /* current cell count */ X long rows; /* number of complete rows */ X GR_COORD minx; /* minimum x value */ X GR_COORD maxx; /* maximum x value */ X GR_COLOR savecolor; /* saved foreground color */ X GR_BOOL dodraw; /* TRUE if draw these points */ X X minx = x; X maxx = x + width - 1; X X /* See if the area is either totally visible or totally invisible. If X * so, then the area drawing is easy. X */ X switch (cliparea(minx, y, maxx, y + height - 1)) { X case GR_CLIP_VISIBLE: X (*gr_dev.drawarea8) (x, y, width, height, table); X /* Fall into return */ X case GR_CLIP_INVISIBLE: return; X} X X savecolor = gr_foreground; X cellstodo = width * height; X while (cellstodo > 0) { X /* See how many of the adjacent remaining points have the X * same color as the next point. X */ X gr_foreground = *table++; X dodraw = (gr_usebg || (gr_foreground != gr_background)); X count = 1; X cellstodo--; X while ((cellstodo > 0) && (gr_foreground == *table)) { X table++; X count++; X cellstodo--; X } X X /* If there is only one point with this color, then draw it X * by itself. X */ X if (count == 1) { X if (dodraw) drawpoint(x, y); X if (++x > maxx) { X x = minx; X y++; X } X continue; X } X X /* There are multiple points with the same color. If we are X * not at the start of a row of the rectangle, then draw this X * first row specially. X */ X if (x != minx) { X cc = count; X if (x + cc - 1 > maxx) cc = maxx - x + 1; X if (dodraw) drawrow(x, x + cc - 1, y); X count -= cc; X x += cc; X if (x > maxx) { X x = minx; X y++; X } X } X X /* Now the x value is at the beginning of a row if there are X * any points left to be drawn. Draw all the complete rows X * with one call. X */ X rows = count / width; X if (rows > 0) { X if (dodraw) fillrect(x, y, maxx, y + rows - 1); X count %= width; X y += rows; X } X X /* If there is a final partial row of pixels left to be X * drawn, then do that. X */ X if (count > 0) { X if (dodraw) drawrow(x, x + count - 1, y); X x += count; X } X } X gr_foreground = savecolor; X} X X X/*===========================================================================* X * drawbitmap * X *===========================================================================*/ XPUBLIC void drawbitmap(x, y, width, height, table) XGR_COORD x; /* leftmost column of area */ XGR_COORD y; /* topmost row of area */ XGR_SIZE width; /* width of area */ XGR_SIZE height; /* height of area */ XGR_BITMAP *table; /* table of bitmaps */ X{ X/* Draw a rectangle of foreground (and possibly background) colors as X * determined by the specified bitmap, clipping if necessary. The X * background is only drawn if the gr_usebg flag is set. X */ X GR_COORD minx; X GR_COORD maxx; X GR_COLOR savecolor; /* saved foreground color */ X GR_BITMAP bitvalue; /* bitmap word value */ X int bitcount; /* number of bits left in bitmap word */ X X switch (cliparea(x, y, x + width - 1, y + height - 1)) { X case GR_CLIP_VISIBLE: X if (gr_usebg) { X (*gr_dev.fillrect) (x, y, x + width - 1, X y + height - 1, gr_background); X } X (*gr_dev.drawbitmap) (x, y, width, height, table, gr_foreground); X /* Fall into return */ X X case GR_CLIP_INVISIBLE: return; X} X X /* The rectangle is partially visible, so must do clipping. First X * fill a rectangle in the background color if necessary. X */ X if (gr_usebg) { X savecolor = gr_foreground; X gr_foreground = gr_background; X fillrect(x, y, x + width - 1, y + height - 1); X gr_foreground = savecolor; X } X minx = x; X maxx = x + width - 1; X bitcount = 0; X while (height > 0) { X if (bitcount <= 0) { X bitcount = GR_BITMAPBITS; X bitvalue = *table++; X } X if (GR_TESTBIT(bitvalue) && clippoint(x, y)) X (*gr_dev.drawpoint) (x, y, gr_foreground); X bitvalue = GR_SHIFTBIT(bitvalue); X bitcount--; X if (x++ == maxx) { X x = minx; X y++; X height--; X bitcount = 0; X } X } X} X X X/*===========================================================================* X * drawtext * X *===========================================================================*/ XPUBLIC void drawtext(x, y, str, cc) XGR_COORD x, y; /* location to draw string at */ XGR_CHAR *str; /* string to draw */ XGR_SIZE cc; /* number of characters */ X{ X/* Draw a text string at a specifed coordinates in the foreground color X * (and possibly the background color), applying clipping if necessary. X * The background color is only drawn if the gr_usebg flag is set. X */ X GR_SIZE width; /* width of text area */ X GR_SIZE height; /* height of text area */ X GR_BITMAP bitmap[14]; /* bitmaps for characters */ X X if ((cc <= 0) || (y < 0) || (x >= gr_dev.cols)) return; X X (*gr_dev.sizetext) (str, cc, &width, &height); X X switch (cliparea(x, y - height + 1, x + width - 1, y)) { X case GR_CLIP_VISIBLE: X if (gr_usebg) { X (*gr_dev.fillrect) (x, y - height + 1, X x + width - 1, y, gr_background); X } X (*gr_dev.drawtext) (x, y, str, cc, gr_foreground); X /* Fall into return */ X X case GR_CLIP_INVISIBLE: return; X} X X /* Get the bitmap for each character individually, and then display X * them using clipping for each one. X */ X y -= (height - 1); X while ((cc-- > 0) && (x < gr_dev.cols)) { X (*gr_dev.getcharbits) (*str++, bitmap, &width, &height); X drawbitmap(x, y, width, height, bitmap); X x += width; X } X} X X/* END CODE */ END_OF_FILE if test 21918 -ne `wc -c <'mini-x/kernel/graph_main.c'`; then echo shar: \"'mini-x/kernel/graph_main.c'\" unpacked with wrong size! fi # end of 'mini-x/kernel/graph_main.c' fi echo shar: End of archive 6 \(of 9\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0