mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
When a test fails we still have to update the different parameters for the following points. Instead of returning, jump to the end of the function where the updates take place. This should also fix graphical issues with stencils.
813 lines
25 KiB
C++
813 lines
25 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
|
* which is licensed under the MIT license (see LICENSE).
|
|
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
|
*/
|
|
|
|
#include "common/endian.h"
|
|
#include "graphics/tinygl/texelbuffer.h"
|
|
#include "graphics/tinygl/zbuffer.h"
|
|
#include "graphics/tinygl/zgl.h"
|
|
|
|
namespace TinyGL {
|
|
|
|
static const int NB_INTERP = 8;
|
|
|
|
static bool applyStipplePattern(int x, int y, const byte *stipple) {
|
|
|
|
int stippleX = x % 32;
|
|
int stippleY = y % 32;
|
|
int byteIndex = stippleY * 4 + (stippleX / 8); // 4 bytes per row
|
|
int bitIndex = stippleX % 8;
|
|
|
|
byte bitmask = 1 << (7 - bitIndex);
|
|
return (stipple[byteIndex] & bitmask);
|
|
}
|
|
|
|
template <bool kDepthWrite, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
|
void FrameBuffer::putPixelNoTexture(int fbOffset, uint *pz, byte *ps, int _a,
|
|
int x, int y, uint &z, uint &r, uint &g, uint &b, uint &a,
|
|
int &dzdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
|
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) {
|
|
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
|
goto end;
|
|
}
|
|
|
|
if (kStippleEnabled && !applyStipplePattern(x + _a, y, _polygonStipplePattern)) {
|
|
goto end;
|
|
}
|
|
|
|
if (kStencilEnabled) {
|
|
bool stencilResult = stencilTest(ps[_a]);
|
|
if (!stencilResult) {
|
|
stencilOp(false, true, ps + _a);
|
|
goto end;
|
|
}
|
|
}
|
|
bool depthTestResult;
|
|
if (kDepthTestEnabled) {
|
|
depthTestResult = compareDepth(z, pz[_a]);
|
|
} else {
|
|
depthTestResult = true;
|
|
}
|
|
if (kStencilEnabled) {
|
|
stencilOp(true, depthTestResult, ps + _a);
|
|
}
|
|
if (depthTestResult) {
|
|
writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite, kFogMode>
|
|
(fbOffset + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8),
|
|
z, fog, fog_r, fog_g, fog_b);
|
|
}
|
|
end:
|
|
z += dzdx;
|
|
if (kFogMode) {
|
|
fog += dfdx;
|
|
}
|
|
if (kSmoothMode) {
|
|
r += drdx;
|
|
g += dgdx;
|
|
b += dbdx;
|
|
a += dadx;
|
|
}
|
|
}
|
|
|
|
template <bool kDepthWrite, bool kLightsMode, bool kSmoothMode, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kDepthTestEnabled>
|
|
void FrameBuffer::putPixelTexture(int fbOffset, const TexelBuffer *texture,
|
|
uint wrap_s, uint wrap_t, uint *pz, byte *ps, int _a,
|
|
int x, int y, uint &z, int &t, int &s,
|
|
uint &r, uint &g, uint &b, uint &a,
|
|
int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, uint dadx,
|
|
uint &fog, int fog_r, int fog_g, int fog_b, int &dfdx) {
|
|
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
|
goto end;
|
|
}
|
|
|
|
if (kStencilEnabled) {
|
|
bool stencilResult = stencilTest(ps[_a]);
|
|
if (!stencilResult) {
|
|
stencilOp(false, true, ps + _a);
|
|
goto end;
|
|
}
|
|
}
|
|
bool depthTestResult;
|
|
if (kDepthTestEnabled) {
|
|
depthTestResult = compareDepth(z, pz[_a]);
|
|
} else {
|
|
depthTestResult = true;
|
|
}
|
|
if (kStencilEnabled) {
|
|
stencilOp(true, depthTestResult, ps + _a);
|
|
}
|
|
if (depthTestResult) {
|
|
uint8 c_a, c_r, c_g, c_b;
|
|
texture->getARGBAt(wrap_s, wrap_t, s, t, c_a, c_r, c_g, c_b);
|
|
if (kLightsMode) {
|
|
uint l_a = (a >> (ZB_POINT_ALPHA_BITS - 8));
|
|
uint l_r = (r >> (ZB_POINT_RED_BITS - 8));
|
|
uint l_g = (g >> (ZB_POINT_GREEN_BITS - 8));
|
|
uint l_b = (b >> (ZB_POINT_BLUE_BITS - 8));
|
|
c_a = (c_a * l_a) >> (ZB_POINT_ALPHA_BITS - 8);
|
|
c_r = (c_r * l_r) >> (ZB_POINT_RED_BITS - 8);
|
|
c_g = (c_g * l_g) >> (ZB_POINT_GREEN_BITS - 8);
|
|
c_b = (c_b * l_b) >> (ZB_POINT_BLUE_BITS - 8);
|
|
}
|
|
writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite, kFogMode>(fbOffset + _a, c_a, c_r, c_g, c_b, z, fog, fog_r, fog_g, fog_b);
|
|
}
|
|
end:
|
|
z += dzdx;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
if (kFogMode) {
|
|
fog += dfdx;
|
|
}
|
|
if (kSmoothMode) {
|
|
a += dadx;
|
|
r += drdx;
|
|
g += dgdx;
|
|
b += dbdx;
|
|
}
|
|
}
|
|
|
|
template <bool kDepthWrite, bool kEnableScissor, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
|
void FrameBuffer::putPixelDepth(uint *pz, byte *ps, int _a, int x, int y, uint &z, int &dzdx) {
|
|
if (kEnableScissor && scissorPixel(x + _a, y)) {
|
|
goto end;
|
|
}
|
|
|
|
/*if (kStippleEnabled && !applyStipplePattern(x + _a, y, _polygonStipplePattern)) {
|
|
return;
|
|
}*/
|
|
|
|
if (kStencilEnabled) {
|
|
bool stencilResult = stencilTest(ps[_a]);
|
|
if (!stencilResult) {
|
|
stencilOp(false, true, ps + _a);
|
|
goto end;
|
|
}
|
|
}
|
|
bool depthTestResult;
|
|
if (kDepthTestEnabled) {
|
|
depthTestResult = compareDepth(z, pz[_a]);
|
|
} else {
|
|
depthTestResult = true;
|
|
}
|
|
if (kStencilEnabled) {
|
|
stencilOp(true, depthTestResult, ps + _a);
|
|
}
|
|
if (kDepthWrite && depthTestResult) {
|
|
pz[_a] = z;
|
|
}
|
|
end:
|
|
z += dzdx;
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode,
|
|
bool kDepthWrite, bool kFogMode, bool kAlphaTestEnabled, bool kEnableScissor,
|
|
bool kBlendingEnabled, bool kStencilEnabled, bool kStippleEnabled, bool kDepthTestEnabled>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const TexelBuffer *texture;
|
|
float fdzdx = 0, fndzdx = 0, ndszdx = 0, ndtzdx = 0;
|
|
|
|
ZBufferPoint *tp, *pr1 = 0, *pr2 = 0, *l1 = 0, *l2 = 0;
|
|
float fdx1, fdx2, fdy1, fdy2, fz0, d1, d2;
|
|
uint *pz1 = nullptr;
|
|
byte *ps1 = nullptr;
|
|
int part, update_left = 1, update_right = 1;
|
|
|
|
int nb_lines, dx1, dy1, tmp, dx2, dy2, y;
|
|
|
|
int error = 0, derror = 0;
|
|
int x1 = 0, dxdy_min = 0, dxdy_max = 0;
|
|
// warning: x2 is multiplied by 2^16
|
|
int x2 = 0, dx2dy2 = 0;
|
|
|
|
int z1 = 0, dzdx = 0, dzdy = 0, dzdl_min = 0, dzdl_max = 0;
|
|
int f1 = 0, dfdx = 0, dfdy = 0, dfdl_min = 0, dfdl_max = 0;
|
|
|
|
int r1 = 0, drdx = 0, drdy = 0, drdl_min = 0, drdl_max = 0;
|
|
int g1 = 0, dgdx = 0, dgdy = 0, dgdl_min = 0, dgdl_max = 0;
|
|
int b1 = 0, dbdx = 0, dbdy = 0, dbdl_min = 0, dbdl_max = 0;
|
|
int a1 = 0, dadx = 0, dady = 0, dadl_min = 0, dadl_max = 0;
|
|
|
|
float sz1 = 0.0, dszdx = 0, dszdy = 0, dszdl_min = 0.0, dszdl_max = 0.0;
|
|
float tz1 = 0.0, dtzdx = 0, dtzdy = 0, dtzdl_min = 0.0, dtzdl_max = 0.0;
|
|
|
|
byte fog_r = 0, fog_g = 0, fog_b = 0;
|
|
|
|
// we sort the vertex with increasing y
|
|
if (p1->y < p0->y) {
|
|
tp = p0;
|
|
p0 = p1;
|
|
p1 = tp;
|
|
}
|
|
if (p2->y < p0->y) {
|
|
tp = p2;
|
|
p2 = p1;
|
|
p1 = p0;
|
|
p0 = tp;
|
|
} else if (p2->y < p1->y) {
|
|
tp = p1;
|
|
p1 = p2;
|
|
p2 = tp;
|
|
}
|
|
|
|
// we compute dXdx and dXdy for all interpolated values
|
|
|
|
fdx1 = (float)(p1->x - p0->x);
|
|
fdy1 = (float)(p1->y - p0->y);
|
|
|
|
fdx2 = (float)(p2->x - p0->x);
|
|
fdy2 = (float)(p2->y - p0->y);
|
|
|
|
fz0 = fdx1 * fdy2 - fdx2 * fdy1;
|
|
if (fz0 == 0)
|
|
return;
|
|
fz0 = (float)(1.0 / fz0);
|
|
|
|
fdx1 *= fz0;
|
|
fdy1 *= fz0;
|
|
fdx2 *= fz0;
|
|
fdy2 *= fz0;
|
|
|
|
if (kInterpRGB && kFogMode) {
|
|
fog_r = _fogColorR * 255;
|
|
fog_g = _fogColorG * 255;
|
|
fog_b = _fogColorB * 255;
|
|
d1 = (float)(p1->f - p0->f);
|
|
d2 = (float)(p2->f - p0->f);
|
|
dfdx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
dfdy = (int)(fdx1 * d2 - fdx2 * d1);
|
|
}
|
|
|
|
if (kInterpZ) {
|
|
d1 = (float)(p1->z - p0->z);
|
|
d2 = (float)(p2->z - p0->z);
|
|
dzdx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
dzdy = (int)(fdx1 * d2 - fdx2 * d1);
|
|
}
|
|
|
|
if (kInterpRGB && kSmoothMode) {
|
|
d1 = (float)(p1->r - p0->r);
|
|
d2 = (float)(p2->r - p0->r);
|
|
drdx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
drdy = (int)(fdx1 * d2 - fdx2 * d1);
|
|
|
|
d1 = (float)(p1->g - p0->g);
|
|
d2 = (float)(p2->g - p0->g);
|
|
dgdx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
dgdy = (int)(fdx1 * d2 - fdx2 * d1);
|
|
|
|
d1 = (float)(p1->b - p0->b);
|
|
d2 = (float)(p2->b - p0->b);
|
|
dbdx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
dbdy = (int)(fdx1 * d2 - fdx2 * d1);
|
|
|
|
d1 = (float)(p1->a - p0->a);
|
|
d2 = (float)(p2->a - p0->a);
|
|
dadx = (int)(fdy2 * d1 - fdy1 * d2);
|
|
dady = (int)(fdx1 * d2 - fdx2 * d1);
|
|
}
|
|
|
|
if (kInterpST || kInterpSTZ) {
|
|
if (kInterpSTZ) {
|
|
float zz;
|
|
zz = (float)p0->z;
|
|
p0->sz = (float)p0->s * zz;
|
|
p0->tz = (float)p0->t * zz;
|
|
zz = (float)p1->z;
|
|
p1->sz = (float)p1->s * zz;
|
|
p1->tz = (float)p1->t * zz;
|
|
zz = (float)p2->z;
|
|
p2->sz = (float)p2->s * zz;
|
|
p2->tz = (float)p2->t * zz;
|
|
} else {
|
|
p0->sz = (float)p0->s;
|
|
p0->tz = (float)p0->t;
|
|
p1->sz = (float)p1->s;
|
|
p1->tz = (float)p1->t;
|
|
p2->sz = (float)p2->s;
|
|
p2->tz = (float)p2->t;
|
|
}
|
|
|
|
d1 = p1->sz - p0->sz;
|
|
d2 = p2->sz - p0->sz;
|
|
dszdx = (fdy2 * d1 - fdy1 * d2);
|
|
dszdy = (fdx1 * d2 - fdx2 * d1);
|
|
|
|
d1 = p1->tz - p0->tz;
|
|
d2 = p2->tz - p0->tz;
|
|
dtzdx = (fdy2 * d1 - fdy1 * d2);
|
|
dtzdy = (fdx1 * d2 - fdx2 * d1);
|
|
}
|
|
|
|
int polyOffset = 0;
|
|
if (kInterpZ && kInterpRGB && (_offsetStates & TGL_OFFSET_FILL)) {
|
|
int m = MAX(ABS(dzdx), ABS(dzdy));
|
|
polyOffset = -m * _offsetFactor + -_offsetUnits * (1 << 6);
|
|
}
|
|
|
|
// screen coordinates
|
|
|
|
int pp1 = _pbufWidth * p0->y;
|
|
pz1 = _zbuf + p0->y * _pbufWidth;
|
|
if (kStencilEnabled) {
|
|
ps1 = _sbuf + p0->y * _pbufWidth;
|
|
}
|
|
|
|
if (kInterpRGB && !kSmoothMode) {
|
|
r1 = p2->r;
|
|
g1 = p2->g;
|
|
b1 = p2->b;
|
|
a1 = p2->a;
|
|
}
|
|
|
|
if (kInterpRGB && (kInterpST || kInterpSTZ)) {
|
|
texture = _currentTexture;
|
|
fdzdx = (float)dzdx;
|
|
fndzdx = NB_INTERP * fdzdx;
|
|
ndszdx = NB_INTERP * dszdx;
|
|
ndtzdx = NB_INTERP * dtzdx;
|
|
}
|
|
|
|
if (fz0 > 0) {
|
|
l1 = p0;
|
|
l2 = p2;
|
|
pr1 = p0;
|
|
pr2 = p1;
|
|
} else {
|
|
l1 = p0;
|
|
l2 = p1;
|
|
pr1 = p0;
|
|
pr2 = p2;
|
|
}
|
|
nb_lines = p1->y - p0->y;
|
|
y = p0->y;
|
|
for (part = 0; part < 2; part++) {
|
|
if (part == 1) {
|
|
// second part
|
|
if (fz0 > 0) {
|
|
update_left = 0;
|
|
pr1 = p1;
|
|
pr2 = p2;
|
|
} else {
|
|
update_right = 0;
|
|
l1 = p1;
|
|
l2 = p2;
|
|
}
|
|
nb_lines = p2->y - p1->y + 1;
|
|
}
|
|
|
|
// compute the values for the left edge
|
|
|
|
if (update_left) {
|
|
dy1 = l2->y - l1->y;
|
|
dx1 = l2->x - l1->x;
|
|
if (dy1 > 0)
|
|
tmp = (dx1 << 16) / dy1;
|
|
else
|
|
tmp = 0;
|
|
x1 = l1->x;
|
|
error = 0;
|
|
derror = tmp & 0x0000ffff;
|
|
dxdy_min = tmp >> 16;
|
|
dxdy_max = dxdy_min + 1;
|
|
|
|
if (kInterpRGB && kFogMode) {
|
|
f1 = l1->f;
|
|
dfdl_min = (dfdy + dfdx * dxdy_min);
|
|
dfdl_max = dfdl_min + dfdx;
|
|
}
|
|
|
|
if (kInterpZ) {
|
|
z1 = l1->z + polyOffset;
|
|
dzdl_min = (dzdy + dzdx * dxdy_min);
|
|
dzdl_max = dzdl_min + dzdx;
|
|
}
|
|
|
|
if (kInterpRGB && kSmoothMode) {
|
|
r1 = l1->r;
|
|
drdl_min = (drdy + drdx * dxdy_min);
|
|
drdl_max = drdl_min + drdx;
|
|
|
|
g1 = l1->g;
|
|
dgdl_min = (dgdy + dgdx * dxdy_min);
|
|
dgdl_max = dgdl_min + dgdx;
|
|
|
|
b1 = l1->b;
|
|
dbdl_min = (dbdy + dbdx * dxdy_min);
|
|
dbdl_max = dbdl_min + dbdx;
|
|
|
|
a1 = l1->a;
|
|
dadl_min = (dady + dadx * dxdy_min);
|
|
dadl_max = dadl_min + dadx;
|
|
}
|
|
|
|
if (kInterpST || kInterpSTZ) {
|
|
sz1 = l1->sz;
|
|
dszdl_min = (dszdy + dszdx * dxdy_min);
|
|
dszdl_max = dszdl_min + dszdx;
|
|
|
|
tz1 = l1->tz;
|
|
dtzdl_min = (dtzdy + dtzdx * dxdy_min);
|
|
dtzdl_max = dtzdl_min + dtzdx;
|
|
}
|
|
}
|
|
|
|
// compute values for the right edge
|
|
|
|
if (update_right) {
|
|
dx2 = (pr2->x - pr1->x);
|
|
dy2 = (pr2->y - pr1->y);
|
|
if (dy2 > 0)
|
|
dx2dy2 = (dx2 << 16) / dy2;
|
|
else
|
|
dx2dy2 = 0;
|
|
x2 = pr1->x << 16;
|
|
}
|
|
|
|
// we draw all the scan line of the part
|
|
while (nb_lines > 0) {
|
|
int x = x1;
|
|
if (!kInterpRGB) {
|
|
int n;
|
|
uint *pz;
|
|
byte *ps = nullptr;
|
|
uint z;
|
|
n = (x2 >> 16) - x1;
|
|
if (kInterpZ) {
|
|
pz = pz1 + x1;
|
|
z = z1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps = ps1 + x1;
|
|
}
|
|
while (n >= 3) {
|
|
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 0, x, y, z, dzdx);
|
|
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 1, x, y, z, dzdx);
|
|
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 2, x, y, z, dzdx);
|
|
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 3, x, y, z, dzdx);
|
|
if (kInterpZ) {
|
|
pz += 4;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += 4;
|
|
}
|
|
n -= 4;
|
|
x += 4;
|
|
}
|
|
while (n >= 0) {
|
|
putPixelDepth<kDepthWrite, kEnableScissor, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>(pz, ps, 0, x, y, z, dzdx);
|
|
if (kInterpZ) {
|
|
pz += 1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += 1;
|
|
}
|
|
n -= 1;
|
|
x += 1;
|
|
}
|
|
} else if (!(kInterpST || kInterpSTZ)) {
|
|
uint *pz;
|
|
byte *ps = nullptr;
|
|
int pp;
|
|
uint z, r, g, b, a, fog;
|
|
int n = (x2 >> 16) - x1;
|
|
pp = pp1 + x1;
|
|
r = r1;
|
|
g = g1;
|
|
b = b1;
|
|
a = a1;
|
|
if (kFogMode) {
|
|
fog = f1;
|
|
}
|
|
if (kInterpZ) {
|
|
pz = pz1 + x1;
|
|
z = z1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps = ps1 + x1;
|
|
}
|
|
while (n >= 3) {
|
|
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
|
(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
|
(pp, pz, ps, 1, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
|
(pp, pz, ps, 2, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
|
(pp, pz, ps, 3, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
pp += 4;
|
|
if (kInterpZ) {
|
|
pz += 4;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += 4;
|
|
}
|
|
n -= 4;
|
|
x += 4;
|
|
}
|
|
while (n >= 0) {
|
|
putPixelNoTexture<kDepthWrite, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kStippleEnabled, kDepthTestEnabled>
|
|
(pp, pz, ps, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
pp += 1;
|
|
if (kInterpZ) {
|
|
pz += 1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += 1;
|
|
}
|
|
n -= 1;
|
|
x += 1;
|
|
}
|
|
} else if (kInterpST || kInterpSTZ) {
|
|
uint *pz;
|
|
byte *ps = nullptr;
|
|
int s, t;
|
|
uint z, r, g, b, a, fog;
|
|
int n, pp;
|
|
float sz, tz, fz, zinv;
|
|
int dsdx, dtdx;
|
|
|
|
n = (x2 >> 16) - x1;
|
|
fz = (float)z1;
|
|
zinv = (float)(1.0 / fz);
|
|
|
|
pp = pp1 + x1;
|
|
if (kFogMode) {
|
|
fog = f1;
|
|
}
|
|
if (kInterpZ) {
|
|
pz = pz1 + x1;
|
|
z = z1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps = ps1 + x1;
|
|
}
|
|
sz = sz1;
|
|
tz = tz1;
|
|
r = r1;
|
|
g = g1;
|
|
b = b1;
|
|
a = a1;
|
|
while (n >= (NB_INTERP - 1)) {
|
|
{
|
|
float ss, tt;
|
|
ss = sz * zinv;
|
|
tt = tz * zinv;
|
|
s = (int)ss;
|
|
t = (int)tt;
|
|
dsdx = (int)((dszdx - ss * fdzdx) * zinv);
|
|
dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
|
|
fz += fndzdx;
|
|
zinv = (float)(1.0 / fz);
|
|
}
|
|
for (int _a = 0; _a < NB_INTERP; _a++) {
|
|
putPixelTexture<kDepthWrite, kInterpRGB, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kDepthTestEnabled>
|
|
(pp, texture, _wrapS, _wrapT, pz, ps, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
}
|
|
pp += NB_INTERP;
|
|
if (kInterpZ) {
|
|
pz += NB_INTERP;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += NB_INTERP;
|
|
}
|
|
sz += ndszdx;
|
|
tz += ndtzdx;
|
|
n -= NB_INTERP;
|
|
x += NB_INTERP;
|
|
}
|
|
|
|
{
|
|
float ss, tt;
|
|
ss = sz * zinv;
|
|
tt = tz * zinv;
|
|
s = (int)ss;
|
|
t = (int)tt;
|
|
dsdx = (int)((dszdx - ss * fdzdx) * zinv);
|
|
dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
|
|
}
|
|
|
|
while (n >= 0) {
|
|
putPixelTexture<kDepthWrite, kInterpRGB, kSmoothMode, kFogMode, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled, kStencilEnabled, kDepthTestEnabled>
|
|
(pp, texture, _wrapS, _wrapT, pz, ps, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx, fog, fog_r, fog_g, fog_b, dfdx);
|
|
pp += 1;
|
|
if (kInterpZ) {
|
|
pz += 1;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps += 1;
|
|
}
|
|
n -= 1;
|
|
x += 1;
|
|
}
|
|
}
|
|
|
|
// left edge
|
|
error += derror;
|
|
if (error > 0) {
|
|
error -= 0x10000;
|
|
x1 += dxdy_max;
|
|
if (kInterpRGB && kFogMode) {
|
|
f1 += dfdl_max;
|
|
}
|
|
if (kInterpZ) {
|
|
z1 += dzdl_max;
|
|
}
|
|
if (kInterpRGB && kSmoothMode) {
|
|
r1 += drdl_max;
|
|
g1 += dgdl_max;
|
|
b1 += dbdl_max;
|
|
a1 += dadl_max;
|
|
}
|
|
if (kInterpST || kInterpSTZ) {
|
|
sz1 += dszdl_max;
|
|
tz1 += dtzdl_max;
|
|
}
|
|
} else {
|
|
x1 += dxdy_min;
|
|
if (kInterpRGB && kFogMode) {
|
|
f1 += dfdl_min;
|
|
}
|
|
if (kInterpZ) {
|
|
z1 += dzdl_min;
|
|
}
|
|
if (kInterpRGB && kSmoothMode) {
|
|
r1 += drdl_min;
|
|
g1 += dgdl_min;
|
|
b1 += dbdl_min;
|
|
a1 += dadl_min;
|
|
}
|
|
if (kInterpST || kInterpSTZ) {
|
|
sz1 += dszdl_min;
|
|
tz1 += dtzdl_min;
|
|
}
|
|
}
|
|
|
|
// right edge
|
|
x2 += dx2dy2;
|
|
|
|
// screen coordinates
|
|
if (kInterpRGB) {
|
|
pp1 += _pbufWidth;
|
|
}
|
|
if (kInterpZ) {
|
|
pz1 += _pbufWidth;
|
|
}
|
|
if (kStencilEnabled) {
|
|
ps1 += _pbufWidth;
|
|
}
|
|
|
|
nb_lines--;
|
|
y++;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled, bool kStippleEnabled>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_depthTestEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, kStippleEnabled, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, kStippleEnabled, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending, bool kStencilEnabled>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_polygonStippleEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, kStencilEnabled, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_sbuf && _stencilTestEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, kEnableBlending, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest, bool kEnableScissor>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_blendingEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, kEnableScissor, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode, bool kEnableAlphaTest>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_clippingEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, kEnableAlphaTest, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite, bool kFogMode>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_alphaTestEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, kFogMode, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, bool kSmoothMode, bool kDepthWrite>
|
|
void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
if (_fogEnabled) {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, true>(p0, p1, p2);
|
|
} else {
|
|
fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kSmoothMode, kDepthWrite, false>(p0, p1, p2);
|
|
}
|
|
}
|
|
|
|
void FrameBuffer::fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const bool interpZ = true;
|
|
const bool interpRGB = false;
|
|
const bool interpST = false;
|
|
const bool interpSTZ = false;
|
|
const bool smoothMode = false;
|
|
if (_depthWrite && _depthTestEnabled)
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
|
else
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
|
}
|
|
|
|
void FrameBuffer::fillTriangleFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const bool interpZ = true;
|
|
const bool interpRGB = true;
|
|
const bool interpST = false;
|
|
const bool interpSTZ = false;
|
|
const bool smoothMode = false;
|
|
if (_depthWrite && _depthTestEnabled)
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
|
else
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
|
}
|
|
|
|
// Smooth filled triangle.
|
|
void FrameBuffer::fillTriangleSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const bool interpZ = true;
|
|
const bool interpRGB = true;
|
|
const bool interpST = false;
|
|
const bool interpSTZ = false;
|
|
const bool smoothMode = true;
|
|
if (_depthWrite && _depthTestEnabled)
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
|
else
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
|
}
|
|
|
|
void FrameBuffer::fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const bool interpZ = true;
|
|
const bool interpRGB = true;
|
|
const bool interpST = true;
|
|
const bool interpSTZ = true;
|
|
const bool smoothMode = true;
|
|
if (_depthWrite && _depthTestEnabled)
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
|
else
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
|
}
|
|
|
|
void FrameBuffer::fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
|
|
const bool interpZ = true;
|
|
const bool interpRGB = true;
|
|
const bool interpST = false;
|
|
const bool interpSTZ = true;
|
|
const bool smoothMode = false;
|
|
if (_depthWrite && _depthTestEnabled)
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, true>(p0, p1, p2);
|
|
else
|
|
fillTriangle<interpRGB, interpZ, interpST, interpSTZ, smoothMode, false>(p0, p1, p2);
|
|
}
|
|
|
|
} // end of namespace TinyGL
|