delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/10/09/12:46:15

From: dyad255 AT aol DOT com (Dyad255)
Newsgroups: comp.os.msdos.djgpp
Subject: Plush with Allegro framebuffer? -- "3d1.c" (16kb)
Date: 9 Oct 1997 15:42:16 GMT
Lines: 545
Message-ID: <19971009154200.LAA14494@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

After digging around a bit, I found a C.O.M.DJGPP post (a couple months old)
 regarding using Allegro[2.2]'s framebuffer for Plush. It looks interesting,
 very simple, and like the other Plush examples now that I made minor (obvious,
 easy) updates to match the most recent Plush (1.1).

Everything I can imagine looks, compiles, and runs fine, but I never actually
 SEE anything! I've dug into the Plush headers (which are very informative) and
 examples, and tested many parameters just in case. I've tried with/without
 z-buffering, and with many video modes and screen sizes, to no avail.

Judging from all the run-time output (Allegro initializes graphics mode, Plush
 creates Light/Camera/Objects and sets the screen palette, Plush starts
 rendering 7 rings moving around a planet in 2 loops, SCREEN STAYS BLACK, a
 keypress exits the loops, Allegro goes to text mode, no errors) ... it LOOKS
 like there's no Light, or an all-black palette, but I double-checked those.

I suspect the error might involve the blit() or memset() calls near the bottom,
 in Planet1() or Planet1Colors(). The first half of the program just processes
 command-line arguments.


Any assistance is MUCH appreciated! I know there are several others who want to
 use Plush with Allegro, and have had similar problems. And Shawn, you've
 helped enough already, so bugger off. 8)


/*******************************************************
 * This Is 3D1.EXE (3D1.C)                             *
 * It Is Written By Norman MacDonald.                  *
 * It Was Written Just For Something To Do             *
 * It Uses Two Libraries (Plush and Allegro)           *
 * Copyright 1997 Norman MacDonald                     *
 *******************************************************/

// Modified by dyad AT wasteland DOT uc DOT surgery DOT med DOT uc DOT edu (Justin) for Plush 1.1

// ********** INCLUDES **********
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <allegro.h>
#include <plush.h>


// ********** GLOBAL VARIABLES **********
BITMAP *temp;
pl_ZBuffer *zbuffer;
pl_Mat RingMaterial, PlanetMaterial, RingMaterial2, RingMaterial3,
 RingMaterial4, RingMaterial5, RingMaterial6;
int vWidth = 320, vHeight = 200;
pl_Float RapidTurn = -0.4;
int loopcount;

// ********** FUNCTIONS **********
void Planet1Colors(); // Setup Colors For Planet One
void Planet1(); // Create Planet One

// ********** MAIN FUNCTION **********
int main(int argc, char **argv)
{

 allegro_init(); // Initializes The Allegro Library

 // ********** COMMAND LINE PARSING BEGINS **********
 // Check If User Has Specified A Video Mode
 for (loopcount = 1; loopcount < argc - 1; loopcount++)
 {
  if (!stricmp(argv[loopcount],"-vmode")) // If Users Enters Switch At Current
 argc
  {
   sscanf(argv[loopcount + 1],"%dx%d",&vWidth,&vHeight); // Take Info From
 Current argc + 1
  }
 }

 // Check If User Does Not Want A Z-Buffer
 if ((argc > 1 && !stricmp(argv[1],"-nozb")) ||
    (argc > 2 && !stricmp(argv[2],"-nozb")) ||
    (argc > 3 && !stricmp(argv[3],"-nozb")) ||
    (argc > 4 && !stricmp(argv[4],"-nozb")) ||
    (argc > 5 && !stricmp(argv[5],"-nozb")) ||
    (argc > 6 && !stricmp(argv[6],"-nozb")) ||
    (argc > 7 && !stricmp(argv[7],"-nozb")) ||
    (argc > 8 && !stricmp(argv[8],"-nozb")) ||
    (argc > 9 && !stricmp(argv[9],"-nozb")) ||
    (argc > 10 && !stricmp(argv[10],"-nozb")))
 {
  zbuffer = 0; // If True, No Z-Buffer
 }
 else
 {
  // If False, Allocate A Z-Buffer
  zbuffer = (pl_ZBuffer *) malloc(sizeof(pl_ZBuffer)*vWidth*vHeight);
 }

 // Check If User Wants The Planet(s) To Turn Rapidly
 if ((argc > 1 && !stricmp(argv[1],"-rapturn")) ||
    (argc > 2 && !stricmp(argv[2],"-rapturn")) ||
    (argc > 3 && !stricmp(argv[3],"-rapturn")) ||
    (argc > 4 && !stricmp(argv[4],"-rapturn")) ||
    (argc > 5 && !stricmp(argv[5],"-rapturn")) ||
    (argc > 6 && !stricmp(argv[6],"-rapturn")) ||
    (argc > 7 && !stricmp(argv[7],"-rapturn")) ||
    (argc > 8 && !stricmp(argv[8],"-rapturn")) ||
    (argc > 9 && !stricmp(argv[9],"-rapturn")) ||
    (argc > 10 && !stricmp(argv[10],"-rapturn")))
 {
  RapidTurn = -12; // If True, Rapid Turn Equals -4 (Fast To The Left)
 }

 // Check If User Wants The Planet(s) To Turn Extremely Rapidly
 if ((argc > 1 && !stricmp(argv[1],"-extrapturn")) ||
    (argc > 2 && !stricmp(argv[2],"-extrapturn")) ||
    (argc > 3 && !stricmp(argv[3],"-extrapturn")) ||
    (argc > 4 && !stricmp(argv[4],"-extrapturn")) ||
    (argc > 5 && !stricmp(argv[5],"-extrapturn")) ||
    (argc > 6 && !stricmp(argv[6],"-extrapturn")) ||
    (argc > 7 && !stricmp(argv[7],"-extrapturn")) ||
    (argc > 8 && !stricmp(argv[8],"-extrapturn")) ||
    (argc > 9 && !stricmp(argv[9],"-extrapturn")) ||
    (argc > 10 && !stricmp(argv[10],"-extrapturn")))
 {
  RapidTurn = -12; // If True, Rapid Turn Equals -4 (Fast To The Left)
 }

 // Check If User Wants The Rings Gouraud Shaded
 if ((argc > 1 && !stricmp(argv[1],"-ringgour")) ||
    (argc > 2 && !stricmp(argv[2],"-ringgour")) ||
    (argc > 3 && !stricmp(argv[3],"-ringgour")) ||
    (argc > 4 && !stricmp(argv[4],"-ringgour")) ||
    (argc > 5 && !stricmp(argv[5],"-ringgour")) ||
    (argc > 6 && !stricmp(argv[6],"-ringgour")) ||
    (argc > 7 && !stricmp(argv[7],"-ringgour")) ||
    (argc > 8 && !stricmp(argv[8],"-ringgour")) ||
    (argc > 9 && !stricmp(argv[9],"-ringgour")) ||
    (argc > 10 && !stricmp(argv[10],"-ringgour")))
 {
  // If True, Make Rings Gouraud Shaded
  RingMaterial.ShadeType = PL_SHADE_GOURAUD;
  RingMaterial2.ShadeType = PL_SHADE_GOURAUD;
  RingMaterial3.ShadeType = PL_SHADE_GOURAUD;
  RingMaterial4.ShadeType = PL_SHADE_GOURAUD;
 }
 else
 {
  // If False, Use Default Flat Shading
  RingMaterial.ShadeType = PL_SHADE_FLAT;
  RingMaterial2.ShadeType = PL_SHADE_FLAT;
  RingMaterial3.ShadeType = PL_SHADE_FLAT;   
  RingMaterial4.ShadeType = PL_SHADE_FLAT;   
 }

 // Check If User Wants The Rings Flat Shaded
 if ((argc > 1 && !stricmp(argv[1],"-ringflat")) ||
    (argc > 2 && !stricmp(argv[2],"-ringflat")) ||
    (argc > 3 && !stricmp(argv[3],"-ringflat")) ||
    (argc > 4 && !stricmp(argv[4],"-ringflat")) ||
    (argc > 5 && !stricmp(argv[5],"-ringflat")) ||
    (argc > 6 && !stricmp(argv[6],"-ringflat")) ||
    (argc > 7 && !stricmp(argv[7],"-ringflat")) ||
    (argc > 8 && !stricmp(argv[8],"-ringflat")) ||
    (argc > 9 && !stricmp(argv[9],"-ringflat")) ||
    (argc > 10 && !stricmp(argv[10],"-ringflat")))
 {
  // If True, Make Rings Flat Shaded
  RingMaterial.ShadeType = PL_SHADE_FLAT;
  RingMaterial2.ShadeType = PL_SHADE_FLAT;
  RingMaterial3.ShadeType = PL_SHADE_FLAT;
  RingMaterial4.ShadeType = PL_SHADE_FLAT;
 }

 // Check If User Wants The Rings Not Shaded
 if ((argc > 1 && !stricmp(argv[1],"-ringnone")) ||
    (argc > 2 && !stricmp(argv[2],"-ringnone")) ||
    (argc > 3 && !stricmp(argv[3],"-ringnone")) ||
    (argc > 4 && !stricmp(argv[4],"-ringnone")) ||
    (argc > 5 && !stricmp(argv[5],"-ringnone")) ||
    (argc > 6 && !stricmp(argv[6],"-ringnone")) ||
    (argc > 7 && !stricmp(argv[7],"-ringnone")) ||
    (argc > 8 && !stricmp(argv[8],"-ringnone")) ||
    (argc > 9 && !stricmp(argv[9],"-ringnone")) ||
    (argc > 10 && !stricmp(argv[10],"-ringnone")))
 {
  // If True, Make Rings Not Shaded
  RingMaterial.ShadeType = PL_SHADE_NONE;
  RingMaterial2.ShadeType = PL_SHADE_NONE;
  RingMaterial3.ShadeType = PL_SHADE_NONE;
  RingMaterial4.ShadeType = PL_SHADE_NONE;
 }

 // Check If Users Wants The Planet Gouraud Shaded
 if ((argc > 1 && !stricmp(argv[1],"-plangour")) ||
    (argc > 2 && !stricmp(argv[2],"-plangour")) ||
    (argc > 3 && !stricmp(argv[3],"-plangour")) ||
    (argc > 4 && !stricmp(argv[4],"-plangour")) ||
    (argc > 5 && !stricmp(argv[5],"-plangour")) ||
    (argc > 6 && !stricmp(argv[6],"-plangour")) ||
    (argc > 7 && !stricmp(argv[7],"-plangour")) ||
    (argc > 8 && !stricmp(argv[8],"-plangour")) ||
    (argc > 9 && !stricmp(argv[9],"-plangour")) ||
    (argc > 10 && !stricmp(argv[10],"-plangour")))
 {
  // If True, Make Planet Gouraud Shaded
  PlanetMaterial.ShadeType = PL_SHADE_GOURAUD;
 }
 else
 {
  // If False, Use Default Flat Shading
  PlanetMaterial.ShadeType = PL_SHADE_FLAT;
 }

 // Check If User Wants Planet Flat Shaded
 if ((argc > 1 && !stricmp(argv[1],"-planflat")) ||
    (argc > 2 && !stricmp(argv[2],"-planflat")) ||
    (argc > 3 && !stricmp(argv[3],"-planflat")) ||
    (argc > 4 && !stricmp(argv[4],"-planflat")) ||
    (argc > 5 && !stricmp(argv[5],"-planflat")) ||
    (argc > 6 && !stricmp(argv[6],"-planflat")) ||
    (argc > 7 && !stricmp(argv[7],"-planflat")) ||
    (argc > 8 && !stricmp(argv[8],"-planflat")) ||
    (argc > 9 && !stricmp(argv[9],"-planflat")) ||
    (argc > 10 && !stricmp(argv[10],"-planflat")))
 {
  // If True Make Planet Flat Shaded
  PlanetMaterial.ShadeType = PL_SHADE_FLAT;
 }

 // Check If User Wants Planet Not Shaded
 if ((argc > 1 && !stricmp(argv[1],"-plannone")) ||
    (argc > 2 && !stricmp(argv[2],"-plannone")) ||
    (argc > 3 && !stricmp(argv[3],"-plannone")) ||
    (argc > 4 && !stricmp(argv[4],"-plannone")) ||
    (argc > 5 && !stricmp(argv[5],"-plannone")) ||
    (argc > 6 && !stricmp(argv[6],"-plannone")) ||
    (argc > 7 && !stricmp(argv[7],"-plannone")) ||
    (argc > 8 && !stricmp(argv[8],"-plannone")) ||
    (argc > 9 && !stricmp(argv[9],"-plannone")) ||
    (argc > 10 && !stricmp(argv[10],"-plannone")))
 {
  // If True Make Planet Flat Shaded
  PlanetMaterial.ShadeType = PL_SHADE_NONE;
 }
 // ********** COMMAND LINE PARSING ENDS **********

 Planet1(); // Call Planet One Routine

 set_gfx_mode(GFX_TEXT,0,0,0,0); // Set Graphics Mode To Text Mode (DOS)

 exit(0); // Exit With An Error Code Of 0
}

// Create Planet One
void Planet1()
{
 // Local Planet One Variables
 pl_Cam *Camera;               
 pl_Obj *Ring;
 pl_Obj *Planet;
 pl_Obj *Ring2;
 pl_Obj *Ring3;
 pl_Obj *Ring4;
 pl_Obj *Ring5;
 pl_Obj *Ring6;
 pl_Light *Light;

 // Create Objects For The Planet Scene
 Ring = plMakeTorus(80,75,20,20,&RingMaterial);
 Ring2 = plMakeTorus(90,85,20,20,&RingMaterial2);
 Ring3 = plMakeTorus(100,98,20,20,&RingMaterial3);
 Ring4 = plMakeTorus(66,64,20,20,&RingMaterial4);
 Ring5 = plMakeTorus(115,113,20,20,&RingMaterial5);
 Ring6 = plMakeTorus(110,107,20,20,&RingMaterial6);
 Planet = plMakeSphere(60,30,30,&PlanetMaterial);

 // Create And Setup The Light(s)
 Light = plLightCreate();
 plLightSet(Light,PL_LIGHT_VECTOR,0,0,0,1.0,1.0);

 // Setup The Screen Mode
 if (set_gfx_mode(GFX_AUTODETECT,vWidth,vHeight,0,0))
 {
  // If It Fails,
  allegro_exit(); // Exit Allegro
  printf("Mode not supported\n"); // Print Error Message
  exit(1); // Exit With An Error Code Of 1
 }

 temp = create_bitmap(vWidth,vHeight); // Create Temporary Bitmap

 // Create The Camera
 Camera = plCamCreate(vWidth,vHeight, vWidth*3.0/(vHeight*4.0),
                      80.0, temp->dat, zbuffer);
 Camera->Z = -2000;


 if (zbuffer) Camera->Sort = 0; // If There Is A Z-Buffer, Don't Sort
 else Camera->Sort = 1; // If There Is Not A Z-Buffer, Sort

 Planet1Colors(); // Setup The Colors For Planet One

 // Setup Starting Locations For The Rings
 Ring->Xa -= 12.0;
 Ring2->Xa -= 12.0;
 Ring3->Xa -= 12.0;
 Ring4->Xa -= 12.0;
 Ring5->Xa -= 12.0;
 Ring6->Xa -= 12.0;
 Ring->Za -= 12.0;
 Ring2->Za -= 12.0;
 Ring3->Za -= 12.0;
 Ring4->Za -= 12.0;
 Ring5->Za -= 12.0;
 Ring6->Za -= 12.0;

 // Start The Planets Rotation While Zooming In
 while (!kbhit())
 {
  Camera->Z += 20; // Zoom In Camera
  // Rotate The Rings
  Ring->Ya += 16.0;
  Ring2->Ya += 16.0;
  Ring3->Ya += 16.0;
  Ring4->Ya += 16.0;
  Ring5->Ya += 16.0;
  Ring6->Ya += 16.0;
  // Rotate The Planet
  Planet->Xa += RapidTurn;
  Planet->Ya += RapidTurn;
  Planet->Za += RapidTurn;
  // Clear The Temporary Bitmap
  clear(temp);

  if (Camera->zBuffer) memset(Camera->zBuffer,0,sizeof(pl_ZBuffer)*
                              Camera->ScreenWidth*Camera->ScreenHeight);

  // Do The Rendering
  plRenderBegin(Camera); // Begin Render
  plRenderLight(Light); // Render Light
  plRenderObj(Planet); // Render Planet
  plRenderObj(Ring); // Render Ring 1
  plRenderObj(Ring2); // Render Ring 2
  plRenderObj(Ring3); // Render Ring 3
  plRenderObj(Ring4); // Render Ring 4
  plRenderObj(Ring5); // Render Ring 5
  plRenderObj(Ring6); // Render Ring 6
  plRenderEnd(); // Do The Rendering
  vsync(); // Wait For vsync (Allegro)
  // Write The Bitmap To The Screen
  blit(temp,screen,0,0,0,0,Camera->ScreenWidth,Camera->ScreenHeight);

  if (Camera->Z > -300) break; // If Zoomed In All The Way, Go To Next Loop
 }

 // Start The Planets Rotation After Zooming In
 while (!kbhit())
 {
  // Rotate The Rings
  Ring->Ya += 16.0;
  Ring2->Ya += 16.0;
  Ring3->Ya += 16.0;
  Ring4->Ya += 16.0;
  Ring5->Ya += 16.0;
  Ring6->Ya += 16.0;
  // Rotate The Planet
  Planet->Xa += RapidTurn;
  Planet->Ya += RapidTurn;
  Planet->Za += RapidTurn;
  // Clear Temporary Bitmap
  clear(temp);

  if (Camera->zBuffer) memset(Camera->zBuffer,0,sizeof(pl_ZBuffer)*
                              Camera->ScreenWidth*Camera->ScreenHeight);

  // Do The Rendering
  plRenderBegin(Camera); // Begin Render
  plRenderLight(Light); // Render Light
  plRenderObj(Planet); // Render Planet
  plRenderObj(Ring); // Render Ring 1
  plRenderObj(Ring2); // Render Ring 2
  plRenderObj(Ring3); // Render Ring 3
  plRenderObj(Ring4); // Render Ring 4
  plRenderObj(Ring5); // Render Ring 5
  plRenderObj(Ring6); // Render Ring 6
  plRenderEnd(); // Do The Rendering
  vsync(); // Wait For vsync (Allegro)
  // Write The Bitmap To The Screen
  blit(temp,screen,0,0,0,0,Camera->ScreenWidth,Camera->ScreenHeight);
 }

 // Free Up Memory Used By The Objects
 plObjDelete(Ring);
 plObjDelete(Ring2);
 plObjDelete(Ring3);
 plObjDelete(Ring4);
 plObjDelete(Ring5);
 plObjDelete(Ring6);
 plObjDelete(Planet);
 plLightDelete(Light);  
 plCamDelete(Camera);
 free(zbuffer);
 // Destroy The Temporary Bitmap
 destroy_bitmap(temp);
}

void Planet1Colors()
{
 // Local Variables For Planet One's Colors
 int x;
 PALETTE pal; // Allegro palette
 char cpal[768]; // Plush palette

 memset(cpal,0,768);

 // Setup Material Properties
// PlanetMaterial.Priority = 0;


 PlanetMaterial.NumGradients = 200;
 PlanetMaterial.Ambient[0] = 20;
 PlanetMaterial.Ambient[1] = 255;
 PlanetMaterial.Ambient[2] = 0;
 PlanetMaterial.Specular[0] = 0;
 PlanetMaterial.Specular[1] = 0;
 PlanetMaterial.Specular[2] = 0;
 PlanetMaterial.Shininess = 15;
 PlanetMaterial.Transparent = 0;
 PlanetMaterial.Environment = NULL;
 PlanetMaterial.Texture = NULL;

 // Setup Material Properties
// RingMaterial.Priority = 0;
 RingMaterial.NumGradients = 200;
 RingMaterial.Ambient[0] = 255;
 RingMaterial.Ambient[1] = 255;
 RingMaterial.Ambient[2] = 255;
 RingMaterial.Specular[0] = 0;
 RingMaterial.Specular[1] = 0;
 RingMaterial.Specular[2] = 0;
 RingMaterial.Shininess = 15;
 RingMaterial.Transparent = 3;
 RingMaterial.Environment = NULL;
 RingMaterial.Texture = NULL;

 // Setup Material Properties
// RingMaterial2.Priority = 0;
 RingMaterial2.NumGradients = 200;
 RingMaterial2.Ambient[0] = 255;
 RingMaterial2.Ambient[1] = 0;
 RingMaterial2.Ambient[2] = 0;
 RingMaterial2.Specular[0] = 0;
 RingMaterial2.Specular[1] = 0;
 RingMaterial2.Specular[2] = 0;
 RingMaterial2.Shininess = 15;
 RingMaterial2.Transparent = 2;
 RingMaterial2.Environment = NULL;
 RingMaterial2.Texture = NULL;

 // Setup Material Properties
// RingMaterial3.Priority = 0;
 RingMaterial3.NumGradients = 200;
 RingMaterial3.Ambient[0] = 255;
 RingMaterial3.Ambient[1] = 255;
 RingMaterial3.Ambient[2] = 0;
 RingMaterial3.Specular[0] = 0;
 RingMaterial3.Specular[1] = 0;
 RingMaterial3.Specular[2] = 0;
 RingMaterial3.Shininess = 15;
 RingMaterial3.Transparent = 2;
 RingMaterial3.Environment = NULL;
 RingMaterial3.Texture = NULL;

 // Setup Material Properties
// RingMaterial4.Priority = 0;
 RingMaterial4.NumGradients = 200;
 RingMaterial4.Ambient[0] = 0;
 RingMaterial4.Ambient[1] = 255;
 RingMaterial4.Ambient[2] = 255;
 RingMaterial4.Specular[0] = 0;
 RingMaterial4.Specular[1] = 0;
 RingMaterial4.Specular[2] = 0;
 RingMaterial4.Shininess = 15;
 RingMaterial4.Transparent = 3;
 RingMaterial4.Environment = NULL;
 RingMaterial4.Texture = NULL;

 // Setup Material Properties
// RingMaterial5.Priority = 0;
 RingMaterial5.NumGradients = 200;
 RingMaterial5.Ambient[0] = 255;
 RingMaterial5.Ambient[1] = 0;
 RingMaterial5.Ambient[2] = 255;
 RingMaterial5.Specular[0] = 0;
 RingMaterial5.Specular[1] = 0;
 RingMaterial5.Specular[2] = 0;
 RingMaterial5.Shininess = 15;
 RingMaterial5.Transparent = 2;
 RingMaterial5.Environment = NULL;
 RingMaterial5.Texture = NULL;

 // Setup Material Properties
// RingMaterial6.Priority = 0;
 RingMaterial6.NumGradients = 200;
 RingMaterial6.Ambient[0] = 127;
 RingMaterial6.Ambient[1] = 127;
 RingMaterial6.Ambient[2] = 255;
 RingMaterial6.Specular[0] = 0;
 RingMaterial6.Specular[1] = 0;
 RingMaterial6.Specular[2] = 0;
 RingMaterial6.Shininess = 15;
 RingMaterial6.Transparent = 2;
 RingMaterial6.Environment = NULL;
 RingMaterial6.Texture = NULL;


 // Initialize map materials
 // Planet Surface
 plMatInit(&PlanetMaterial);
 // Ring Surfaces
 plMatInit(&RingMaterial);
 plMatInit(&RingMaterial2);
 plMatInit(&RingMaterial3);
 plMatInit(&RingMaterial4);
 plMatInit(&RingMaterial5);
 plMatInit(&RingMaterial6);
 // Now map them to the palette
 plMatMapToPal(&PlanetMaterial, cpal, 1, 254);
 plMatMapToPal(&RingMaterial, cpal, 1, 254);
 plMatMapToPal(&RingMaterial2, cpal, 1, 254);
 plMatMapToPal(&RingMaterial3, cpal, 1, 254);
 plMatMapToPal(&RingMaterial4, cpal, 1, 254);
 plMatMapToPal(&RingMaterial5, cpal, 1, 254);
 plMatMapToPal(&RingMaterial6, cpal, 1, 254);


 /* Palette Conversion */
 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
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019