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