246 lines
9 KiB
C++
246 lines
9 KiB
C++
|
|
#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);
|
|
}
|
|
}
|
|
}
|
|
}
|