scummvm/engines/icb/drawpoly_pc.cpp
2022-10-08 01:42:15 +02:00

3736 lines
100 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.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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/>.
*
*/
#include "engines/icb/common/px_common.h"
#include "engines/icb/gfx/psx_pcdefines.h"
#include "engines/icb/gfx/psx_pcdefines.h"
#include "engines/icb/gfx/psx_scrn.h"
#include "engines/icb/common/px_capri_maths.h"
#include "engines/icb/gfx/psx_poly.h"
#include "engines/icb/global_objects_psx.h"
#include "engines/icb/light_pc.h"
namespace ICB {
#if _PSX_ON_PC == 1
extern uint32 selFace;
extern CVECTOR unlitPoly;
extern CVECTOR deadObjectColour;
extern uint32 deadObject;
extern uint32 _drawBface;
extern uint8 selWRed;
extern uint8 selWGreen;
extern uint8 selWBlue;
extern uint8 selPRed;
extern uint8 selPGreen;
extern uint8 selPBlue;
extern uint8 selPAlpha;
#else // #if _PSX_ON_PC == 1
uint32 selFace = 65537;
CVECTOR unlitPoly = {255, 255, 255, 0};
CVECTOR deadObjectColour = {0, 0, 0, 0};
uint32 deadObject = 0;
uint32 _drawBface = 0;
uint8 selWRed = 0;
uint8 selWGreen = 255;
uint8 selWBlue = 255;
uint8 selPRed = 255;
uint8 selPGreen = 255;
uint8 selPBlue = 0;
uint8 selPAlpha = 0;
#endif // #if _PSX_ON_PC == 1
// Specialist lighting routines for polygons
// support for bounce & width
inline void LightPolygon(SVECTOR *n0, CVECTOR *rgbIn, CVECTOR *rgb0) {
SVECTORPC lightEffect;
// Normal line vector(local) -> light source effect
ApplyMatrixSV_pc(gtelight_pc, n0, &lightEffect);
if (useLampWidth) {
lightEffect.vx = (int16)(lightEffect.vx + lampWidth[0]);
lightEffect.vy = (int16)(lightEffect.vy + lampWidth[1]);
lightEffect.vz = (int16)(lightEffect.vy + lampWidth[2]);
}
if (useLampBounce) {
if (lightEffect.vx < 0) {
lightEffect.vx = (int16)-lightEffect.vx;
if (lightEffect.vx > lampBounce[0])
lightEffect.vx = (int16)lampBounce[0];
}
if (lightEffect.vy < 0) {
lightEffect.vy = (int16)-lightEffect.vy;
if (lightEffect.vy > lampBounce[1])
lightEffect.vy = (int16)lampBounce[1];
}
if (lightEffect.vz < 0) {
lightEffect.vz = (int16)-lightEffect.vz;
if (lightEffect.vz > lampBounce[2])
lightEffect.vz = (int16)lampBounce[2];
}
} else {
if (lightEffect.vx < 0)
lightEffect.vx = 0;
if (lightEffect.vy < 0)
lightEffect.vy = 0;
if (lightEffect.vz < 0)
lightEffect.vz = 0;
}
// Light source effect -> Colour effect(local colour matrix+back colour)
SVECTORPC colourEffect;
ApplyMatrixSV_pc(gtecolour_pc, &lightEffect, &colourEffect);
if (colourEffect.vx < 0)
colourEffect.vx = 0;
if (colourEffect.vy < 0)
colourEffect.vy = 0;
if (colourEffect.vz < 0)
colourEffect.vz = 0;
// colourEffect is 0-4095 (2^12)
// gteback is 0-255 (2^8)
colourEffect.vx = (int16)((colourEffect.vx >> 4) + gteback_pc[0]);
colourEffect.vy = (int16)((colourEffect.vy >> 4) + gteback_pc[1]);
colourEffect.vz = (int16)((colourEffect.vz >> 4) + gteback_pc[2]);
// 256 = 1.0 in colourEffect
// 128 = 1.0 in in0
int32 red = (rgbIn->r * colourEffect.vx);
int32 green = (rgbIn->g * colourEffect.vy);
int32 blue = (rgbIn->b * colourEffect.vz);
red = red >> 8;
green = green >> 8;
blue = blue >> 8;
if (red > 255)
red = 255;
if (green > 255)
green = 255;
if (blue > 255)
blue = 255;
rgb0->r = (uint8)(red);
rgb0->g = (uint8)(green);
rgb0->b = (uint8)(blue);
}
// Specialist lighting routines for polygons
// support for bounce & width
inline void LightPolygon3(SVECTOR *n0, SVECTOR *n1, SVECTOR *n2, CVECTOR *rgbIn, CVECTOR *rgb0, CVECTOR *rgb1, CVECTOR *rgb2) {
LightPolygon(n0, rgbIn, rgb0);
LightPolygon(n1, rgbIn, rgb1);
LightPolygon(n2, rgbIn, rgb2);
}
#define LIGHTPOLYGON(n0, rgbIn, rgb0) \
{ \
if (useLampWidth || useLampBounce) \
LightPolygon(n0, rgbIn, rgb0); \
else \
gte_NormalColorCol_pc(n0, rgbIn, rgb0); \
}
#define LIGHTPOLYGON3(n0, n1, n2, rgbIn, rgb0, rgb1, rgb2) \
{ \
if (useLampWidth || useLampBounce) \
LightPolygon3(n0, n1, n2, rgbIn, rgb0, rgb1, rgb2); \
else \
gte_NormalColorCol3_pc(n0, n1, n2, rgbIn, rgb0, rgb1, rgb2); \
}
//----------------------------------------------------------------
/*
gte_ll();
gte_llv0();
gte_llv1();
gte_llv2();
gte_llir();
gte_llv0tr();
gte_llv1tr();
gte_llv2tr();
gte_llirtr();
gte_llv0bk();
gte_llv1bk();
gte_llv2bk();
gte_llirbk();
gte_lc();
gte_lcv0();
gte_lcv1();
gte_lcv2();
gte_lcir();
gte_lcv0tr();
gte_lcv1tr();
gte_lcv2tr();
gte_lcirtr();
gte_lcv0bk();
gte_lcv1bk();
gte_lcv2bk();
gte_lcirbk();
*/
//------------------------------------------------------------------------
// Flat, Un-Textured, Self-Luminous, triangles
void drawFUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
CVECTOR *rgbIn;
uint32 tmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// 0x20 | B | G | R
// v1 | v0
// pad | v2
rgbIn = (CVECTOR *)pPoly++;
if (deadObject) {
rgbIn = &deadObjectColour;
}
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw polygon version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
// Draw untextured polygons
POLY_F3 *poly = (POLY_F3 *)drawpacket;
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
// No light source calculation
// So just set base colour
if (selFace == i)
setRGB0(poly, selPRed, selPGreen, selPBlue);
else
setRGB0(poly, rgbIn->r, rgbIn->g, rgbIn->b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
// Gouraud, Un-Textured, Self-Luminous, triangles
void drawGUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint32 tmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
// Base colour for gouraud shading computation
CVECTOR *rgb0;
CVECTOR *rgb1;
CVECTOR *rgb2;
CVECTOR *rgbTemp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x30 | Blue0 | Green0 | Red0
// 0x30 | Blue1 | Green1 | Red1
// 0x30 | Blue2 | Green2 | Red2
// 16-bits | 8-bits | 8-bits
// --------------------------
// v1 | v0
// pad | v2
rgb0 = (CVECTOR *)pPoly++;
rgb1 = (CVECTOR *)pPoly++;
rgb2 = (CVECTOR *)pPoly++;
if (deadObject) {
rgb0 = &deadObjectColour;
rgb1 = &deadObjectColour;
rgb2 = &deadObjectColour;
}
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
rgbTemp = rgb1;
rgb1 = rgb2;
rgb2 = rgbTemp;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0->r, rgb0->g, rgb0->b);
setRGB1(poly, rgb1->r, rgb1->g, rgb1->b);
setRGB2(poly, rgb2->r, rgb2->g, rgb2->b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
}
}
}
// Flat, Textured, Self-Luminous Triangles
void drawFTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
uint32 uv0, uv1, uv2;
// Base colour for shading computation
// Could easily be specified per polygon
CVECTOR *rgbIn;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// Bit 31 ----> Bit 0
//
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x24 | Blue | Green | Red
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// pad | v0
// v2 | v1
rgbIn = (CVECTOR *)pPoly++;
if (deadObject) {
rgbIn = &deadObjectColour;
}
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (uint)(tmp & 0xFFFF);
v2 = pVertex + (uint)(tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
flag = uv1;
uv1 = uv2;
uv2 = flag;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
if (_drawTxture) {
POLY_FT3 *poly = (POLY_FT3 *)drawpacket;
setPolyFT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
// No light source calculation
// So just set base colour
if (selFace == i)
setRGB0(poly, selPRed, selPGreen, selPBlue);
else
setRGB0(poly, rgbIn->r, rgbIn->g, rgbIn->b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_FT3));
} else {
// Set the RGB colours
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
if (selFace == i)
setRGB0(poly, selPRed, selPGreen, selPBlue);
else
setRGB0(poly, rgbIn->r, rgbIn->g, rgbIn->b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
}
// Gouraud, Textured, Self-Luminous Triangles
void drawGTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
uint32 uv0, uv1, uv2;
// gouraud colours
CVECTOR *rgb0;
CVECTOR *rgb1;
CVECTOR *rgb2;
CVECTOR *rgbTemp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x34 | Blue0 | Green0 | Red0
// 0x34 | Blue1 | Green1 | Red1
// 0x34 | Blue2 | Green2 | Red2
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// pad | v0
// v2 | v1
rgb0 = (CVECTOR *)pPoly++;
rgb1 = (CVECTOR *)pPoly++;
rgb2 = (CVECTOR *)pPoly++;
if (deadObject) {
rgb0 = &deadObjectColour;
rgb1 = &deadObjectColour;
rgb2 = &deadObjectColour;
}
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp & 0xFFFF);
v2 = pVertex + (tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
rgbTemp = rgb1;
rgb1 = rgb2;
rgb2 = rgbTemp;
flag = uv1;
uv1 = uv2;
uv2 = flag;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
if (_drawTxture) {
// Set the RGB colours
POLY_GT3 *poly = (POLY_GT3 *)drawpacket;
setPolyGT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
// No light source calculation
// So just set base colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0->r, rgb0->b, rgb0->b);
setRGB1(poly, rgb1->r, rgb1->b, rgb1->b);
setRGB2(poly, rgb2->r, rgb2->b, rgb2->b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_GT3));
} else {
// Set the RGB colours
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0->r, rgb0->b, rgb0->b);
setRGB1(poly, rgb1->r, rgb1->b, rgb1->b);
setRGB2(poly, rgb2->r, rgb2->b, rgb2->b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
}
}
}
}
// Flat, Un-Textured, Lit, triangles
void drawFUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
SVECTORPC sxyn0;
SVECTORPC sn0;
CVECTOR *rgbIn;
CVECTOR rgb0 = {0, 0, 0, 0};
uint32 tmp;
uint8 ctmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// 0x20 | B | G | R
// v0 | n0
// v2 | v1
rgbIn = (CVECTOR *)pPoly++;
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v2 = pVertex + (tmp >> 16);
v1 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Set the RGB colours
if (_drawLit) {
// Do the flat lighting computation
LIGHTPOLYGON(n0, rgbIn, &rgb0);
}
// Put normal lines in list before wireframe
// so should be drawn in front of wireframe triangles
if ((_drawNormals) && ((selFace == i) || (selFace > 65536))) {
// Do coord transform on the scaled normal vectors + v0
sn0.vx = (int16)(v0->vx + (-n0->vx >> _normalScale));
sn0.vy = (int16)(v0->vy + (-n0->vy >> _normalScale));
sn0.vz = (int16)(v0->vz + (-n0->vz >> _normalScale));
// z0 = RotTransPers( &sn0, &sxyn0, &p, &flag );
gte_RotTransPers_pc(&sn0, &sxyn0, &p, &flag, &z0);
// Normal 0 : scale the normal and add to vertex scrn pos
LINE_G2 *line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn0.vx;
line->y1 = sxyn0.vy;
if (selFace == i) {
// from bright red
setRGB0(line, 255, 0, 0);
// to bright white
setRGB1(line, 255, 255, 255);
} else {
// from bright blue
setRGB0(line, 0, 0, 255);
// to bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Draw a wireframe that responds to lighting
if (_drawLit) {
int32 cval;
// Compute the colour scaling and clip it
// Flat shading so give the same colour to each vertex
if (rgbIn->r != 0) {
cval = ((wfrmRed * rgb0.r) / rgbIn->r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->r0 = ctmp;
if (rgbIn->g != 0) {
cval = ((wfrmGreen * rgb0.g) / rgbIn->g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->g0 = ctmp;
if (rgbIn->b != 0) {
cval = ((wfrmBlue * rgb0.b) / rgbIn->b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->b0 = ctmp;
} else {
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
}
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw polygon version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
// Draw untextured polygons
POLY_F3 *poly = (POLY_F3 *)drawpacket;
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
if (_drawLit) {
// Flat shaded so give each vertex the same colour
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
} else {
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn->r, rgbIn->g, rgbIn->b);
}
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
// Gouraud, Un-Textured, Lit, triangles
void drawGUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTOR *n1;
SVECTOR *n2;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
SVECTOR *ntemp;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint32 tmp;
uint8 ctmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
SVECTORPC sxyn0, sxyn1, sxyn2;
SVECTORPC sn0, sn1, sn2;
// Base colour for gouraud shading computation
// Could easily be specified per polygon
CVECTOR rgbIn;
CVECTOR rgb0 = {0, 0, 0, 0};
CVECTOR rgb1 = {0, 0, 0, 0};
CVECTOR rgb2 = {0, 0, 0, 0};
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x20 | Blue | Green | Red
// 16-bits | 8-bits | 8-bits
// --------------------------
// v0 | n0
// v1 | n1
// v2 | n2
tmp = *pPoly++;
// code0 = tmp >> 24;
rgbIn.r = (uint8)(tmp & 0xFF);
rgbIn.g = (uint8)((tmp >> 8) & 0xFF);
rgbIn.b = (uint8)((tmp >> 16) & 0xFF);
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp >> 16);
n1 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v2 = pVertex + (tmp >> 16);
n2 = pNormal + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
ntemp = n1;
n1 = n2;
n2 = ntemp;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Set the RGB colours
if (_drawLit) {
// Do the full gouraud computation
// NormalColorCol3( n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2 );
LIGHTPOLYGON3(n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2);
int32 cval;
if (!_drawGouraud) {
// For flat shading mode take the average RGB for the face
// Could/should use something like AVSZ3
// but hell whats a divide by 3 between friends (~30 cycles?)
cval = ((rgb0.r + rgb1.r + rgb2.r) / 3);
if (cval > 255)
cval = 255;
rgb0.r = (uint8)cval;
cval = ((rgb0.g + rgb1.g + rgb2.g) / 3);
if (cval > 255)
cval = 255;
rgb0.g = (uint8)cval;
cval = ((rgb0.b + rgb1.b + rgb2.b) / 3);
if (cval > 255)
cval = 255;
rgb0.b = (uint8)cval;
}
} else {
rgbIn.r = unlitPoly.r;
rgbIn.g = unlitPoly.g;
rgbIn.b = unlitPoly.b;
}
// Put normal lines in list before wireframe
// so should be drawn in front of wireframe triangles
if ((_drawNormals) && ((selFace == i) || (selFace > 65536))) {
// Do coord transform on the scaled normal vectors + v0
sn0.vx = (int16)(v0->vx + (-n0->vx >> _normalScale));
sn0.vy = (int16)(v0->vy + (-n0->vy >> _normalScale));
sn0.vz = (int16)(v0->vz + (-n0->vz >> _normalScale));
sn1.vx = (int16)(v1->vx + (-n1->vx >> _normalScale));
sn1.vy = (int16)(v1->vy + (-n1->vy >> _normalScale));
sn1.vz = (int16)(v1->vz + (-n1->vz >> _normalScale));
sn2.vx = (int16)(v2->vx + (-n2->vx >> _normalScale));
sn2.vy = (int16)(v2->vy + (-n2->vy >> _normalScale));
sn2.vz = (int16)(v2->vz + (-n2->vz >> _normalScale));
// z0 = RotTransPers3( &sn0, &sn1, &sn2,
// &sxyn0, &sxyn1, &sxyn2, &p, &flag );
gte_RotTransPers3_pc(&sn0, &sn1, &sn2, &sxyn0, &sxyn1, &sxyn2, &p, &flag, &z0);
// Normal 0
LINE_G2 *line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
// Normal 1
line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn1.vx;
line->y1 = sxyn1.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
// Normal 2
line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn2.vx;
line->y1 = sxyn2.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
// Draw a wireframe that responds to lighting
if (_drawLit) {
LINE_G4 *line = (LINE_G4 *)drawpacket;
setLineG4(line);
int32 cval;
if (_drawGouraud) {
// Give each vertex a separate colour
// Compute the colour scaling and clip it
if (rgbIn.r != 0) {
cval = ((wfrmRed * rgb0.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r0 = ctmp;
line->r3 = ctmp;
cval = ((wfrmRed * rgb1.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r1 = ctmp;
cval = ((wfrmRed * rgb2.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r2 = ctmp;
} else {
line->r0 = 0;
line->r3 = 0;
line->r1 = 0;
line->r2 = 0;
}
if (rgbIn.g != 0) {
cval = ((wfrmGreen * rgb0.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g0 = ctmp;
line->g3 = ctmp;
cval = ((wfrmGreen * rgb1.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g1 = ctmp;
cval = ((wfrmGreen * rgb2.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g2 = ctmp;
} else {
line->g0 = 0;
line->g3 = 0;
line->g1 = 0;
line->g2 = 0;
}
if (rgbIn.b != 0) {
cval = ((wfrmBlue * rgb0.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b0 = ctmp;
line->b3 = ctmp;
cval = ((wfrmBlue * rgb1.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b1 = ctmp;
cval = ((wfrmBlue * rgb2.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b2 = ctmp;
} else {
line->b0 = 0;
line->b3 = 0;
line->b1 = 0;
line->b2 = 0;
}
} else {
// Compute the colour scaling and clip it
// Flat shading so give the same colour to each vertex
if (rgbIn.r != 0) {
cval = ((wfrmRed * rgb0.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->r0 = ctmp;
line->r1 = ctmp;
line->r2 = ctmp;
line->r3 = ctmp;
if (rgbIn.g != 0) {
cval = ((wfrmGreen * rgb0.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->g0 = ctmp;
line->g1 = ctmp;
line->g2 = ctmp;
line->g3 = ctmp;
if (rgbIn.b != 0) {
cval = ((wfrmBlue * rgb0.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->b0 = ctmp;
line->b1 = ctmp;
line->b2 = ctmp;
line->b3 = ctmp;
}
if (selFace == i) {
setRGB0(line, selWRed, selWGreen, selWBlue);
setRGB1(line, selWRed, selWGreen, selWBlue);
setRGB2(line, selWRed, selWGreen, selWBlue);
setRGB3(line, selWRed, selWGreen, selWBlue);
}
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G4));
} else {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
// Set the RGB colours
if (_drawLit) {
if (_drawGouraud) {
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
setRGB1(poly, rgb1.r, rgb1.g, rgb1.b);
setRGB2(poly, rgb2.r, rgb2.g, rgb2.b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
} else {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Flat shaded so give each vertex the same colour
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
} else {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn.r, rgbIn.g, rgbIn.b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
}
// Flat, Textured, Lit Triangles
void drawFTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
uint8 ctmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
SVECTORPC sxyn0;
SVECTORPC sn0;
uint32 uv0, uv1, uv2;
// Base colour for shading computation
// Could easily be specified per polygon
CVECTOR rgbIn = {128, 128, 128, 0};
CVECTOR rgb0 = {0, 0, 0, 0};
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// Bit 31 ----> Bit 0
//
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// v0 | n0
// v2 | v1
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp & 0xFFFF);
v2 = pVertex + (tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
flag = uv1;
uv1 = uv2;
uv2 = flag;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Set the RGB colours
if (_drawLit) {
// Do the full gouraud computation
// NormalColorCol( n0, &rgbIn, &rgb0 );
LIGHTPOLYGON(n0, &rgbIn, &rgb0);
}
// Put normal lines in list before wireframe
// so should be drawn in front of wireframe triangles
if ((_drawNormals) && ((selFace == i) || (selFace > 65536))) {
// Do coord transform on the scaled normal vectors + v0
sn0.vx = (int16)(v0->vx + (-n0->vx >> _normalScale));
sn0.vy = (int16)(v0->vy + (-n0->vy >> _normalScale));
sn0.vz = (int16)(v0->vz + (-n0->vz >> _normalScale));
// z0 = RotTransPers( &sn0, &sxyn0, &p, &flag );
gte_RotTransPers_pc(&sn0, &sxyn0, &p, &flag, &z0);
// Normal 0
LINE_G2 *line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn0.vx;
line->y1 = sxyn0.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
// Draw a wireframe that responds to lighting
if (_drawLit) {
int32 cval;
LINE_G4 *line = (LINE_G4 *)drawpacket;
setLineG4(line);
// Compute the colour scaling and clip it
// Flat shading so give the same colour to each vertex
cval = ((wfrmRed * rgb0.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r0 = ctmp;
line->r1 = ctmp;
line->r2 = ctmp;
line->r3 = ctmp;
cval = ((wfrmGreen * rgb0.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g0 = ctmp;
line->g1 = ctmp;
line->g2 = ctmp;
line->g3 = ctmp;
cval = ((wfrmBlue * rgb0.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b0 = ctmp;
line->b1 = ctmp;
line->b2 = ctmp;
line->b3 = ctmp;
if (selFace == i) {
setRGB0(line, selWRed, selWGreen, selWBlue);
setRGB1(line, selWRed, selWGreen, selWBlue);
setRGB2(line, selWRed, selWGreen, selWBlue);
setRGB3(line, selWRed, selWGreen, selWBlue);
}
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G4));
} else {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
if (_drawTxture) {
POLY_FT3 *poly = (POLY_FT3 *)drawpacket;
setPolyFT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
if (_drawLit) {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
} else {
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn.r, rgbIn.g, rgbIn.b);
}
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_FT3));
} else {
// Set the RGB colours
if (_drawLit) {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Flat shaded so give each vertex the same colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
} else {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn.r, rgbIn.g, rgbIn.b);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
}
}
// Gouraud, Textured, Lit Triangles
void drawGTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTOR *n1;
SVECTOR *n2;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
SVECTOR *ntemp;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
uint8 ctmp;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
SVECTORPC sxyn0, sxyn1, sxyn2;
SVECTORPC sn0, sn1, sn2;
uint32 uv0, uv1, uv2;
// Base colour for gouraud shading computation
// Could easily be specified per polygon
CVECTOR rgbIn = {128, 128, 128, 0};
CVECTOR rgb0 = {0, 0, 0, 0};
CVECTOR rgb1 = {0, 0, 0, 0};
CVECTOR rgb2 = {0, 0, 0, 0};
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Structure is :
// v0, u0
// v1, u1
// v2, u2
// v0 | n0
// v1 | n1
// v2 | n2
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp >> 16);
n1 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v2 = pVertex + (tmp >> 16);
n2 = pNormal + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// Do we want to do back face removal ?
if (_removeBackface) {
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
if (_useWindingOrder) {
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facings polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
if (_drawBface) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
ntemp = n1;
n1 = n2;
n2 = ntemp;
flag = uv1;
uv1 = uv2;
uv2 = flag;
} else {
// Skip this polygon
continue;
}
} else if (flag == 0)
continue; // ignore zero-area polygons
}
// TODO
// dot product of viewing direction and polygon normal
// will require generation of polygon normal from vertex normals
// and transformation of the normal to world space
}
// Set the RGB colours
if (_drawLit) {
// Do the full gouraud computation
// NormalColorCol3( n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2 );
LIGHTPOLYGON3(n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2);
int32 cval;
if (!_drawGouraud) {
// For flat shading mode take the average RGB for the face
// Could/should use something like AVSZ3
// but hell whats a divide by 3 between friends (~30 cycles?)
cval = ((rgb0.r + rgb1.r + rgb2.r) / 3);
if (cval > 255)
cval = 255;
rgb0.r = (uint8)cval;
cval = ((rgb0.g + rgb1.g + rgb2.g) / 3);
if (cval > 255)
cval = 255;
rgb0.g = (uint8)cval;
cval = ((rgb0.b + rgb1.b + rgb2.b) / 3);
if (cval > 255)
cval = 255;
rgb0.b = (uint8)cval;
}
}
// Put normal lines in list before wireframe
// so should be drawn in front of wireframe triangles
if ((_drawNormals) && ((selFace == i) || (selFace > 65536))) {
// Do coord transform on the scaled normal vectors + v0
sn0.vx = (int16)(v0->vx + (-n0->vx >> _normalScale));
sn0.vy = (int16)(v0->vy + (-n0->vy >> _normalScale));
sn0.vz = (int16)(v0->vz + (-n0->vz >> _normalScale));
sn1.vx = (int16)(v1->vx + (-n1->vx >> _normalScale));
sn1.vy = (int16)(v1->vy + (-n1->vy >> _normalScale));
sn1.vz = (int16)(v1->vz + (-n1->vz >> _normalScale));
sn2.vx = (int16)(v2->vx + (-n2->vx >> _normalScale));
sn2.vy = (int16)(v2->vy + (-n2->vy >> _normalScale));
sn2.vz = (int16)(v2->vz + (-n2->vz >> _normalScale));
// z0 = RotTransPers3( &sn0, &sn1, &sn2,
// &sxyn0, &sxyn1, &sxyn2, &p, &flag );
gte_RotTransPers3_pc(&sn0, &sn1, &sn2, &sxyn0, &sxyn1, &sxyn2, &p, &flag, &z0);
// Normal 0
LINE_G2 *line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn0.vx;
line->y1 = sxyn0.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
// Normal 1
line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn1.vx;
line->y1 = sxyn1.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
// Normal 2
line = (LINE_G2 *)drawpacket;
setLineG2(line);
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxyn2.vx;
line->y1 = sxyn2.vy;
if (selFace == i) {
// Bright red
setRGB0(line, 255, 0, 0);
// Bright white
setRGB1(line, 255, 255, 255);
} else {
// Bright blue
setRGB0(line, 0, 0, 255);
// Bright white
setRGB1(line, 255, 255, 255);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G2));
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
// Draw a wireframe that responds to lighting
if (_drawLit) {
LINE_G4 *line = (LINE_G4 *)drawpacket;
setLineG4(line);
int32 cval;
if (_drawGouraud) {
// Give each vertex a separate colour
// Compute the colour scaling and clip it
if (rgbIn.r != 0) {
cval = ((wfrmRed * rgb0.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r0 = ctmp;
line->r3 = ctmp;
cval = ((wfrmRed * rgb1.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r1 = ctmp;
cval = ((wfrmRed * rgb2.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->r2 = ctmp;
} else {
line->r0 = 0;
line->r3 = 0;
line->r1 = 0;
line->r2 = 0;
}
if (rgbIn.g != 0) {
cval = ((wfrmGreen * rgb0.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g0 = ctmp;
line->g3 = ctmp;
cval = ((wfrmGreen * rgb1.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g1 = ctmp;
cval = ((wfrmGreen * rgb2.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->g2 = ctmp;
} else {
line->g0 = 0;
line->g3 = 0;
line->g1 = 0;
line->g2 = 0;
}
if (rgbIn.b != 0) {
cval = ((wfrmBlue * rgb0.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b0 = ctmp;
line->b3 = ctmp;
cval = ((wfrmBlue * rgb1.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b1 = ctmp;
cval = ((wfrmBlue * rgb2.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
line->b2 = ctmp;
} else {
line->b0 = 0;
line->b3 = 0;
line->b1 = 0;
line->b2 = 0;
}
} else {
// Compute the colour scaling and clip it
// Flat shading so give the same colour to each vertex
if (rgbIn.r != 0) {
cval = ((wfrmRed * rgb0.r) / rgbIn.r);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->r0 = ctmp;
line->r1 = ctmp;
line->r2 = ctmp;
line->r3 = ctmp;
if (rgbIn.g != 0) {
cval = ((wfrmGreen * rgb0.g) / rgbIn.g);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->g0 = ctmp;
line->g1 = ctmp;
line->g2 = ctmp;
line->g3 = ctmp;
if (rgbIn.b != 0) {
cval = ((wfrmBlue * rgb0.b) / rgbIn.b);
if (cval > 255)
cval = 255;
ctmp = (uint8)cval;
} else
ctmp = 0;
line->b0 = ctmp;
line->b1 = ctmp;
line->b2 = ctmp;
line->b3 = ctmp;
}
if (selFace == i) {
setRGB0(line, selWRed, selWGreen, selWBlue);
setRGB1(line, selWRed, selWGreen, selWBlue);
setRGB2(line, selWRed, selWGreen, selWBlue);
setRGB3(line, selWRed, selWGreen, selWBlue);
}
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_G4));
} else {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
}
// Draw textured version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
if (_drawTxture) {
// Set the RGB colours
if ((_drawLit) && (_drawGouraud)) {
POLY_GT3 *poly = (POLY_GT3 *)drawpacket;
setPolyGT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
setRGB1(poly, rgb1.r, rgb1.g, rgb1.b);
setRGB2(poly, rgb2.r, rgb2.g, rgb2.b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_GT3));
} else {
POLY_FT3 *poly = (POLY_FT3 *)drawpacket;
setPolyFT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
if (_drawLit) {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
} else {
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn.r, rgbIn.g, rgbIn.b);
}
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_FT3));
}
} else {
// Set the RGB colours
if (_drawLit) {
if (_drawGouraud) {
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
setRGB1(poly, selPRed, selPGreen, selPBlue);
setRGB2(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
setRGB1(poly, rgb1.r, rgb1.g, rgb1.b);
setRGB2(poly, rgb2.r, rgb2.g, rgb2.b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
} else {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Flat shaded so give each vertex the same colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
} else {
POLY_F3 *poly = (POLY_F3 *)drawpacket;
// Draw untextured polygons
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// No light source calculation
// So just set base colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
} else {
setRGB0(poly, unlitPoly.r, unlitPoly.g, unlitPoly.b);
poly->code = unlitPoly.cd;
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
}
}
}
// Simple flat untextured triangles
// draw backfacing triangles as well
// the colour is set by a global variable
void drawTRI3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
// uint32 num = min( n, 10 ); // do a maximum of 10 polygons
uint32 num = n;
int32 p, flag;
uint32 i;
uint32 *pPoly;
int32 z0, z1, z2;
SVECTORPC sxy0, sxy1, sxy2, stemp;
uint32 tmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < num; i++) {
// Each polygon is 2 32-bit WORDS
// Bit 31 ----> Bit 0
//
// 16-bits | 16-bits
// --------------------------
// v1 | v0
// pad | v2
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
gte_RotTransPers_pc(v0, &sxy0, &p, &flag, &z0);
z0 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v1, &sxy1, &p, &flag, &z1);
z1 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
gte_RotTransPers_pc(v2, &sxy2, &p, &flag, &z2);
z2 <<= 2; // multiply by 4 to cope with AverageZ later on dividing by 4
// test the return value of flag
if (flag & 0x80000000)
continue;
// Give the GTE some time to recover
int32 avgz;
gte_AverageZ3_pc(z0, z1, z2, &avgz);
// See what winding order this polygon is ?
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facing polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
}
// Put wireframe triangles in list before textured ones
// so should be in front of textured ones
if ((_drawWfrm) || (selFace == i)) {
LINE_F4 *line = (LINE_F4 *)drawpacket;
setLineF4(line);
// set XY's in the GPU packet 0-1-2-3
line->x0 = sxy0.vx;
line->y0 = sxy0.vy;
line->x1 = sxy1.vx;
line->y1 = sxy1.vy;
line->x2 = sxy2.vx;
line->y2 = sxy2.vy;
line->x3 = sxy0.vx;
line->y3 = sxy0.vy;
if (selFace == i)
setRGB0(line, selWRed, selWGreen, selWBlue);
else
setRGB0(line, (uint8)wfrmRed, (uint8)wfrmGreen, (uint8)wfrmBlue);
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(LINE_F4));
}
// Draw polygon version behind the wireframe
if ((_drawPolys) || (selFace == i)) {
// Draw untextured polygons
TPOLY_F3 *poly = (TPOLY_F3 *)drawpacket;
setTPolyF3(poly);
setTABRMode(poly, 2); // 2 = back - front
setTSemiTrans(poly, 1); // 1 = enable semi-transparency
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
// No light source calculation
// So just set base colour
if (selFace == i) {
setRGB0(poly, selPRed, selPGreen, selPBlue);
poly->code = selPAlpha;
} else {
setRGB0(poly, unlitPoly.r, unlitPoly.g, unlitPoly.b);
poly->code = unlitPoly.cd;
}
// Put it into the global ot at the correct place
myAddPrimClip(avgz, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(TPOLY_F3));
}
}
}
// Flat, Un-Textured, Self-Luminous, triangles
void fastDrawFUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
CVECTOR *rgbIn;
uint32 tmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// 0x20 | B | G | R
// v1 | v0
// pad | v2
rgbIn = (CVECTOR *)pPoly++;
if (deadObject) {
rgbIn = &deadObjectColour;
}
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
// Draw untextured polygons
POLY_F3 *poly = (POLY_F3 *)drawpacket;
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
// No light source calculation
// So just set base colour
setRGB0(poly, rgbIn->r, rgbIn->g, rgbIn->b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
// Fast: no options, Gouraud, Un-Textured, Self-Luminous, triangles
void fastDrawGUS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint32 tmp;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
// Base colour for gouraud shading computation
// Could easily be specified per polygon
CVECTOR *rgb0;
CVECTOR *rgb1;
CVECTOR *rgb2;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x30 | Blue0 | Green0 | Red0
// 0x30 | Blue1 | Green1 | Red1
// 0x30 | Blue2 | Green2 | Red2
// 16-bits | 8-bits | 8-bits
// --------------------------
// v1 | v0
// pad | v2
rgb0 = (CVECTOR *)pPoly++;
rgb1 = (CVECTOR *)pPoly++;
rgb2 = (CVECTOR *)pPoly++;
if (deadObject) {
rgb0 = &deadObjectColour;
rgb1 = &deadObjectColour;
rgb2 = &deadObjectColour;
}
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setRGB0(poly, rgb0->r, rgb0->g, rgb0->b);
setRGB1(poly, rgb1->r, rgb1->g, rgb1->b);
setRGB2(poly, rgb2->r, rgb2->g, rgb2->b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
}
}
// Fast: no options, Flat, Textured, Self-Luminous Triangles
void fastDrawFTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
uint32 uv0, uv1, uv2;
// Base colour for shading computation
// Could easily be specified per polygon
CVECTOR *rgbIn;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// Bit 31 ----> Bit 0
//
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x24 | Blue | Green | Red
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// pad | v0
// v2 | v1
rgbIn = (CVECTOR *)pPoly++;
if (deadObject == 1) {
rgbIn = &deadObjectColour;
}
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (uint)(tmp & 0xFFFF);
v2 = pVertex + (uint)(tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
POLY_FT3 *poly = (POLY_FT3 *)drawpacket;
setPolyFT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
// No light source calculation so just set base colour
setRGB0(poly, rgbIn->r, rgbIn->b, rgbIn->b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_FT3));
}
}
// Fast: no options, Gouraud, Textured, Self-Luminous Triangles
void fastDrawGTS3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
uint32 uv0, uv1, uv2;
// gouraud colours
CVECTOR *rgb0;
CVECTOR *rgb1;
CVECTOR *rgb2;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x34 | Blue0 | Green0 | Red0
// 0x34 | Blue1 | Green1 | Red1
// 0x34 | Blue2 | Green2 | Red2
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// pad | v0
// v2 | v1
rgb0 = (CVECTOR *)pPoly++;
rgb1 = (CVECTOR *)pPoly++;
rgb2 = (CVECTOR *)pPoly++;
if (deadObject) {
rgb0 = &deadObjectColour;
rgb1 = &deadObjectColour;
rgb2 = &deadObjectColour;
}
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp & 0xFFFF);
v2 = pVertex + (tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
// Set the RGB colours
POLY_GT3 *poly = (POLY_GT3 *)drawpacket;
setPolyGT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
setRGB0(poly, rgb0->r, rgb0->b, rgb0->b);
setRGB1(poly, rgb1->r, rgb1->b, rgb1->b);
setRGB2(poly, rgb2->r, rgb2->b, rgb2->b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_GT3));
}
}
// Fast: no options, Flat, Un-Textured, Lit, triangles
void fastDrawFUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
CVECTOR *rgbIn;
CVECTOR rgb0;
uint32 tmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// 0x20 | B | G | R
// v0 | n0
// v2 | v1
rgbIn = (CVECTOR *)pPoly++;
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v2 = pVertex + (tmp >> 16);
v1 = pVertex + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
// Do the flat lighting computation
LIGHTPOLYGON(n0, rgbIn, &rgb0);
// Draw untextured polygons
POLY_F3 *poly = (POLY_F3 *)drawpacket;
setPolyF3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
// Flat shaded so give each vertex the same colour
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_F3));
}
}
// Fast: no options, Gouraud, Un-Textured, Lit, triangles
void fastDrawGUL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTOR *n1;
SVECTOR *n2;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint32 tmp;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
// Base colour for gouraud shading computation
// Could easily be specified per polygon
CVECTOR rgbIn = {128, 128, 128, 0};
CVECTOR rgb0, rgb1, rgb2;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// 8-bits | 8-bits | 8-bits | 8-bits
// 0x20 | Blue | Green | Red
// 16-bits | 8-bits | 8-bits
// --------------------------
// v0 | n0
// v1 | n1
// v2 | n2
tmp = *pPoly++;
// code0 = tmp >> 24;
rgbIn.r = (uint8)(tmp & 0xFF);
rgbIn.g = (uint8)((tmp >> 8) & 0xFF);
rgbIn.b = (uint8)((tmp >> 16) & 0xFF);
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp >> 16);
n1 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v2 = pVertex + (tmp >> 16);
n2 = pNormal + (tmp & 0xFFFF);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
// Do the full gouraud computation
// NormalColorCol3( n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2 );
LIGHTPOLYGON3(n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2);
POLY_G3 *poly = (POLY_G3 *)drawpacket;
// Draw untextured polygons
setPolyG3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
setRGB1(poly, rgb1.r, rgb1.g, rgb1.b);
setRGB2(poly, rgb2.r, rgb2.g, rgb2.b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_G3));
}
}
//------------------------------------------------------------------------
// Fast: no options, Flat, Textured, Lit Triangles
void fastDrawFTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint16 uu0, uu1, uu2;
uint16 vv0, vv1, vv2;
uint32 tmp;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2;
uint32 uv0, uv1, uv2;
// Base colour for shading computation
// Could easily be specified per polygon
CVECTOR rgbIn = {128, 128, 128, 0};
CVECTOR rgb0;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// Bit 31 ----> Bit 0
//
// 16-bits | 16-bits
// --------------------------
// v0 | u0
// v1 | u1
// v2 | u2
// --------------------------
// v0 | n0
// v2 | v1
uv0 = *pPoly++;
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *pPoly++;
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *pPoly++;
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
tmp = *pPoly++;
v0 = pVertex + (tmp >> 16);
n0 = pNormal + (tmp & 0xFFFF);
tmp = *pPoly++;
v1 = pVertex + (tmp & 0xFFFF);
v2 = pVertex + (tmp >> 16);
// Now do RotTransPers3 on the vectors
// z0 = RotTransPers3( v0, v1, v2, &sxy0, &sxy1, &sxy2, &p, &flag );
// gte_RotTransPers3_pc(v0,v1,v2,&sxy0,&sxy1,&sxy2,&p,&flag,&z0);
// test the return value of flag
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
if (v0->pad != 0)
continue;
if (v1->pad != 0)
continue;
if (v2->pad != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
if (flag <= 0)
continue;
// Do the full gouraud computation
// NormalColorCol( n0, &rgbIn, &rgb0 );
LIGHTPOLYGON(n0, &rgbIn, &rgb0);
POLY_FT3 *poly = (POLY_FT3 *)drawpacket;
setPolyFT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_FT3));
}
}
// Fast : no options : Gouraud, Textured, Lit Triangles
void fastDrawGTL3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex, SVECTOR *pNormal) {
SVECTOR *n0;
SVECTOR *n1;
SVECTOR *n2;
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
uint16 uu0;
uint16 uu1;
uint16 uu2;
uint16 vv0;
uint16 vv1;
uint16 vv2;
int32 flag;
uint32 i;
int32 z0;
uint32 uv0;
uint32 uv1;
uint32 uv2;
uint32 vt0;
uint32 vt1;
uint32 vt2;
SVECTORPC sxy0;
SVECTORPC sxy1;
SVECTORPC sxy2;
int32 pad0;
int32 pad1;
int32 pad2;
// Base colour for gouraud shading computation
// Could easily be specified per polygon
CVECTOR rgbIn = {128, 128, 128, 0};
CVECTOR rgb0, rgb1, rgb2;
POLY_GT3 *poly;
uint32 *pPoly;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Structure is :
// v0, u0
// v1, u1
// v2, u2
// v0 | n0
// v1 | n1
// v2 | n2
uv0 = *(pPoly++);
vv0 = (uint16)((uv0 >> 16) & 0xFFFF);
uu0 = (uint16)(uv0 & 0xFFFF);
uv1 = *(pPoly++);
vv1 = (uint16)((uv1 >> 16) & 0xFFFF);
uu1 = (uint16)(uv1 & 0xFFFF);
uv2 = *(pPoly++);
vv2 = (uint16)((uv2 >> 16) & 0xFFFF);
uu2 = (uint16)(uv2 & 0xFFFF);
vt0 = *(pPoly++);
v0 = (pVertex + (vt0 >> 16));
n0 = (pNormal + (vt0 & 0xFFFF));
vt1 = *(pPoly++);
v1 = (pVertex + (vt1 >> 16));
n1 = (pNormal + (vt1 & 0xFFFF));
vt2 = *(pPoly++);
v2 = (pVertex + (vt2 >> 16));
n2 = (pNormal + (vt2 & 0xFFFF));
// The vertices have been pre-transformed into screen space and stored in the vertex pool
// The flag value is set to 0x8000 or 0 in the pad structure
pad0 = v0->pad;
pad1 = v1->pad;
pad2 = v2->pad;
flag = pad0 | pad1 | pad2;
if (flag != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Give the GTE some time to recover
// Ignore polygons which are too small
if (flag <= 0)
continue;
// Do the full gouraud computation
LIGHTPOLYGON3(n0, n1, n2, &rgbIn, &rgb0, &rgb1, &rgb2);
// Try to overlap this with the LIGHTPOLYGON3 !
poly = (POLY_GT3 *)drawpacket;
setPolyGT3(poly);
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
setUV3(poly, uu0, vv0, uu1, vv1, uu2, vv2);
setRGB0(poly, rgb0.r, rgb0.g, rgb0.b);
setRGB1(poly, rgb1.r, rgb1.g, rgb1.b);
setRGB2(poly, rgb2.r, rgb2.g, rgb2.b);
// Put it into the global ot at the correct place
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(POLY_GT3));
}
}
// For mucking about with lighting
// Draw a solid bounding box around the actor (and so obscuring him)
// but then have the box respond to the lights e.g. give it normals
// and do flat & goraud shading
// Assume the GTE lighting registers to be pre-prepared
void drawSolidBboxPC(SVECTOR *scrn, CVECTOR *rgbIn) {
// 6 POLY_F4's i.e. 6 faces
// The 8 verticies are:
// 0 { xmin, ymin, zmin },
// 1 { xmin, ymin, zmax },
// 2 { xmax, ymin, zmin },
// 3 { xmax, ymin, zmax },
// 4 { xmax, ymax, zmin },
// 5 { xmax, ymax, zmax },
// 6 { xmin, ymax, zmin },
// 7 { xmin, ymax, zmax }
// The 6 faces are the following vertex links:
// ymin face : 0->1->3->2
// xmax face : 2->3->5->4
// zmin face : 0->2->4->6
// xmin face : 0->6->7->1
// zmax face : 1->7->5->3
// ymax face : 6->4->5->7
// The 6 face normals are (normal points into front side of face on PSX)
// ymin face : 0,+4096,0 +ve y
// xmax face : -4096,0,0 -ve x
// zmin face : 0,0,+4096 +ve z
// xmin face : +4096,0,0 +ve x
// zmax face : 0,0,-4096 -ve z
// ymax face : 0,-4096,0 -ve y
int32 z0, flag;
SVECTOR normal;
CVECTOR rgb;
POLY_F4 *face = nullptr;
gte_NormalClip_pc(&(scrn[0]), &(scrn[1]), &(scrn[2]), &flag);
if (flag > 0) {
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// ymin face normal : 0,+4096,0 +ve y
normal.vx = 0;
normal.vy = 4096;
normal.vz = 0;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
// ymin face : 0->1->3->2 : note PSX is 0-1-3-2 for a quad
setXY4(face, scrn[0].vx, scrn[0].vy, scrn[1].vx, scrn[1].vy, scrn[2].vx, scrn[2].vy, scrn[3].vx, scrn[3].vy);
z0 = (scrn[0].vz + scrn[1].vz + scrn[2].vz + scrn[3].vz) / 4;
z0 = myAddPrimClip(z0, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
gte_NormalClip_pc(&(scrn[2]), &(scrn[3]), &(scrn[4]), &flag);
if (flag > 0) {
// xmax face : 2->3->5->4 : note PSX is 0-1-3-2 for a quad
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// xmax face : -4096,0,0 -ve x
normal.vx = -4096;
normal.vy = 0;
normal.vz = 0;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
setXY4(face, scrn[2].vx, scrn[2].vy, scrn[3].vx, scrn[3].vy, scrn[4].vx, scrn[4].vy, scrn[5].vx, scrn[5].vy);
z0 = (scrn[2].vz + scrn[3].vz + scrn[4].vz + scrn[5].vz) / 4;
z0 = myAddPrimClip(z0, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
gte_NormalClip_pc(&(scrn[0]), &(scrn[2]), &(scrn[4]), &flag);
if (flag > 0) {
// zmin face : 0->2->4->6 : note PSX is 0-1-3-2 for a quad
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// zmin face : 0,0,+4096 +ve z
normal.vx = 0;
normal.vy = 0;
normal.vz = 4096;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
setXY4(face, scrn[0].vx, scrn[0].vy, scrn[2].vx, scrn[2].vy, scrn[6].vx, scrn[6].vy, scrn[4].vx, scrn[4].vy);
z0 = (scrn[0].vz + scrn[2].vz + scrn[4].vz + scrn[6].vz) / 4;
z0 = myAddPrimClip(z0, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
gte_NormalClip_pc(&(scrn[0]), &(scrn[6]), &(scrn[7]), &flag);
if (flag > 0) {
// xmin face : 0->6->7->1 : note PSX is 0-1-3-2 for a quad
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// xmin face : +4096,0,0 +ve x
normal.vx = 0;
normal.vy = 0;
normal.vz = 4096;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
setXY4(face, scrn[0].vx, scrn[0].vy, scrn[6].vx, scrn[6].vy, scrn[1].vx, scrn[1].vy, scrn[7].vx, scrn[7].vy);
z0 = myAddPrimClip(scrn[7].vz, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
gte_NormalClip_pc(&(scrn[1]), &(scrn[7]), &(scrn[5]), &flag);
if (flag > 0) {
// zmax face : 1->7->5->3 : note PSX is 0-1-3-2 for a quad
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// zmax face : 0,0,-4096 -ve z
normal.vx = 0;
normal.vy = 0;
normal.vz = -4096;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
setXY4(face, scrn[1].vx, scrn[1].vy, scrn[7].vx, scrn[7].vy, scrn[3].vx, scrn[3].vy, scrn[5].vx, scrn[5].vy);
z0 = (scrn[1].vz + scrn[3].vz + scrn[5].vz + scrn[7].vz) / 4;
z0 = myAddPrimClip(z0, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
gte_NormalClip_pc(&(scrn[6]), &(scrn[4]), &(scrn[5]), &flag);
if (flag > 0) {
// ymax face : 6->4->5->7 : note PSX is 0-1-3-2 for a quad
face = (POLY_F4 *)drawpacket;
setPolyF4(face);
// ymax face : 0,-4096,0 -ve y
normal.vx = 0;
normal.vy = -4096;
normal.vz = 0;
if (_drawLit) {
LIGHTPOLYGON(&normal, rgbIn, &rgb);
setRGB0(face, rgb.r, rgb.g, rgb.b);
} else {
setRGB0(face, rgbIn->r, rgbIn->g, rgbIn->b);
}
setXY4(face, scrn[6].vx, scrn[6].vy, scrn[4].vx, scrn[4].vy, scrn[7].vx, scrn[7].vy, scrn[5].vx, scrn[5].vy);
z0 = (scrn[4].vz + scrn[5].vz + scrn[6].vz + scrn[7].vz) / 4;
z0 = myAddPrimClip(z0, drawpacket);
myAddPacket(sizeof(POLY_F4));
}
}
// Simple flat untextured triangles
// draw backfacing triangles as well
// the colour is set by a global variable
void fastDrawTRI3PC(uint32 *polyStart, const uint32 n, SVECTORPC *pVertex) {
SVECTORPC *v0;
SVECTORPC *v1;
SVECTORPC *v2;
int32 flag;
uint32 i;
uint32 *pPoly;
int32 z0;
SVECTORPC sxy0, sxy1, sxy2, stemp;
uint32 tmp;
pPoly = polyStart;
// Loop over each polygon
for (i = 0; i < n; i++) {
// Each polygon is 2 32-bit WORDS
// Bit 31 ----> Bit 0
//
// 16-bits | 16-bits
// --------------------------
// v1 | v0
// pad | v2
tmp = *pPoly++;
v0 = pVertex + (tmp & 0xFFFF);
v1 = pVertex + (tmp >> 16);
tmp = *pPoly++;
v2 = pVertex + (tmp & 0xFFFF);
flag = (v0->pad) | (v1->pad) | (v2->pad);
if (flag != 0)
continue;
// use winding order of the polygons
// e.g. NormalClip which is cross product of screen vectors
sxy0.vx = v0->vx;
sxy0.vy = v0->vy;
sxy1.vx = v1->vx;
sxy1.vy = v1->vy;
sxy2.vx = v2->vx;
sxy2.vy = v2->vy;
// See what winding order this polygon is ?
gte_NormalClip_pc(&sxy0, &sxy1, &sxy2, &flag);
// Drawing back facing polys requires making them have
// clockwise winding order as by definition they have
// anti-clockwise winding order
if (flag < 0) {
stemp = sxy1;
sxy1 = sxy2;
sxy2 = stemp;
}
// Give the GTE some time to recover
gte_AverageZ3_pc(v0->vz, v1->vz, v2->vz, &z0);
// Draw untextured polygons
TPOLY_F3 *poly = (TPOLY_F3 *)drawpacket;
setTPolyF3(poly);
setTABRMode(poly, 2); // 2 = back - front
setTSemiTrans(poly, 1); // 1 = enable semi-transparency
// set XY's in the GPU packet 0-1-2
poly->x0 = sxy0.vx;
poly->y0 = sxy0.vy;
poly->x1 = sxy1.vx;
poly->y1 = sxy1.vy;
poly->x2 = sxy2.vx;
poly->y2 = sxy2.vy;
// Set the RGB colours
// No light source calculation
// So just set base colour
setRGB0(poly, unlitPoly.r, unlitPoly.g, unlitPoly.b);
poly->code = unlitPoly.cd;
myAddPrimClip(z0, drawpacket);
// advance the global packet pointer by correct amount
myAddPacket(sizeof(TPOLY_F3));
}
}
} // End of namespace ICB