From: dyad255 AT aol DOT com (Dyad255) Newsgroups: comp.os.msdos.djgpp Subject: Re: Plush with Allegro framebuffer -- "apex.c" (13kb) Date: 13 Oct 1997 09:48:20 GMT Lines: 437 Message-ID: <19971013094801.FAA24711@ladder01.news.aol.com> NNTP-Posting-Host: ladder01.news.aol.com Organization: AOL http://www.aol.com To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Precedence: bulk Example program intended to demonstrate some use of the configurable Allegro 2.2 framebuffer by the Plush 1.1 3D rendering system. Hacked from someone to Norman MacDonald to me. Offers command-line and run-time options ('apex -?' describes them) for affecting various features. Might have used 3DS objects like the Plush examples, but stuck with the tori. You can blame a little bad code on me. 8) // apex.c // ********** INCLUDES ********** #include <float.h> // for _control87() when using DJGPP/Watcom #include <stdio.h> #include <conio.h> // getch() #include <stdlib.h> #include <string.h> #include <allegro.h> #include <plush.h> // ********** DEFAULTS & DEFINES ********** #define GFX_MODE GFX_AUTODETECT // Allegro graphics mode (c.f.) #define DEFAULT_WIDTH 320 #define DEFAULT_HEIGHT 200 #define NUM_OBJECTS 3 #define DEFAULT_TORI_STRIPS 8 #define DEFAULT_TORI_SECTIONS 8 #define DEFAULT_SHADING_MODE PL_SHADE_GOURAUD // Plush shading mode (c.f.) #define DEFAULT_SPIN 6.0 #define DEFAULT_TRANSPARENCY 2 #define DEFAULT_SHININESS 8 // ********** GLOBAL VARIABLES ********** int counter = 0; // General counter int done = 0; // General conditional int wait_vsync = 1; // Wait for vsync? BITMAP *temp; // Allegro, for blitting rendered scene to pl_ZBuffer *zbuffer; pl_Cam *Camera; pl_Light *Light; pl_Obj *Object[NUM_OBJECTS]; // Objects pl_Mat *Material[NUM_OBJECTS]; // Materials (each for the corresponding Object) // These can be set later (at startup) by command-line parameters int vWidth = DEFAULT_WIDTH, vHeight = DEFAULT_HEIGHT; pl_uInt AllToriiStrips = DEFAULT_TORI_STRIPS; pl_uInt AllToriiSections = DEFAULT_TORI_SECTIONS; // These can be altered later (at run-time) with keyboard commands pl_uChar AllShadeType = DEFAULT_SHADING_MODE; pl_uChar AllTransparency, GivenTransparency = DEFAULT_TRANSPARENCY; pl_uInt AllShininess = DEFAULT_SHININESS; int AllSpinRate = DEFAULT_SPIN; // ********** FUNCTIONS ********** void SetupMaterials(); // Setup objects and map to palettes void StartObjects(); // Create objects, render in loops until keypress // ********** MAIN ********** int main(int argc, char **argv) { // For perspective correction to work? #if defined(DJGPP) || defined(__WATCOMC__) // Put the fpu in a low precision, no exception state _control87(MCW_EM|PC_24, MCW_EM|MCW_PC); #endif // ********** COMMAND LINE PARSING BEGINS ********** // Check if user wants help if ((argc > 1 && !stricmp(argv[1],"-?")) || (argc > 2 && !stricmp(argv[2],"-?")) || (argc > 3 && !stricmp(argv[3],"-?")) || (argc > 4 && !stricmp(argv[4],"-?")) || (argc > 5 && !stricmp(argv[5],"-?")) || (argc > 6 && !stricmp(argv[6],"-?")) || (argc > 7 && !stricmp(argv[7],"-?")) || (argc > 8 && !stricmp(argv[8],"-?")) || (argc > 9 && !stricmp(argv[9],"-?")) || (argc > 10 && !stricmp(argv[10],"-?"))) { // If so: allegro_exit(); // exit Allegro, printf("\n"); // show command line options, printf("APEx: Allegro 2.2+WIP and Plush 1.1 example\n"); printf("\n [command-line options]\n"); printf("-vsize WxH video size (default %dx%d)\n", DEFAULT_WIDTH, DEFAULT_HEIGHT); printf("-r n # tori strips (3-uInt) (default %d)\n", DEFAULT_TORI_STRIPS); printf("-c n # tori sections (3-uInt) (default %d)\n", DEFAULT_TORI_SECTIONS); printf("-t n global transparency (default %d)\n", DEFAULT_TRANSPARENCY); printf("-? this help text\n"); printf("\n [real-time keyboard commands]\n"); printf("[ESC] exit\n"); printf("-/= zoom out/in"); printf("g use gouraud shading (default)\n"); printf("f use flat shading\n"); printf("n use no shading\n"); printf("t toggles transparency (set above)\n"); printf("s/S -/+ 1 shininess (default %d)\n", DEFAULT_SHININESS); printf("v toggle vsync (wait for screen refresh)\n"); printf("z toggle z-buffer/sort-whole-polygons\n"); exit(0); // and exit program with no errors } // Check if user has specified a video size for (counter = 1; counter < argc - 1; counter++) { if (!stricmp(argv[counter], "-vsize")) // If user enters switch at current argc sscanf(argv[counter + 1], "%dx%d",&vWidth,&vHeight); // Take info from current argc + 1 } // Check if user supplied tori radial divisions (strips) for (counter = 1; counter < argc - 1; counter++) { if (!stricmp(argv[counter], "-r")) // If user enters switch at current argc sscanf(argv[counter + 1],"%d", &AllToriiStrips); // Take info from current argc + 1 } // Check if user supplied tori circumference divisions (sections) for (counter = 1; counter < argc - 1; counter++) { if (!stricmp(argv[counter], "-c")) // If user enters switch at current argc sscanf(argv[counter + 1],"%d", &AllToriiSections); // Take info from current argc + 1 } // Check if user supplied a global transparency for (counter = 1; counter < argc - 1; counter++) { if (!stricmp(argv[counter], "-t")) // If user enters switch at current argc { sscanf(argv[counter + 1],"%d", &GivenTransparency); // Take info from current argc + 1 AllTransparency = GivenTransparency; } } allegro_init(); // Initializes Allegro StartObjects(); // Big setup & looping routine // Finishing up... set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); // Set screen mode to DOS text allegro_exit(); // Exit Allegro exit(0); // Exit with an error code of 0 } // ********** BIG SETUP & LOOPING ROUTINE ********** void StartObjects() { // Setup the screen mode if (set_gfx_mode(GFX_MODE, vWidth, vHeight, 0, 0)) { // If it fails: allegro_exit(); // exit Allegro, printf("Graphics mode not supported.\n"); // print error message, exit(1); // and exit program with an error } // Allocate the temporary screen bitmap temp = create_bitmap(vWidth,vHeight); // Allocate the zbuffer zbuffer = (pl_ZBuffer *) malloc(sizeof(pl_ZBuffer)*vWidth*vHeight); // Allocate as many materials as objects for(counter = 0; counter < NUM_OBJECTS; counter++) Material[counter] = plMatCreate(); // Setup the initial material properties and map them to palette SetupMaterials(); // Create 3 tori objects from corresponding materials Object[0] = plMakeTorus(70, 30, AllToriiSections, AllToriiStrips, Material[0]); Object[1] = plMakeTorus(90, 50, AllToriiSections, AllToriiStrips, Material[1]); Object[2] = plMakeTorus(110, 70, AllToriiSections, AllToriiStrips, Material[2]); // Create and setup the light Light = plLightCreate(); plLightSet(Light, PL_LIGHT_VECTOR, 0, 0, 0, 1, 0); // Create the camera Camera = plCamCreate(vWidth,vHeight, vWidth*3.0/(vHeight*4.0), 80.0, temp->dat, zbuffer); Camera->Sort = 0; // There is initially a zbuffer, so don't sort polygons Camera->Z = -300; // Start back a fair distance // Setup starting angles for the objects Object[0]->Xa = 0.0; Object[0]->Za -= 36.0; Object[1]->Xa += 36.0; Object[1]->Za = 0.0; Object[2]->Xa -= 36.0; Object[2]->Za = 0.0; // Start the object movement while (!done) { // Rotate the objects Object[0]->Za += AllSpinRate; Object[1]->Xa += AllSpinRate; Object[2]->Ya += AllSpinRate; // Clear the temp screen bitmap clear(temp); if (Camera->zBuffer) memset(Camera->zBuffer, 0, sizeof(pl_ZBuffer)* Camera->ScreenWidth*Camera->ScreenHeight); // Do the rendering plRenderBegin(Camera); // Start render plRenderLight(Light); // Render Light // Render all the objects for(counter = 0; counter < NUM_OBJECTS; counter++) plRenderObj(Object[counter]); plRenderEnd(); // Finish render if (wait_vsync) vsync(); // Wait for vsync (Allegro) // Write the temp screen bitmap to the screen blit(temp, screen, 0, 0, 0, 0, Camera->ScreenWidth, Camera->ScreenHeight); // Handle keyboard input while (kbhit()) switch(getch()) { // ESC = quit case 27: done++; break; // - is for zooming out case '-': Camera->Fov += 1.0; if (Camera->Fov > 179.0) Camera->Fov = 179.0; break; // = or + are for zooming in case '=': case '+': Camera->Fov -= 1.0; if (Camera->Fov < 1.0) Camera->Fov = 1.0; break; // g = gouraud shading case 'g': AllShadeType = PL_SHADE_GOURAUD; // set global shading mode SetupMaterials(); break; // f = flat shading case 'f': AllShadeType = PL_SHADE_FLAT; // set global shading mode SetupMaterials(); break; // n = no shading case 'n': AllShadeType = PL_SHADE_NONE; // set global shading mode SetupMaterials(); break; // s and S decrease and increase global shininess case 's': AllShininess += (AllShininess > 65534) ? 0 : 1; SetupMaterials(); break; case 'S': AllShininess -= (AllShininess < 1) ? 0 : 1; SetupMaterials(); break; // t toggles global transparency case 't': AllTransparency = (AllTransparency == 0) ? GivenTransparency : 0; SetupMaterials(); break; // , and . decrease and increase global spin rate case ',': AllSpinRate -= 1; break; case '.': AllSpinRate += 1; break; // v toggles vsync case 'v': wait_vsync ^= 1; break; // z toggles zbuffer case 'z': if (Camera->zBuffer) // If the camera is currently using the zbuffer, { Camera->zBuffer = 0; // make the camera ignore the zbuffer, Camera->Sort = 1; // and sort the polygons instead } else // The camera's not using the zbuffer, so... { Camera->zBuffer = zbuffer; // point it to our zbuffer Camera->Sort = 0; // and turn polygon sorting off } break; } } // Close down world: Free up memory used by the Plush objects, Allegro bitmaps, and zbuffer for(counter = 0; counter < NUM_OBJECTS; counter++) { plObjDelete(Object[counter]); plMatDelete(Material[counter]); } plLightDelete(Light); plCamDelete(Camera); free(zbuffer); // Destroy the temporary Allegro bitmap destroy_bitmap(temp); } // ********** SET UP MATERIALS AND PALETTES ********** void SetupMaterials() { // Local variables for setting palettes pl_Mat *AllMaterials[NUM_OBJECTS + 1]; // Null-terminated list of materials int x; PALETTE pal; // Allegro palette (set below using Plush palette) pl_uChar cpal[768]; // Plush palette memset(cpal, 0, 768); // Setup material properties Material[0]->ShadeType = AllShadeType; // see defines and key commands Material[0]->NumGradients = 96; Material[0]->Ambient[0] = 200; Material[0]->Ambient[1] = 0; Material[0]->Ambient[2] = 0; Material[0]->Diffuse[0] = 0; Material[0]->Diffuse[1] = 200; Material[0]->Diffuse[2] = 0; Material[0]->Specular[0] = 0; Material[0]->Specular[1] = 0; Material[0]->Specular[2] = 200; Material[0]->Shininess = AllShininess; // see defines and key commands Material[0]->Transparent = AllTransparency; // see defines and key commands Material[0]->Environment = NULL; Material[0]->Texture = NULL; Material[0]->PerspectiveCorrect = 0; Material[0]->zBufferable = TRUE; Material[0]->FadeDist = 0.0; // Setup material properties Material[1]->ShadeType = AllShadeType; // see defines and key commands Material[1]->NumGradients = 96; Material[1]->Ambient[0] = 0; Material[1]->Ambient[1] = 200; Material[1]->Ambient[2] = 0; Material[1]->Diffuse[0] = 0; Material[1]->Diffuse[1] = 0; Material[1]->Diffuse[2] = 200; Material[1]->Specular[0] = 200; Material[1]->Specular[1] = 0; Material[1]->Specular[2] = 0; Material[1]->Shininess = AllShininess; // see defines and key commands Material[1]->Transparent = AllTransparency; // see defines and key commands Material[1]->Environment = NULL; Material[1]->Texture = NULL; Material[1]->PerspectiveCorrect = 0; Material[1]->zBufferable = TRUE; Material[1]->FadeDist = 0.0; // Setup material properties Material[2]->ShadeType = AllShadeType; // see defines and key commands Material[2]->NumGradients = 96; Material[2]->Ambient[0] = 0; Material[2]->Ambient[1] = 0; Material[2]->Ambient[2] = 200; Material[2]->Diffuse[0] = 200; Material[2]->Diffuse[1] = 0; Material[2]->Diffuse[2] = 0; Material[2]->Specular[0] = 0; Material[2]->Specular[1] = 200; Material[2]->Specular[2] = 0; Material[2]->Shininess = AllShininess; // see defines and key commands Material[2]->Transparent = AllTransparency; // see defines and key commands Material[2]->Environment = NULL; Material[2]->Texture = NULL; Material[2]->PerspectiveCorrect = 0; Material[2]->zBufferable = TRUE; Material[2]->FadeDist = 0.0; // Must initialize map materials and add to a list before mapping to palette for(counter = 0; counter < NUM_OBJECTS; counter++) { plMatInit(Material[counter]); AllMaterials[counter] = Material[counter]; } AllMaterials[NUM_OBJECTS] = 0; // Null-terminate the list // Generate an optimal palette from the list of materials plMatMakeOptPal(cpal, 1, 255, AllMaterials); // Start at 1 instead of 0, cpal[0] = cpal[1] = cpal[2] = 0; // because that's always black // Now map the individual materials to the palette for(counter = 0; counter < NUM_OBJECTS; counter++) plMatMapToPal(Material[counter], cpal, 0, 255); // Palette conversion for Allegro for (x = 0; x < 256; x++) { pal[x].r = cpal[x*3+0] >> 2; // Convert red pal[x].g = cpal[x*3+1] >> 2; // Convert green pal[x].b = cpal[x*3+2] >> 2; // Convert blue } set_palette(pal); // Set The Palette }