PRLight 1.0
-----------

What is PRLight?

   PRLight is a Power Render utility used to generate precalculated colored
   lighting for 3D models.  It lets you place any number of Directional and
   point lights in 3D space and adjust their color, strength, and radius.
   Results are shown in realtime so you know exactly how it will look.

   Lighting is done at the vertex level, as opposed to lightmaps used in
   games such as Quake2.


What are the requirements?

   PRLight has been compiled for DOS using Glide, which means you need
   DOS Glide drivers and a 3Dfx card.  The source code is included so you
   can port it to the D3D libraries as well.

How do I start?

   Two examples are included.  From the PRLight directory run either
   demo1.bat or demo2.bat.  When the scene is loaded, hold down F1
   for the basic controls.  


What is this used for?

   You can use it for any model, but it will be most useful to generate
   lighting on the walls with indoor rooms.  

   Programmers will probably want to modify the utility so it supports a
   custom level file format.

   It should also be feasible to divide an entire level into regions,
   where each region is stored in a separate segment in a PRO file.
   A file with information for collision detection and object
   positions could be used in addition to the PRO file.


How was this possible using Power Render?

   The PRO format stores U, V, and a color intensity for every vertex of
   every face.  The intensity was originally used for precalculated mono
   lighting and the colors were obtained from the material properties.
   I have designed a new rendering method which uses the intensity to
   represent true color lighting values.  Basically I used the dword
   to store a 3 byte RGB structure instead of a single intensity.

   This means that the color values you use in the EDITMAT utility are
   not used.

How do I use this new rendering method?

   Use the EDITMAT utility and set the rendering method to number 73
   (user defined).  Any materials which use this method will be affected
   by the lights in PRLight.

   Since the old utilities will not recognize this new method of storing
   the colors, you will have to add the new lighting routine and
   recompile them.

   Registering a new lighting method is simple.  Just add the following
   routine to your code:


void PR_LightFunc_RGBTEXT (void)
{
PR_FACE_DATA_REAL *faceptr;
PR_DWORD packedrgb;

  if (ADDPRIV_setup_state)
    {
     if (last_material != ADDPRIV_mat)
       {
        guColorCombineFunction (GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB);
        grTexCombineFunction (GR_TMU0, GR_TEXTURECOMBINE_DECAL);
        PR_SelectTexture (ADDPRIV_mat->texture_number);

        grDepthBiasLevel (0);
        grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO,
                              GR_BLEND_ONE, GR_BLEND_ZERO);
        grAlphaTestFunction (GR_CMP_ALWAYS);
        last_material = ADDPRIV_mat;
       }
    }


  if (ADDPRIV_setup_data)
    {
     PR_WORKFACEFLAGS = !(ADDPRIV_face->flags & FFLAG_BACK_VISIBLE);

     packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[0];
     ADDPRIV_vptr1data->r = (packedrgb)       & 0xFF;
     ADDPRIV_vptr1data->g = (packedrgb >> 8)  & 0xFF;
     ADDPRIV_vptr1data->b = (packedrgb >> 16) & 0xFF;
     ADDPRIV_vptr1data->a = ADDPRIV_mat->a;

     packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[1];
     ADDPRIV_vptr2data->r = (packedrgb)       & 0xFF;
     ADDPRIV_vptr2data->g = (packedrgb >> 8)  & 0xFF;
     ADDPRIV_vptr2data->b = (packedrgb >> 16) & 0xFF;
     ADDPRIV_vptr2data->a = ADDPRIV_mat->a;

     packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[2];
     ADDPRIV_vptr3data->r = (packedrgb)       & 0xFF;
     ADDPRIV_vptr3data->g = (packedrgb >> 8)  & 0xFF;
     ADDPRIV_vptr3data->b = (packedrgb >> 16) & 0xFF;
     ADDPRIV_vptr3data->a = ADDPRIV_mat->a;

     faceptr = (PR_FACE_DATA_REAL *)&ADDPRIV_face->face_data;
     SET_TMAP(ADDPRIV_mat, ADDPRIV_vptr1data, ADDPRIV_vptr2data, ADDPRIV_vptr3data, ADDPRIV_vptr1, ADDPRIV_vptr2, ADDPRIV_vptr3, ADDPRIV_vptr1data,ADDPRIV_vptr2data,ADDPRIV_vptr3data,faceptr);
    }
}


Next remember to #include <prstate.h> or #include <d3dstate.h> depending
if you are using the 3Dfx or D3D libraries.

Finally, call the PR_RegisterRenderMethod as follows:

  PR_RegisterRenderMethod(73, PR_LightFunc_RGBTEXT, 0);

This should be called after the devices have been initialized.


The function as defined above was based on the contant gouraud shaded
method, which does not take dynamic lighting into account.  If you need
precomputed lighting AND dynamic lights, you should use the following
function instead:


void PR_LightFunc_RGBTEXT (void)
{
PR_FACE_DATA_REAL *faceptr;
PR_DWORD packedrgb;

  if (ADDPRIV_setup_state)
    {
     if (last_material != ADDPRIV_mat)
       {
        guColorCombineFunction (GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB);
        grTexCombineFunction (PR_CurrentTMU, GR_TEXTURECOMBINE_DECAL);
        PR_SelectTexture (ADDPRIV_mat->texture_number);

        grDepthBiasLevel (0);
        grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO,
                              GR_BLEND_ONE, GR_BLEND_ZERO);
        grAlphaTestFunction (GR_CMP_ALWAYS);

        last_material = ADDPRIV_mat;
       }
    }
   

  if (ADDPRIV_setup_data)
    {
     PR_WORKFACEFLAGS = !(ADDPRIV_face->flags & FFLAG_BACK_VISIBLE);
     if (ADDPRIV_vptr1data->dotproduct != ADDPRIV_material_num)
       {
        PR_CalcVertexLighting3Dfx (ADDPRIV_vptr1, ADDPRIV_vptr1data);

        packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[0];
        ADDPRIV_r += (packedrgb)       & 0xFF;
        ADDPRIV_g += (packedrgb >> 8)  & 0xFF;
        ADDPRIV_b += (packedrgb >> 16) & 0xFF;
        CLAMP_RGB;

        ADDPRIV_vptr1data->dotproduct = -1;
        ADDPRIV_vptr1data->r = ADDPRIV_r;
        ADDPRIV_vptr1data->g = ADDPRIV_g;
        ADDPRIV_vptr1data->b = ADDPRIV_b;
        ADDPRIV_vptr1data->a = ADDPRIV_mat->a;
       }

     if (ADDPRIV_vptr2data->dotproduct != ADDPRIV_material_num)
       {
        PR_CalcVertexLighting3Dfx (ADDPRIV_vptr2, ADDPRIV_vptr2data);

        packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[1];
        ADDPRIV_r += (packedrgb)       & 0xFF;
        ADDPRIV_g += (packedrgb >> 8)  & 0xFF;
        ADDPRIV_b += (packedrgb >> 16) & 0xFF;
        CLAMP_RGB;

        ADDPRIV_vptr2data->dotproduct = -1;
        ADDPRIV_vptr2data->r = ADDPRIV_r;
        ADDPRIV_vptr2data->g = ADDPRIV_g;
        ADDPRIV_vptr2data->b = ADDPRIV_b;
        ADDPRIV_vptr2data->a = ADDPRIV_mat->a;
       }

     if (ADDPRIV_vptr3data->dotproduct != ADDPRIV_material_num)
       {
        PR_CalcVertexLighting3Dfx (ADDPRIV_vptr3, ADDPRIV_vptr3data);

        packedrgb = *(PR_DWORD *)&ADDPRIV_facedatareal->col[2];
        ADDPRIV_r += (packedrgb)       & 0xFF;
        ADDPRIV_g += (packedrgb >> 8)  & 0xFF;
        ADDPRIV_b += (packedrgb >> 16) & 0xFF;
        CLAMP_RGB;

        ADDPRIV_vptr3data->dotproduct = -1;
        ADDPRIV_vptr3data->r = ADDPRIV_r;
        ADDPRIV_vptr3data->g = ADDPRIV_g;
        ADDPRIV_vptr3data->b = ADDPRIV_b;
        ADDPRIV_vptr3data->a = ADDPRIV_mat->a;
       }

     faceptr = (PR_FACE_DATA_REAL *)&ADDPRIV_face->face_data;
     SET_TMAP(ADDPRIV_mat, ADDPRIV_vptr1data, ADDPRIV_vptr2data, ADDPRIV_vptr3data, ADDPRIV_vptr1, ADDPRIV_vptr2, ADDPRIV_vptr3, ADDPRIV_vptr1data,ADDPRIV_vptr2data,ADDPRIV_vptr3data,faceptr);
    }
}


What else should I know about using this utility?

  PRLight is designed to be run from any directory, so keep your PRO
  file and textures in a separate directory.  You can add the directory
  to your path environment variable, or copy the files in the main PRLight
  directory to your \pr\bin directory if you have already installed
  Power Render.

  When you first load a new model, there will not be any lights.  This means
  you'll just get a black screen.  You'll probably want to add a directional
  light as the first light, so you can see the model. You can change the
  directional light to a point light afterwards if you don't want a
  directional light.

  You should also get familar with the camera control.  If you hold down
  CTRL and move the mouse up and down, the camera will move forward and
  backward in the direction it is facing.  If you hold down ALT and move
  the mouse, it will control the direction of the camera.  If you want to
  move the camera to a new location, first aim it where you want to go using
  ALT, and then use CTRL to move it.

  While you hold down CTRL or ALT, the current light will flash quickly.
  This will show you exactly which light you will be changing.

  If you cannot see the current light, you can hit ENTER to move the camera
  directly in front of it.  The current camera angle is maintained.

  If you want to move the current light directly in front of the camera,
  press SPACE.

  If you move the camera too far away from the model and can't find your way
  back, press HOME to return to the origin.  Note that models don't have to
  be centered at the origin so this may be a bad thing to do.

  If you hold down F1, a screen of text will appear which reminds you of
  these basic controls.


  PRLight reads some initialization data from a file called prlight.ini.
  This allows you to control the scale of the camera and light movement,
  maximum number of lights, etc.  Depending on the scale of your PRO models,
  you'll have to modify this file.  The default file looks like this:

  MAXLIGHT 500
  MOVEMENT_MULTIPLIER 20
  MAXRADIUS 15000
  POINTER_SCALE 200

  If you change any of these values, just change the number.  The utility
  requires that the lines occur in the order shown.

  MAXLIGHT defines how many lights are available.
  MOVEMENT_MULTIPLIER defines how fast the camera and lights move
  MAXRADIUS defines the largest radius value for a point light
  POINTER_SCALE defines the scale of the light markers.


  For larger models with lots of vertices, you may want to modify the
  code so the lighting is computed when the mouse button is released
  instead of every frame drawn.


I'm interested in designing a simple indoor level editor capable of creating
worlds like Tomb Raider, perhaps without the rooms above rooms feature.
If anyone would like to give input on a suitable file format or help out
in any way, let me know.  

I guess that's all.  If you have any comments or suggestions email Chris
(egerter@egerter.com)



