2016-03-21 04:10:14 +00:00
|
|
|
#include "Supermodel.h"
|
|
|
|
#include "PolyHeader.h"
|
|
|
|
|
|
|
|
namespace New3D {
|
|
|
|
|
|
|
|
PolyHeader::PolyHeader()
|
|
|
|
{
|
2021-11-22 17:15:06 +00:00
|
|
|
header = nullptr;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PolyHeader::PolyHeader(UINT32* h)
|
|
|
|
{
|
|
|
|
header = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PolyHeader::operator = (const UINT32* h)
|
|
|
|
{
|
|
|
|
header = (UINT32*)h;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT32* PolyHeader::StartOfData()
|
|
|
|
{
|
|
|
|
return header + 7; // 7 is size of header in bytes, data immediately follows
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::NextPoly()
|
|
|
|
{
|
|
|
|
if (LastPoly()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
header += 7 + (NumVerts() - NumSharedVerts()) * 4;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::NumPolysTotal()
|
|
|
|
{
|
|
|
|
UINT32* start = header; // save start address
|
|
|
|
int count = 1;
|
|
|
|
|
|
|
|
while (NextPoly()) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
header = start; // restore start address
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::NumTrianglesTotal()
|
|
|
|
{
|
|
|
|
if (header[6] == 0) {
|
|
|
|
return 0; // no poly data
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT32* start = header; // save start address
|
|
|
|
|
|
|
|
int count = (NumVerts() == 4) ? 2 : 1;
|
|
|
|
|
|
|
|
while (NextPoly()) {
|
|
|
|
count += (NumVerts() == 4) ? 2 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
header = start; // restore start address
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// header 0
|
|
|
|
//
|
|
|
|
|
2016-05-06 15:00:12 +00:00
|
|
|
bool PolyHeader::SpecularEnabled()
|
2016-03-21 04:10:14 +00:00
|
|
|
{
|
2016-05-06 15:00:12 +00:00
|
|
|
return (header[0] & 0x80) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
float PolyHeader::SpecularValue()
|
|
|
|
{
|
2016-05-15 16:24:49 +00:00
|
|
|
return (header[0] >> 26) / 63.f; // 63 matches decompiled lib value
|
2016-05-06 15:00:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::Clockwise()
|
|
|
|
{
|
|
|
|
return (header[0] & 0x2000000) > 0;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::PolyNumber()
|
|
|
|
{
|
|
|
|
return (header[0] & 0x000FFFC00) >> 10; // not all programs pass this, instead they are set to 0
|
|
|
|
}
|
|
|
|
|
2017-04-15 19:00:46 +00:00
|
|
|
bool PolyHeader::Discard()
|
2016-03-21 04:10:14 +00:00
|
|
|
{
|
2016-05-13 08:39:48 +00:00
|
|
|
if ((header[0] & 0x100) && (header[0] & 0x200)) {
|
2016-03-21 04:10:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-15 19:00:46 +00:00
|
|
|
bool PolyHeader::Discard1()
|
|
|
|
{
|
|
|
|
return (header[0] & 0x200) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::Discard2()
|
|
|
|
{
|
|
|
|
return (header[0] & 0x100) > 0;
|
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
int PolyHeader::NumVerts()
|
|
|
|
{
|
|
|
|
return (header[0] & 0x40) ? 4 : 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::NumSharedVerts()
|
|
|
|
{
|
2016-03-24 13:17:17 +00:00
|
|
|
int sharedVerts[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
|
2016-03-21 04:10:14 +00:00
|
|
|
|
2016-03-24 13:17:17 +00:00
|
|
|
return sharedVerts[header[0] & 0xf];
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::SharedVertex(int vertex)
|
|
|
|
{
|
|
|
|
UINT32 mask = 1 << vertex;
|
|
|
|
|
|
|
|
return (header[0] & mask) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// header 1
|
|
|
|
//
|
|
|
|
|
|
|
|
void PolyHeader::FaceNormal(float n[3])
|
|
|
|
{
|
|
|
|
n[0] = (float)(((INT32)header[1]) >> 8) * (1.0f / 4194304.0f);
|
|
|
|
n[1] = (float)(((INT32)header[2]) >> 8) * (1.0f / 4194304.0f);
|
|
|
|
n[2] = (float)(((INT32)header[3]) >> 8) * (1.0f / 4194304.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
float PolyHeader::UVScale()
|
|
|
|
{
|
|
|
|
return (header[1] & 0x40) ? 1.0f : (1.0f / 8.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::DoubleSided()
|
|
|
|
{
|
|
|
|
return (header[1] & 0x10) ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::LastPoly()
|
|
|
|
{
|
|
|
|
if ((header[1] & 4) > 0 || header[6] == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::PolyColor()
|
|
|
|
{
|
|
|
|
return (header[1] & 2) > 0;
|
|
|
|
}
|
|
|
|
|
2016-04-29 23:03:46 +00:00
|
|
|
bool PolyHeader::FixedShading()
|
|
|
|
{
|
|
|
|
return (header[1] & 0x20) > 0;
|
|
|
|
}
|
|
|
|
|
2016-05-05 00:01:17 +00:00
|
|
|
bool PolyHeader::SmoothShading()
|
|
|
|
{
|
|
|
|
return (header[1] & 0x8) > 0;
|
|
|
|
}
|
|
|
|
|
2018-10-19 20:59:46 +00:00
|
|
|
bool PolyHeader::NoLosReturn()
|
|
|
|
{
|
|
|
|
return (header[1] & 0x1) > 0;
|
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
//
|
|
|
|
// header 2
|
|
|
|
//
|
|
|
|
|
|
|
|
bool PolyHeader::TexUMirror()
|
|
|
|
{
|
|
|
|
return (header[2] & 2) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::TexVMirror()
|
|
|
|
{
|
|
|
|
return (header[2] & 1) > 0;
|
|
|
|
}
|
|
|
|
|
2016-05-04 00:35:07 +00:00
|
|
|
bool PolyHeader::MicroTexture()
|
|
|
|
{
|
|
|
|
return (header[2] & 0x10) > 0;
|
|
|
|
}
|
|
|
|
|
2016-10-06 01:37:29 +00:00
|
|
|
int PolyHeader::MicroTextureID()
|
|
|
|
{
|
2016-12-09 14:13:46 +00:00
|
|
|
return (header[2] >> 5) & 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::MicroTextureMinLOD()
|
|
|
|
{
|
|
|
|
return (header[2] >> 2) & 3;
|
2016-10-06 01:37:29 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
//
|
|
|
|
// header 3
|
|
|
|
|
|
|
|
int PolyHeader::TexWidth()
|
|
|
|
{
|
2016-05-01 19:52:02 +00:00
|
|
|
UINT32 w = (header[3] >> 3) & 7;
|
|
|
|
|
|
|
|
if (w >= 6) {
|
|
|
|
w = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 32 << w;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
2016-05-01 19:52:02 +00:00
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
int PolyHeader::TexHeight()
|
|
|
|
{
|
2016-05-01 19:52:02 +00:00
|
|
|
UINT32 h = (header[3] >> 0) & 7;
|
|
|
|
|
|
|
|
if (h >= 6) {
|
|
|
|
h = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 32 << h;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
2016-05-07 18:57:06 +00:00
|
|
|
bool PolyHeader::TexSmoothU()
|
|
|
|
{
|
|
|
|
return (header[3] & 0x80) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::TexSmoothV()
|
|
|
|
{
|
|
|
|
return (header[3] & 0x40) > 0;
|
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
//
|
|
|
|
// header 4
|
|
|
|
//
|
|
|
|
|
|
|
|
void PolyHeader::Color(UINT8& r, UINT8& g, UINT8& b)
|
|
|
|
{
|
|
|
|
r = (header[4] >> 24);
|
|
|
|
g = (header[4] >> 16) & 0xFF;
|
|
|
|
b = (header[4] >> 8) & 0xFF;
|
|
|
|
}
|
|
|
|
|
2016-05-28 20:49:10 +00:00
|
|
|
int PolyHeader::ColorIndex()
|
|
|
|
{
|
|
|
|
return (header[4] >> 8) & 0xFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PolyHeader::SensorColorIndex()
|
|
|
|
{
|
|
|
|
return (header[4] >> 20) & 0xFFF;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:20:42 +00:00
|
|
|
bool PolyHeader::TranslatorMap()
|
2016-04-27 16:42:31 +00:00
|
|
|
{
|
|
|
|
return (header[4] & 0x80) > 0;
|
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
int PolyHeader::Page()
|
|
|
|
{
|
|
|
|
return (header[4] & 0x40) >> 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// header 5
|
|
|
|
//
|
|
|
|
|
2016-03-26 22:44:26 +00:00
|
|
|
int PolyHeader::X()
|
2016-03-21 04:10:14 +00:00
|
|
|
{
|
|
|
|
//====
|
|
|
|
int x;
|
|
|
|
//====
|
|
|
|
|
2016-03-26 22:44:26 +00:00
|
|
|
x = (32 * (((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 1)));
|
2016-03-21 04:10:14 +00:00
|
|
|
x &= 2047;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-03-26 22:44:26 +00:00
|
|
|
int PolyHeader::Y()
|
2016-03-21 04:10:14 +00:00
|
|
|
{
|
|
|
|
//=======
|
|
|
|
int y;
|
|
|
|
int page;
|
|
|
|
//=======
|
|
|
|
|
|
|
|
if (Page()) {
|
|
|
|
page = 1024;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
page = 0;
|
|
|
|
}
|
|
|
|
|
2016-03-26 22:44:26 +00:00
|
|
|
y = (32 * (header[5] & 0x1F) + page); // if we hit 2nd page add 1024 to y coordinate
|
2016-03-21 04:10:14 +00:00
|
|
|
y &= 2047;
|
|
|
|
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// header 6
|
|
|
|
//
|
|
|
|
|
2016-05-27 19:30:40 +00:00
|
|
|
bool PolyHeader::Layered()
|
|
|
|
{
|
|
|
|
return (header[6] & 0x8) > 0;
|
|
|
|
}
|
|
|
|
|
2016-05-15 16:24:49 +00:00
|
|
|
float PolyHeader::Shininess()
|
|
|
|
{
|
2017-08-09 16:56:56 +00:00
|
|
|
return (float)((header[6] >> 5) & 3); // input sdk values are float 0-1 output are int 0-3
|
2016-05-15 16:24:49 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
int PolyHeader::TexFormat()
|
|
|
|
{
|
|
|
|
return (header[6] >> 7) & 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::TexEnabled()
|
|
|
|
{
|
2016-04-03 16:10:40 +00:00
|
|
|
return (header[6] & 0x400) > 0;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::LightEnabled()
|
|
|
|
{
|
|
|
|
return !(header[6] & 0x00010000);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::AlphaTest()
|
|
|
|
{
|
|
|
|
return (header[6] & 0x80000000) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT8 PolyHeader::Transparency()
|
|
|
|
{
|
2016-05-30 23:10:56 +00:00
|
|
|
if (header[6] & 0x800000) { // check top bit to see if its 1. Star wars is writing 1 for opaque, but the rest of the bits are garbage and are ignored
|
|
|
|
return 255; // without this check we get overflow. In the SDK, values are explicitly clamped to 0-32.
|
|
|
|
}
|
|
|
|
|
2017-08-14 09:14:06 +00:00
|
|
|
return (((header[6] >> 18) & 0x3F) * 255) / 32;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::PolyAlpha()
|
|
|
|
{
|
|
|
|
return (header[6] & 0x00800000) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::TextureAlpha()
|
|
|
|
{
|
2016-04-30 09:02:38 +00:00
|
|
|
return (header[6] & 0x7) > 0;
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool PolyHeader::Luminous()
|
|
|
|
{
|
|
|
|
return (header[6] & 0x00010000) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
float PolyHeader::LightModifier()
|
|
|
|
{
|
2016-05-16 10:49:00 +00:00
|
|
|
return ((header[6] >> 11) & 0x1F) * (1.0f / 16.0f);
|
2016-03-21 04:10:14 +00:00
|
|
|
}
|
|
|
|
|
2017-02-18 23:58:08 +00:00
|
|
|
bool PolyHeader::HighPriority()
|
|
|
|
{
|
|
|
|
return (header[6] & 0x10) > 0;
|
|
|
|
}
|
|
|
|
|
2017-04-05 17:57:38 +00:00
|
|
|
int PolyHeader::TranslatorMapOffset()
|
|
|
|
{
|
|
|
|
return (header[6] >> 24) & 0x7f;
|
|
|
|
}
|
|
|
|
|
2018-05-24 20:13:15 +00:00
|
|
|
bool PolyHeader::TranslucencyPatternSelect()
|
|
|
|
{
|
2018-05-24 20:19:54 +00:00
|
|
|
return (header[6] & 0x20000) > 0;
|
2018-05-24 20:13:15 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 04:10:14 +00:00
|
|
|
//
|
2018-05-28 11:59:48 +00:00
|
|
|
// hashing
|
2016-03-21 04:10:14 +00:00
|
|
|
//
|
|
|
|
|
2016-03-26 22:44:26 +00:00
|
|
|
UINT64 PolyHeader::Hash()
|
2016-03-21 04:10:14 +00:00
|
|
|
{
|
|
|
|
UINT64 hash = 0;
|
|
|
|
|
2018-05-28 11:59:48 +00:00
|
|
|
hash |= (UINT64)(header[3] & 0xFF); // bits 0-7 tex width / height / uv smooth
|
|
|
|
hash |= (UINT64)(((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 1)) << 8; // bits 8-13 x offset
|
2018-05-29 14:54:23 +00:00
|
|
|
hash |= (UINT64)(header[5] & 0x1F) << 14; // bits 14-18 y offset
|
2020-05-11 09:05:46 +00:00
|
|
|
hash |= (UINT64)((header[4] & 0xC0) >> 6) << 19; // bits 19-20 page / translatormap
|
|
|
|
hash |= (UINT64)DoubleSided() << 21; // bits 21 double sided
|
|
|
|
hash |= (UINT64)AlphaTest() << 22; // bits 22 contour processing
|
|
|
|
hash |= (UINT64)PolyAlpha() << 23; // bits 23 poly alpha processing
|
|
|
|
hash |= (UINT64)(header[2] & 0xFF) << 24; // bits 24-31 microtexture / uv mirror
|
|
|
|
hash |= (UINT64)SpecularEnabled() << 32; // bits 32 enable specular reflection
|
|
|
|
hash |= (UINT64)SmoothShading() << 33; // bits 33 smooth shading
|
|
|
|
hash |= (UINT64)FixedShading() << 34; // bits 34 fixed shading
|
|
|
|
hash |= (UINT64)(header[0] >> 26) << 35; // bits 35-40 specular coefficient (opacity)
|
|
|
|
hash |= (UINT64)(header[6] & 0x3FFFF) << 41; // bits 41-58 Translucency pattern select / disable lighting / Polygon light modifier / Texture enable / Texture format / Shininess / High priority / Layered polygon / Translucency mode
|
2016-03-21 04:10:14 +00:00
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // New3D
|