MuckyFoot-UrbanChaos/thrust/lmap.cpp
2017-05-20 11:14:17 +10:00

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);
}