#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 // bool PolyHeader::SpecularEnabled() { return (header[0] & 0x80) > 0; } float PolyHeader::SpecularValue() { return (header[0] >> 26) / 63.f; // 63 matches decompiled lib value } 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 }; 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; } bool PolyHeader::FixedShading() { return (header[1] & 0x20) > 0; } 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; } 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; } 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() { 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; } // // header 6 // bool PolyHeader::Layered() { return (header[6] & 0x8) > 0; } float PolyHeader::Shininess() { return (float)((header[6] >> 5) & 3); // input sdk values are float 0-1 output are int 0-3 } int PolyHeader::TexFormat() { return (header[6] >> 7) & 7; } bool PolyHeader::TexEnabled() { 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; } bool PolyHeader::TranslucencyPatternSelect() { return (header[6] & 0x20000) > 0; } // // 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 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