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