Supermodel/Src/Graphics/New3D/PolyHeader.cpp

419 lines
7.5 KiB
C++
Raw Permalink Normal View History

#include "Supermodel.h"
#include "PolyHeader.h"
namespace New3D {
PolyHeader::PolyHeader()
{
header = nullptr;
}
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-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;
}
int PolyHeader::PolyNumber()
{
return (header[0] & 0x000FFFC00) >> 10; // not all programs pass this, instead they are set to 0
}
bool PolyHeader::Discard()
{
if ((header[0] & 0x100) && (header[0] & 0x200)) {
return true;
}
return false;
}
bool PolyHeader::Discard1()
{
return (header[0] & 0x200) > 0;
}
bool PolyHeader::Discard2()
{
return (header[0] & 0x100) > 0;
}
int PolyHeader::NumVerts()
{
return (header[0] & 0x40) ? 4 : 3;
}
int PolyHeader::NumSharedVerts()
{
static const int sharedVerts[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
2016-03-24 13:17:17 +00:00
return sharedVerts[header[0] & 0xf];
}
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) * (float)(1.0 / 4194304.0);
n[1] = (float)(((INT32)header[2]) >> 8) * (float)(1.0 / 4194304.0);
n[2] = (float)(((INT32)header[3]) >> 8) * (float)(1.0 / 4194304.0);
}
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;
}
bool PolyHeader::NoLosReturn()
{
return (header[1] & 0x1) > 0;
}
bool PolyHeader::EdgeOnTranslucency()
{
return (header[1] & 0x80) > 0;
}
//
// 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;
}
int PolyHeader::MicroTextureID()
{
return (header[2] >> 5) & 7;
}
int PolyHeader::MicroTextureMinLOD()
{
return (header[2] >> 2) & 3;
}
//
// header 3
int PolyHeader::TexWidth()
{
UINT32 w = (header[3] >> 3) & 7;
if (w >= 6) {
w = 0;
}
return 32 << w;
}
int PolyHeader::TexHeight()
{
UINT32 h = (header[3] >> 0) & 7;
if (h >= 6) {
h = 0;
}
return 32 << h;
}
2016-05-07 18:57:06 +00:00
bool PolyHeader::TexSmoothU()
{
return (header[3] & 0x80) > 0;
}
bool PolyHeader::TexSmoothV()
{
return (header[3] & 0x40) > 0;
}
//
// 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;
}
int PolyHeader::ColorIndex()
{
return (header[4] >> 8) & 0xFFF;
}
int PolyHeader::SensorColorIndex()
{
return (header[4] >> 20) & 0xFFF;
}
bool PolyHeader::TranslatorMap()
2016-04-27 16:42:31 +00:00
{
return (header[4] & 0x80) > 0;
}
int PolyHeader::Page()
{
return (header[4] & 0x40) >> 6;
}
//
// header 5
//
int PolyHeader::X()
{
//====
int x;
//====
x = (32 * (((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 1)));
x &= 2047;
return x;
}
int PolyHeader::Y()
{
//====
int y;
//====
y = 32 * (header[5] & 0x1F); // if we hit 2nd page add 1024 to y coordinate
y &= 2047;
return y;
}
float PolyHeader::TextureNP()
{
return (float)(header[5] >> 8);
}
//
// header 6
//
bool PolyHeader::Layered()
{
return (header[6] & 0x8) > 0;
}
2016-05-15 16:24:49 +00:00
float PolyHeader::Shininess()
{
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
}
int PolyHeader::TexFormat()
{
return (header[6] >> 7) & 7;
}
bool PolyHeader::TexEnabled()
{
2016-04-03 16:10:40 +00:00
return (header[6] & 0x400) > 0;
}
bool PolyHeader::LightEnabled()
{
return !(header[6] & 0x00010000);
}
bool PolyHeader::AlphaTest()
{
return (header[6] & 0x80000000) > 0;
}
UINT8 PolyHeader::Transparency()
{
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.
}
return (((header[6] >> 18) & 0x3F) * 255) / 32;
}
bool PolyHeader::PolyAlpha()
{
return (header[6] & 0x00800000) == 0;
}
bool PolyHeader::TextureAlpha()
{
return (header[6] & 0x7) > 0;
}
bool PolyHeader::Luminous()
{
return (header[6] & 0x00010000) > 0;
}
float PolyHeader::LightModifier()
{
return ((header[6] >> 11) & 0x1F) * (1.0f / 16.0f);
}
bool PolyHeader::HighPriority()
{
return (header[6] & 0x10) > 0;
}
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
}
//
// hashing
//
UINT64 PolyHeader::Hash()
{
UINT64 hash = 0;
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
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
hash |= (UINT64)NoLosReturn() << 59; // bits 59 no line of sight return
return hash;
}
} // New3D