room101/TEXTURE.CPP

247 lines
9 KiB
C++
Raw Normal View History

#include "defs.hpp"
#include "texture.hpp"
#include "convex.hpp"
#include "triangle.hpp"
#include "polygon.hpp"
#define Trunc Round
/*******************************************************************************
** TextureMap
*******************************************************************************/
void
TextureMap(
Picture* texture,
Spanner* spanner,
Camera* camera,
Surface* surface,
Matrix matrix)
{
int x, xx;
Span defaultspan;
Vector R, S, T;
Triangle PMN, ABC;
defaultspan.x1 = 0;
defaultspan.x2 = camera->fb->width;
assert(texture && camera);
assert(texture->width > 0 && texture->height > 0);
int flag = 1;
/*
** Iterate scan lines from top to bottom.
*/
for (int y = scantop; y < scanbot; y++)
{
assert(y >= 0 && y < camera->fb->height);
int length = FIX_TO_INT(scanright[y].x) - FIX_TO_INT(scanleft[y].x);
/*
** Is this span visible?.
*/
if (length > 0 && (!spanner || spanner->lines[y].nspans > 0))
{
/*
** Iterate empty spans.
*/
for (int i = 0; i < (spanner ? spanner->lines[y].nspans : 1); i++)
{
/*
** Make a copy of polygon variables. We don't want to change these.
*/
int x1 = FIX_TO_INT(scanleft[y].x);
int x2 = FIX_TO_INT(scanright[y].x);
/*
** Clip polygon span to visible span.
*/
Span* span = spanner ? &spanner->lines[y].spans[i] : &defaultspan;
int cx = x1 - span->x1;
int cy = span->x2 - x2;
if (cx < 0) x1 = span->x1;
if (cy < 0) x2 = span->x2;
assert(x1 >= 0 && x2 <= camera->fb->width);
/*
** Test for visiblity.
*/
if (x1 < x2)
{
if (flag)
{
flag = 0;
VectorTransform(PMN[0], surface->PMN[0], matrix);
VectorRotate (PMN[1], surface->PMN[1], matrix);
VectorRotate (PMN[2], surface->PMN[2], matrix);
/*
** It's the magic ABC vectors. Adjust for lightmap width & height.
** Convert to fixed point.
*/
VectorCrossProduct(ABC[0], PMN[0], PMN[2]);
VectorCrossProduct(ABC[1], PMN[1], PMN[0]);
VectorCrossProduct(ABC[2], PMN[2], PMN[1]);
float xtile = texture->width;
float ytile = texture->height;
if (surface->colour == 1)
{
xtile *= surface->width / texture->width * 0.25f;
ytile *= surface->height / texture->height * 0.25f;
}
if (surface->colour == 2)
{
xtile *= (surface->width / texture->width) * 0.04f;
ytile *= (surface->height / texture->height) * 0.04f;
}
VectorScale(ABC[0], ABC[0], xtile * INT_TO_FIX(1));
VectorScale(ABC[1], ABC[1], ytile * INT_TO_FIX(1));
/*
** Adjust for camera space scale.
*/
float scale = camera->origin[1] / camera->origin[0];
R[0] = ABC[0][0] *= scale;
R[1] = ABC[1][0] *= scale;
R[2] = ABC[2][0] *= scale;
VectorScale(R, R, 16.0f);
}
/*
** Calculate texture point by transforming screen space point
** into texture space.
*/
S[0] = x1 - camera->origin[0];
S[1] = camera->origin[1] - y;
S[2] = camera->origin[1];
T[0] = VectorDotProduct(S, ABC[0]);
T[1] = VectorDotProduct(S, ABC[1]);
T[2] = VectorDotProduct(S, ABC[2]);
int u = Round(T[0] / T[2]), uu;
int v = Round(T[1] / T[2]), vv;
int zz = (scanright[y].z - scanleft[y].z) / length;
int z = cx < 0 ? scanleft[y].z - cx * zz : scanleft[y].z;
Pixel* fb = &camera->fb->pixels[y][x1];
Pixel* zb = &camera->zb->pixels[y][x1];
Pixel** tb = texture->pixels;
switch (surface->colour)
{
/*
** Render water/lava.
*/
case 1:
#undef AFFINE
#define AFFINE \
if (FIX_TO_INT(z) > *zb) \
{ \
*zb = FIX_TO_INT(z); \
*fb = PIXEL_BLEND(*fb, tb[FIX_TO_INT(v) & 0x3F][FIX_TO_INT(u) & 0x3F]); \
} \
fb++; zb++; u += uu; v += vv; z += zz;
for (x = x2 - x1; x > 16; x -= 16)
{
T[0] += R[0];
T[1] += R[1];
T[2] += R[2];
uu = (Round(T[0] / T[2]) - u) >> 4;
vv = (Round(T[1] / T[2]) - v) >> 4;
xx = 16; while (xx--) {AFFINE;}
}
T[0] += ABC[0][0] * (x - 1);
T[1] += ABC[1][0] * (x - 1);
T[2] += ABC[2][0] * (x - 1);
uu = (Round(T[0] / T[2]) - u) / x;
vv = (Round(T[1] / T[2]) - v) / x;
while (x--) {AFFINE;}
break;
/*
** Render Sky.
*/
case 2:
x = x2 - x1; while (x--) *zb++ = 0;
#undef AFFINE
#define AFFINE *fb++ = tb[FIX_TO_INT(v) & 0x1FF][FIX_TO_INT(u) & 0x1FF]; u += uu; v += vv;
for (x = x2 - x1; x > 16; x -= 16)
{
T[0] += R[0];
T[1] += R[1];
T[2] += R[2];
uu = (Round(T[0] / T[2]) - u) >> 4;
vv = (Round(T[1] / T[2]) - v) >> 4;
xx = 16; while (xx--) {AFFINE;}
}
T[0] += ABC[0][0] * (x - 1);
T[1] += ABC[1][0] * (x - 1);
T[2] += ABC[2][0] * (x - 1);
uu = (Round(T[0] / T[2]) - u) / x;
vv = (Round(T[1] / T[2]) - v) / x;
while (x--) {AFFINE;}
break;
default:
#undef AFFINE
#define AFFINE *zb++ = FIX_TO_INT(z); z += zz;
x = x2 - x1; while (x--) {AFFINE;}
#undef AFFINE
#define AFFINE *fb++ = tb[FIX_TO_INT(v)][FIX_TO_INT(u)]; u += uu; v += vv;
for (x = x2 - x1; x > 16; x -= 16)
{
T[0] += R[0];
T[1] += R[1];
T[2] += R[2];
uu = (Round(T[0] / T[2]) - u) >> 4;
vv = (Round(T[1] / T[2]) - v) >> 4;
xx = 16; while (xx--) {AFFINE;}
}
T[0] += ABC[0][0] * (x - 1);
T[1] += ABC[1][0] * (x - 1);
T[2] += ABC[2][0] * (x - 1);
uu = (Round(T[0] / T[2]) - u) / x;
vv = (Round(T[1] / T[2]) - v) / x;
while (x--) {AFFINE;}
break;
}
}
}
if (spanner)
{
SpannerValidate(spanner,
FIX_TO_INT(scanleft[y].x), y,
FIX_TO_INT(scanright[y].x), y + 1);
}
}
}
}