mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
This symbol was undefined which meant that it defaulted to being equal to zero. Since this was the value tested for in all cases, then all cases of this macro test were enabled which was not very clear. Looking at the code, it appears this is intended to guard a debugging mode enabling slower, but more readable rendering code and other graphics information. This should probably be migrated to a boolean flag of the engine (since debug already exists) or a ScummVM debug level / flag. This changes also removes a large number of GCC warnings regarding use of undefined macro symbols.
3736 lines
100 KiB
C++
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->b, 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
|