/*************************************************************************** * * first_app.c * * This program is an prototype application for iRMX II/III written for * use with iC n86 using the iSBX 279A interface library. It exhibits * proper device initialization and termination, and provides a * first program from which to build a graphics application. * * A single output stream to a metafile device is utilized. This is the * simplest graphics application one can write. Input handling and use * of multiple devices or I/O streams is not shown. Deletion of default * (or pre-existing) bitmaps is shown, and creation of a new bitmap and * window is shown. */ #pragma extend /* * The standard iC include files are first */ #include #include #include #include /* * The UDI library includes */ #include /* * The iRMX library includes */ #include #include /* * The iRGI library includes */ #include /* * The default name of the graphics device/metafile. */ static char *defcginame = ":VDI:"; /* * The 'real' name in case the user specifies a non-default name. */ static char *cginame; /* * Static data area for pathname conversion from null-terminated string * to counted string for use by iRMX II. */ static char ucginame[256]; /* * A token for the device/file connection from iRMX II. This will be * passed to the buffered O/S layer of RGI for use in subsequent I/O * operations. */ static TOKEN cgiconn; /* * The 'I/O stream identifier' returned by cgi_initialize and required in * all subsequent RGI calls to identify the I/O stream in use. This * may be thought of as a 'file descriptor' created by cgi_initialize. * Up to 10 concurrent I/O streams may be in use in a single application * (or instance of the RGI library data segment for those who delve * deeply into PL/M models and like unusual invocations of BND286). * The cgi_initialize call is currently not ROM-able, due to use of a * single 'INITIAL' statement to detect first entry and clear the data * area. */ static CGIDevice cgidev; /* * A buffer for use by the buffered I/O layer of iRGI. Any buffer size may * be used, however 64K segment limits restrict the maximum size and 0 is * of course the minimum. When a buffer size of zero is used, every call * to the RGI interface results in a 'write' call. This is usually * undesirable. An average packet is about 4 bytes for 'primitive attributes' * so a buffer of just 64 bytes will greatly improve through-put. If large * polygons or other lists are routinely drawn, then the buffer size depends * upon the average size of these lists. In general, when memory usage is * not critical, buffers up to 32K should be used. Of course, when you * examine the SUBMIT file that builds this program you will see that the * same argument is made for stack size. * * The application should never access this buffer. It is 'given away' * to RGI to allow the application program to control the resource usage * of the interface library. */ static char cgibuff[8192]; /* * Nearly all applications that run on top of the HI should use in-line * exception handling. Some interface libraries assume that exceptions * will be returned in-line for proper operation. RGI assumes * internally assume in-line exception handling in this release. * Our example code will check exceptions so the reader becomes aware * of the most likely error conditions and simple mechanisms for handling * these errors. */ static EXCEPTIONSTRUCT noexcept = {0,0,0}; /* * The usual 'usage' message */ void usage( void ) { fprintf(stderr, "usage: first_app -c cgi_dev -x x_size -y y_size -n num_color\n"); fprintf(stderr, " if -c is not specified then :VDI: is assumed.\n"); fprintf(stderr, " if -x is not specified then 320 is used.\n"); fprintf(stderr, " if -y is not specified then 240 is used.\n"); fprintf(stderr, " if -n is not specified then 16 is used.\n"); exit(1); } /* * Some text strings we will display in a window. */ static char *title = "Available Line Styles"; static char *line_styles[] = { "SOLID_LINE (0)", "DASHED_LINE (1)", "DOTTED_LINE (2)", "DOTTED_DASHED_LINE (3)" }; /* * At Last! main() */ main( int argc, char *argv[]) { WORD except = EOK; Word rgi_except = EOK; int i,k; int XR = 320, YR = 240, N = 16; RGI_Index bits; char *p; /* * Step 1. Set up the exception mode so errors are returned inline. */ rqsetexceptionhandler(&noexcept,&except); /* * Step 2. (Optional) Parse the command line in typical 'C' fashion. * Some applications may have no command-line options. */ cginame = defcginame; while ((argc > 1) && (argv[1][0] == '-')) { switch (argv[1][1]) { case 'c': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) cginame = argv[1]; else usage(); break; case 'x': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) XR = atoi( (const char *)&argv[1][0]); else usage(); if ((XR > 640) || (XR < 0)) { fprintf(stderr,"X-size must be positive and cannot exceed 640.\n"); exit(1); } break; case 'y': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) YR = atoi( (const char *)&argv[1][0]); else usage(); if ((YR > 480) || (YR < 0)) { fprintf(stderr,"Y-size must be positive and cannot exceed 480.\n"); exit(1); } break; case 'n': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) N = atoi( (const char *)&argv[1][0]); else usage(); if ((N != 2) && (N != 4) && (N != 16) && (N != 256)) { fprintf(stderr,"Number of Colors must be 2, 4, 16, or 256.\n"); exit(1); } break; default: fprintf(stderr,"Unrecognized Control: %s\n",argv[1]); usage(); break; } argv++; argc--; } if ((argc > 1) && (argv[1][0] != '-')) usage(); /* * Step 3. Obtain access to the graphics device or metafile. * We use 'attach' here to allow 'appending' to a disk resident * file. Multiple applications can then 'build' a picture. * Note that a collection of trivial programs can use this strategy * to implement tools that together can be very powerful. The first * one you will want to write is one that deletes all existing resources * and restores the graphics interpreter to a known state (single bitmap, * single window, known bit depth, known color table, etc). * Otherwise, just detach the device and re-attach it to restore the * configuration parameters. */ cgiconn = rqsattachfile((STRING *)udistr(ucginame,(const char *)cginame), &except); if (except != EOK) { fprintf(stderr, "Error %d Attaching Output File: %s\n",except,cginame); exit(1); } /* * Step 4. Open for read and write with no buffers. If this were * a disk file then EIOS buffers could be used, but use of buffering * in the iRGI interface provides the majority of any performance boost * while no EIOS buffering is needed when output is sent to the screen (the * physical file driver and TSC are used in that case). */ rqsopen(cgiconn, (BYTE)3, (BYTE)0, &except); if (except != EOK) { fprintf(stderr, "Error %d Opening Output File: %s\n",except,cginame); exit(1); } /* * Step 5. (Optional) This step allows appending to the metafile. * Programs that do not expect to 'cooperatively' build pictures with * other programs may simply create the output file in step 2 and * not 'seek' in step 5. * * Since the TSC does not allow a 'terminal' to 'seek', we ignore the * E$IDDR error expected here. */ rqsseek(cgiconn, (BYTE)4, (DWORD) 0, &except); except = EOK; /* ignore any errors... */ /* * Step 6. Initialize the 'Buffered O/S Interface' layer of RGI. * This step is required for all graphics applications. The identifier * returned is use in all subsequent calls. The identifier is similar * to a file descriptor and should never be modified by the program. */ cgidev = cgi_initialize(cgiconn,cgibuff,sizeof cgibuff,&rgi_except); if (rgi_except != EOK) { fprintf(stderr, "Error %d Initializing CGI library: %s\n",except,cginame); exit(1); } /* * Figure out the requested bit depth from the requested number of * colors. */ bits = (int)(log((double)N)/log((double)2.0)); /* * Step 7. (Optional) Get rid of any other resources left by other * applications. * * Note that applications intending to 'append' to a picture would not * perform this step. This application will remove all prior drawings * and start over each time it is invoked. * * Both styles of usage are shown in this program to provide examples and * ideas to the application programmer. */ gqdeleteallbitmaps(cgidev); gqdeleteallwindows(cgidev); /* * Step 8. (Optional) Allocate new resources. Once the pre-existing * bitmaps and windows are destroyed, the application must create new * resources (or just exit if the program simply gets rid of stuff on * the device). * * Note that applications that 'append' to a picture can also skip step * 7 and still perform step 8 - the intent may be to incrementally build * a picture composed of multiple bitmaps and/or several windows. */ gqcreatebitmap(cgidev, (BitmapId)0, (DC)XR, (DC)YR, bits); /* * The remainder of this program is application specific, so we can * regard it all as Step 9. * * When drawing in a bitmap, it must first be selected. */ gqselectdrawingbitmap(cgidev, (BitmapId)0); /* * Prior to using 'coordinates', the Virtual Device Coordinate Space * must be defined by specifying the lower left and upper right corners. * Also, the device viewport must be set to determine the mapping to * device coordinate space by specifying the lower left and upper right * corners. */ gqsetvdcextent(cgidev, (VDC)0, (VDC)0, (VDC)(XR-1), (VDC)(YR-1)); gqsetdeviceviewport(cgidev, (DC)0, (DC)0, (DC)(XR-1), (DC)(YR-1)); /* * BEGINPICTURE is not required, but is good form. Also, the background * color can be set here. */ gqbeginpicture(cgidev, (void *)"", (ColorIndex)BLACK); /* * Bitmaps are initialized to zero when they are created so both BEGIN * PICTURE and CLEARVIEWSURFACE are optional in this context, however * programs that use pre-existing resources should initialize the * graphics device as needed. * Using both BEGIN PICTURE and CLEAR VIEW SURFACE is redundant and will * cause the bitmap to be cleared twice. This will be visible if the * window is visible. */ gqclearviewsurface(cgidev); /* * Primitive text attributes are initialized here. We use the Stroke * font at index 0 and set the character height to allow 26 lines on * the device. Alignment is LEFT and TOP, while path is RIGHT. */ gqsettextprecision (cgidev, (RGI_Index)STROKE_PRECISION); gqsettextalignment (cgidev, (RGI_Index)ALIGN_LEFT, (RGI_Index)ALIGN_TOP, (Real)0.0, (Real)0.0); gqsetcharacterpath (cgidev, (RGI_Index)CHARACTER_RIGHT); gqsettextfontindex (cgidev, (RGI_Index)0); gqsetcharacterspacing (cgidev, (Real)0.25); gqsetcharacterheight (cgidev, (VDC)(YR/26)); /* * Sub-Titles for each of four lines (one in each style) are now drawn. */ gqsettextcolor (cgidev, (ColorIndex)GREEN); for (k = 0; k < 4; k++) { /* line style */ p = line_styles[k]; gqtext (cgidev, (VDC)(XR/4), (VDC)((k+1)*YR/6), (RGI_Index)0, (Integer)strlen((const char *)p), (void *)p); } /* * The Title is added to the picture. */ gqsettextcolor (cgidev, (ColorIndex)CYAN); p = title; gqtext (cgidev, (VDC)(XR/4), (VDC)(5*YR/6), (RGI_Index)0, (Integer)strlen((const char *)p), (void *)p); /* * A window is created to allow the user to view the bitmap. * * Note that the window may be created at any time after the bitmap * is created, however drawing and then creating a window is the * preferred method since users need not know how a picture is constructed * and perceived drawing time is reduced if the user never sees individual * drawing primitives - just completed pictures. * * In addition, this application demonstrates the concept of 'caching' * often used pictures and creating windows to view them as necessary. * Static 'help' screens, 'menus' and other selection screens are all * good candidates. Pictures that are primarily static (graphs and * other data presentation displays) can cache a portion of the bitmap * (the 'background'), and use a raster-op to copy the static portion * into a new bitmap, add the dynamic information, and then create * a window to view the combined picture. Finally, a miriad of visual * effects may be achieved by dynamically manipulating multiple windows * on the same or different bitmaps and by modifying the color table. * These examples are beyond the scope of this simple application. * * In this application, the user will see four lines drawn in different * styles and text will describe the line style. Each line is redrawn * in each of the available colors (depends on bit depth). This provides * a simple visual effect to draw attention to the lines. The window is * created prior to the use of this effect in order to allow the effect * to be seen by the user. * * The created window is 'on top' at priority 255, is visible, has * borders, and displays the entire bitmap in the upper right corner * of the screen. Note the conversion from bitmap to screen coordinates * by inverting the Y coordinate. */ gqcreatewindow(cgidev, (WindowId)0, (BitmapId)0, (RGI_Index)255, (RGI_Index)(VISIBLE | BORDER_VISI), (DC)0, (DC)0, (DC)(640-XR), (DC)0, (DC)XR, (DC)YR); /* * now we will draw some lines */ for (k = 0; k < 4; k++) { /* line style */ gqsetlinetype(cgidev, (RGI_Index)k); for (i = 0; i < N; i++) { /* line color */ gqsetlinecolor(cgidev, (ColorIndex)i); gqline(cgidev, (VDC)(XR/4), (VDC)((k+1)*YR/6), (VDC)(3*XR/4), (VDC)((k+1)*YR/6)); } } /* * Step 10. Terminate Properly. The RGI interface library * is called to free internal resources allocated by cgi_initialize. */ cgi_terminate(cgidev,&rgi_except); if (rgi_except != EOK) exit(1); /* * Step 11. Close the connection and delete it. */ rqsclose(cgiconn,&except); if (except != EOK) exit(1); rqsdeleteconnection(cgiconn, &except); if (except != EOK) exit(1); /* * As a final note, the application may use UDI calls to obtain connections * for use by RGI. iRMX II EIOS calls are shown only as an example. * * That's the end of the program. */ /* return or exit(0) */ }