home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Homebrewer's Handbook
/
vr.iso
/
vr386
/
colormap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-19
|
9KB
|
293 lines
/* Routine to setup and compute colors */
/* for 256-color mode */
/* Written by Dave Stampe Mar 21 1992 */
/* Completely rewritten for VR-386 by Dave Stampe, Dec. 1993 */
// The idea of this code is to let you change the way lighting
// maps polygon attributes to color values that user_render_poly
// recieves, to allow for new effects.
// VR-386 also allows flexible handling of new LIGHT structures
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
#include <stdio.h>
#include <stdlib.h> /* strtoul() */
#include <dos.h>
#include <ctype.h> /* isdigit(), isalnum() */
#include <string.h> /* strnicmp() */
#include "vr_api.h"
#include "intmath.h"
#include "renderer.h"
//*********************************************************/
/* USER POLYGON LIGHTING ROUTINE: DETERMINES POLY COLOR # */
/* The 16-bit color the user specifies for a polygon is broken down as
follows:
H R SS CCCC BBBBBBBB
H is the highlight flag (the polygon should be highlighted in
some way, usually by outlining it in the highlight_color given above).
R is a reserved bit, which should be set to zero
SS is a two-bit field specifying one of four surface types:
00 is a constant-color surface; the 4-bit field CCCC is ignored, and the
8-bit field BBBBBBBB is used as an absolute color number
01 is a cosine-lit surface; the 4-bit field CCCC specifies one of 16
basic colors, and the 8-bit brightness field BBBBBBBB is multiplied
by the cosine of the angle between the light source and the polygon's
surface normal to provide a 4-bit shading value.
10 is a pseudo-metallic surface; the CCCC field gives the starting hue,
and the BBBBBBBB value is ignored. The color will cycle through
the different shades to give a 'metallic' effect.
11 is a pseudo-transparent surface made up of alternating rows of
spaced dots; other than that, it behaves like a pseudo-metallic
surface.
This routine maps the above into an 8-bit color number in the low byte
of its return value, and passes through the top four bits.
*/
/// NOTE FOR MULTIPLE LIGHT IMPLEMENTATION:
/// MAKE SUM OF AMBIENT AND OTHER LIGHTS 127
/// TO PREVENT SATURATION. SUM ALL COSINE-LIT
/// LIGHTS AS SEEN BELOW:
//*********** EXTERNAL LIGHTING CONTROL *************
static WORD ambient_light = 76;
static WORD light1_i = 51;
static COORD light1_x = 1000, light1_y = 15000, light1_z = -5000;
static BOOL light1_s = 0;
static WORD light2_i = 0;
static COORD light2_x, light2_y, light2_z;
static BOOL light2_s = 0;
// in COLORMAP.C, sets up lights to renderer
// this version takes only 3: plus sum of ambient
void setup_lights(LIGHT *llist[3], WORD nlights)
{
int i,j,k;
LIGHT *l;
COORD x,y,z;
DWORD lsum = 0;
DWORD isum = 0;
DWORD totlights = 0;
for(i=0;i<nlights;i++)
{
l = llist[i];
if(get_light_intensity(l)==0) continue;
if(get_light_type(l)==AMBIENT_LIGHT) isum += get_light_intensity(l);
else if(totlights==0)
{
light1_s = get_light_data(l, &light1_x,&light1_y,&light1_z,&light1_i);
lsum += light1_i;
totlights++;
}
else if(totlights==1)
{
light2_s = get_light_data(l, &light2_x,&light2_y,&light2_z,&light2_i);
lsum += light2_i;
totlights++;
}
}
lsum += isum;
ambient_light = mulmuldiv(isum,127,lsum); // scale lights so sum is 127
light1_i = mulmuldiv(light1_i, 127,lsum);
light2_i = mulmuldiv(light2_i, 127,lsum);
light1_s = (light1_s == SPOT_LIGHT);
light2_s = (light2_s == SPOT_LIGHT);
}
//*************** SPECIFIC POLY LIGHTING/COLORING ***********
static WORD map_mono16(POLY *p, int pcolor, int n)
{
int hilite = pcolor & 0xF000; /* highlight flag (MSB) */
int bright = pcolor & 0xFF; /* albedo */
int hue = (pcolor & 0x0F00) >> 8; /* basis color */
int color;
unsigned light;
if (hue == 0)
return ((bright & 15) | hilite); /* abs. palette color */
if ((pcolor & 0x3000) == 0 || n<3)
{
if (bright > 15) bright = 15; /* fixed (unlit) color or line */
return (hilite | bright); /* compute from hue, bright */
}
if (pcolor & 0x2000) /* metal/glass cycle phase compute */
{
color = compute_poly_cosine(p, light1_x, light1_y, light1_z, 0);
color = (bright >> 6) - (color >> 5) + ((hue+320) >> 6);
if (color < 0) color = 0;
if (color > 15) color = 15;
return (hilite | color);
}
/* COSINE-LIT COLOR */
light = 0;
if(light1_i)
{
color = compute_poly_cosine(p, light1_x, light1_y, light1_z, light1_s);
if (color > 0)
light += color*light1_i;
}
if (light2_i)
{
color = compute_poly_cosine(p, light2_x, light2_y, light2_z, light2_s);
if (color > 0)
light += color*light2_i;
}
// this is laboriously hand-tweeked for best range!
color = (light>>7) + ambient_light; // 0 to 127 total
color = (color * (bright>>1))>>5; // 0 to 511
color = (hue+16) * color;
color = color>>10;
if (color <= 0) return( hilite );
if (color > 15) return (15 | hilite);
return (color | hilite);
}
static WORD map_color256(POLY *p, int pcolor, int n)
{
int hilite = pcolor & 0xF000; /* highlight flag (MSB) */
int bright = pcolor & 0xFF; /* albedo */
int hue = (pcolor & 0x0F00) >> 4; /* basis color */
int color;
unsigned light;
if ((pcolor & 0x3000) == 0 || n<3)
{ /* fixed (unlit) color or not poly */
if (hue==0) return bright | hilite; /* black */
return hilite | hue | ((bright >> 4) & 0x0F) ;
}
if (pcolor & 0x2000) /* metal/glass cycle phase */
{
color = compute_poly_cosine(p, light1_x, light1_y, light1_z, 0);
color = (bright-(color<<1))>>4; /* cycle phase */
return hilite | hue | ((color<<4)&256) | (color&15); /* encode phase */
}
/** COSINE-LIT COLOR **/
light = 0;
if(light1_i)
{
color = compute_poly_cosine(p, light1_x, light1_y, light1_z, light1_s);
if (color > 0)
light += color*light1_i;
}
if (light2_i)
{
color = compute_poly_cosine(p, light2_x, light2_y, light2_z, light2_s);
if (color > 0)
light += color*light2_i;
}
color = (((light>>7) + ambient_light)*bright)>>11;
if (color < 1) return hilite; /* absolute zero: black */
if (color > 15) return (15 | hue | hilite); /* clip brite */
return (color | hue | hilite);
}
unsigned user_poly_color(POLY *p, unsigned pcolor, unsigned npoints, long maxz)
{
switch(screeninfo->colors)
{
case 16:
return map_mono16(p, pcolor, npoints);
case 256:
return map_color256(p, pcolor, npoints);
default:
return pcolor; /* unknown color mapping type */
}
}
//*****************************************************
//** MAP ASCII TO COLOR CODE
WORD convert_color(char *s, char **ptr)
{
int hue, value;
if (isdigit(*s)) return (unsigned) strtoul(s, ptr, 0);
if (ptr) for (*ptr = s; isalnum(**ptr) || **ptr == '_'; ++*ptr);
if (!strnicmp(s, "shaded", 6))
{
sscanf(s, "shaded_%d_%d", &hue, &value);
return 0x1000 | ((hue & 0x0F) << 8) | (value & 0xFF);
}
else if (!strnicmp(s, "metal", 5))
{
sscanf(s, "metal_%d_%d", &hue, &value);
return 0x2000 | ((hue & 0x0F) << 8) | ((value & 0x1F) << 3);
}
else if (!strnicmp(s, "glass", 5))
{
sscanf(s, "glass_%d_%d", &hue, &value);
return 0x3000 | ((hue & 0x0F) << 8) | ((value & 0x1F) << 3);
}
return 0;
}