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
}