422 lines
5.9 KiB
C++
422 lines
5.9 KiB
C++
//
|
|
// Creates light maps.
|
|
//
|
|
|
|
#include "always.h"
|
|
#include "lmap.h"
|
|
#include "matrix.h"
|
|
#include "os.h"
|
|
#include "slap.h"
|
|
|
|
|
|
|
|
//
|
|
// The lightmap textures.
|
|
//
|
|
|
|
typedef struct
|
|
{
|
|
SLONG res;
|
|
UBYTE *bitmap;
|
|
|
|
} LMAP_Tex;
|
|
|
|
#define LMAP_MAX_TEXES 5
|
|
|
|
LMAP_Tex LMAP_tex[LMAP_MAX_TEXES] =
|
|
{
|
|
{16, NULL},
|
|
{32, NULL},
|
|
{64, NULL},
|
|
{128, NULL},
|
|
{256, NULL},
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Our lightmap structure.
|
|
//
|
|
|
|
typedef struct lmap_lmap
|
|
{
|
|
SLONG res;
|
|
UBYTE *bitmap;
|
|
|
|
} LMAP_Lmap;
|
|
|
|
|
|
|
|
|
|
LMAP_Lmap *LMAP_create(SLONG resolution)
|
|
{
|
|
SLONG i;
|
|
SLONG x;
|
|
SLONG y;
|
|
|
|
float dx;
|
|
float dy;
|
|
float dist;
|
|
float frac;
|
|
|
|
SLONG value;
|
|
|
|
UBYTE *pixel;
|
|
|
|
//
|
|
// Have we created the texture for this resolution?
|
|
//
|
|
|
|
for (i = 0; i < LMAP_MAX_TEXES; i++)
|
|
{
|
|
if (LMAP_tex[i].res == resolution)
|
|
{
|
|
if (LMAP_tex[i].bitmap != NULL)
|
|
{
|
|
//
|
|
// We've already generated this texture.
|
|
//
|
|
|
|
goto found_texture;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We must generate this texture.
|
|
//
|
|
|
|
LMAP_tex[i].bitmap = (UBYTE *) malloc(sizeof(UBYTE) * resolution * resolution); // It'll always work!
|
|
|
|
pixel = LMAP_tex[i].bitmap;
|
|
|
|
for (y = 0; y < resolution; y++)
|
|
for (x = 0; x < resolution; x++)
|
|
{
|
|
if (x == 0 || x == resolution - 1 ||
|
|
y == 0 || y == resolution - 1)
|
|
{
|
|
value = 0;
|
|
}
|
|
else
|
|
{
|
|
dx = fabs(float((resolution >> 1) - x));
|
|
dy = fabs(float((resolution >> 1) - y));
|
|
|
|
dist = sqrt(dx*dx + dy*dy);
|
|
|
|
frac = dist / float(resolution >> 1);
|
|
frac = frac * frac * frac;
|
|
|
|
value = 255 - ftol(256.0F * frac);
|
|
|
|
SATURATE(value, 0, 255);
|
|
|
|
// value = value * 64 >> 8;
|
|
}
|
|
|
|
*pixel++ = value;
|
|
}
|
|
|
|
goto found_texture;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is a funny resolution!
|
|
//
|
|
|
|
ASSERT(0);
|
|
|
|
return NULL;
|
|
|
|
found_texture:;
|
|
|
|
//
|
|
// Create a new lightmap.
|
|
//
|
|
|
|
LMAP_Lmap *ans = (LMAP_Lmap *) malloc(sizeof(LMAP_Lmap));
|
|
|
|
ans->res = resolution;
|
|
ans->bitmap = (UBYTE *) malloc(sizeof(UBYTE) * resolution * resolution);
|
|
|
|
return ans;
|
|
}
|
|
|
|
|
|
|
|
void LMAP_init(LMAP_Lmap *lmap)
|
|
{
|
|
if (lmap == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Zero out the bitmap.
|
|
//
|
|
|
|
memset(lmap->bitmap, 0, sizeof(UBYTE) * lmap->res * lmap->res);
|
|
|
|
//
|
|
// Initialise the shadowmapper.
|
|
//
|
|
|
|
SLAP_init(
|
|
lmap->bitmap,
|
|
lmap->res);
|
|
}
|
|
|
|
|
|
void LMAP_add_shadow(
|
|
LMAP_Lmap *lmap,
|
|
IMP_Mesh *im,
|
|
float light_x,
|
|
float light_y,
|
|
float light_z,
|
|
float light_matrix[9],
|
|
float light_lens)
|
|
{
|
|
SLONG i;
|
|
|
|
float x;
|
|
float y;
|
|
float z;
|
|
float X;
|
|
float Y;
|
|
float Z;
|
|
|
|
float au;
|
|
float av;
|
|
float bu;
|
|
float bv;
|
|
float cprod;
|
|
|
|
UBYTE f1;
|
|
UBYTE f2;
|
|
|
|
IMP_Vert *iv;
|
|
IMP_Face *ic;
|
|
IMP_Edge *ie;
|
|
|
|
IMP_Vert *iv1;
|
|
IMP_Vert *iv2;
|
|
IMP_Vert *iv3;
|
|
|
|
//
|
|
// Rotate all the points of the mesh into light-source space.
|
|
//
|
|
|
|
for (i = 0; i < im->num_verts; i++)
|
|
{
|
|
iv = &im->vert[i];
|
|
|
|
//
|
|
// Rotate the point into light-source space.
|
|
//
|
|
|
|
x = iv->x - light_x;
|
|
y = iv->y - light_y;
|
|
z = iv->z - light_z;
|
|
|
|
MATRIX_MUL(
|
|
light_matrix,
|
|
x,
|
|
y,
|
|
z);
|
|
|
|
if (z > 0.0F) // No zclip plane!
|
|
{
|
|
//
|
|
// Perspective transform.
|
|
//
|
|
|
|
Z = light_lens / z;
|
|
|
|
X = 0.5F + x * Z;
|
|
Y = 0.5F + y * Z;
|
|
|
|
iv->lu = X;
|
|
iv->lv = Y;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This point is behind the light!
|
|
//
|
|
|
|
ASSERT(0);
|
|
|
|
iv->lu = 0.0F;
|
|
iv->lv = 0.0F;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Work out which faces are visible from the lightsource (i.e. not
|
|
// backface culled).
|
|
//
|
|
|
|
for (i = 0; i < im->num_faces; i++)
|
|
{
|
|
ic = &im->face[i];
|
|
|
|
ASSERT(WITHIN(ic->v[0], 0, im->num_verts - 1));
|
|
ASSERT(WITHIN(ic->v[1], 0, im->num_verts - 1));
|
|
ASSERT(WITHIN(ic->v[2], 0, im->num_verts - 1));
|
|
|
|
iv1 = &im->vert[ic->v[0]];
|
|
iv2 = &im->vert[ic->v[1]];
|
|
iv3 = &im->vert[ic->v[2]];
|
|
|
|
au = iv2->lu - iv1->lu;
|
|
av = iv2->lv - iv1->lv;
|
|
|
|
bu = iv3->lu - iv1->lu;
|
|
bv = iv3->lv - iv1->lv;
|
|
|
|
cprod = au*bv - av*bu;
|
|
|
|
if (cprod <= 0.0F)
|
|
{
|
|
ic->flag |= IMP_FACE_FLAG_BACKFACE;
|
|
}
|
|
else
|
|
{
|
|
ic->flag &= ~IMP_FACE_FLAG_BACKFACE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Work out the sillouhette edges and add them to the shadow mapper.
|
|
//
|
|
|
|
for (i = 0; i < im->num_edges; i++)
|
|
{
|
|
ie = &im->edge[i];
|
|
|
|
ASSERT(WITHIN(ie->f1, 0, im->num_faces - 1));
|
|
ASSERT(WITHIN(ie->f2, 0, im->num_faces - 1) || ie->f2 == 0xffff);
|
|
|
|
f1 = im->face[ie->f1].flag;
|
|
|
|
if (ie->f2 == 0xffff)
|
|
{
|
|
f2 = 0;
|
|
}
|
|
else
|
|
{
|
|
f2 = im->face[ie->f2].flag;
|
|
}
|
|
|
|
if ((f1 ^ f2) & IMP_FACE_FLAG_BACKFACE)
|
|
{
|
|
//
|
|
// This is a silhoutte edge.
|
|
//
|
|
|
|
ASSERT(WITHIN(ie->v1, 0, im->num_verts - 1));
|
|
ASSERT(WITHIN(ie->v2, 0, im->num_verts - 1));
|
|
|
|
iv1 = &im->vert[ie->v1];
|
|
iv2 = &im->vert[ie->v2];
|
|
|
|
if (im->face[ie->f1].flag & IMP_FACE_FLAG_BACKFACE)
|
|
{
|
|
SLAP_add_edge(
|
|
ftol(iv1->lu * float(lmap->res << 8)),
|
|
ftol(iv1->lv * float(lmap->res << 8)),
|
|
ftol(iv2->lu * float(lmap->res << 8)),
|
|
ftol(iv2->lv * float(lmap->res << 8)));
|
|
}
|
|
else
|
|
{
|
|
SLAP_add_edge(
|
|
ftol(iv2->lu * float(lmap->res << 8)),
|
|
ftol(iv2->lv * float(lmap->res << 8)),
|
|
ftol(iv1->lu * float(lmap->res << 8)),
|
|
ftol(iv1->lv * float(lmap->res << 8)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void LMAP_render(LMAP_Lmap *lmap, OS_Texture *ot)
|
|
{
|
|
UBYTE *shadow;
|
|
UBYTE *lmaptex;
|
|
|
|
//
|
|
// Render the shadow map.
|
|
//
|
|
|
|
SLAP_render();
|
|
|
|
//
|
|
// Find the lightmap texture.
|
|
//
|
|
|
|
SLONG i;
|
|
|
|
for (i = 0; i < LMAP_MAX_TEXES; i++)
|
|
{
|
|
if (LMAP_tex[i].res == lmap->res)
|
|
{
|
|
if (LMAP_tex[i].bitmap != NULL)
|
|
{
|
|
//
|
|
// We've generated this texture.
|
|
//
|
|
|
|
lmaptex = LMAP_tex[i].bitmap;
|
|
|
|
goto found_texture;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(0);
|
|
|
|
return;
|
|
|
|
found_texture:;
|
|
|
|
//
|
|
// Create the texture.
|
|
//
|
|
|
|
OS_texture_lock(ot);
|
|
|
|
SLONG x;
|
|
SLONG y;
|
|
|
|
SLONG pixel;
|
|
|
|
shadow = lmap->bitmap;
|
|
|
|
for (y = 0; y < lmap->res; y++)
|
|
for (x = 0; x < lmap->res; x++)
|
|
{
|
|
pixel = (256 - *shadow) * *lmaptex >> 8;
|
|
|
|
if (OS_bitmap_ubyte_screen)
|
|
{
|
|
OS_BITMAP_UBYTE_PLOT(x,y, pixel);
|
|
}
|
|
else
|
|
{
|
|
OS_BITMAP_UWORD_PLOT(x,y, pixel,pixel,pixel);
|
|
}
|
|
|
|
shadow += 1;
|
|
lmaptex += 1;
|
|
}
|
|
|
|
OS_texture_unlock(ot);
|
|
}
|
|
|
|
|
|
|