diff --git a/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp b/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp deleted file mode 100644 index 770e326..0000000 --- a/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp +++ /dev/null @@ -1,352 +0,0 @@ -#include "Texture.h" -#include -#include - -namespace New3D { - -Texture::Texture() -{ - Reset(); -} - -Texture::~Texture() -{ - DeleteTexture(); // make sure to have valid context before destroying -} - -void Texture::DeleteTexture() -{ - if (m_textureID) { - glDeleteTextures(1, &m_textureID); - printf("-----> deleting %i %i %i %i %i\n", m_format, m_x, m_y, m_width, m_height); - Reset(); - } -} - -void Texture::Reset() -{ - m_x = 0; - m_y = 0; - m_width = 0; - m_height = 0; - m_format = 0; - m_textureID = 0; - m_mirrorU = false; - m_mirrorV = false; -} - -void Texture::BindTexture() -{ - glBindTexture(GL_TEXTURE_2D, m_textureID); -} - -void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut) -{ - uOut = (uIn*uvScale) / m_width; - vOut = (vIn*uvScale) / m_height; -} - -void Texture::GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut) -{ - uOut = (uIn*uvScale) / width; - vOut = (vIn*uvScale) / height; -} - -void Texture::SetWrapMode(bool mirrorU, bool mirrorV) -{ - if (mirrorU != m_mirrorU) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT); - m_mirrorU = mirrorU; - } - - if (mirrorV != m_mirrorV) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT); - m_mirrorV = mirrorV; - } -} - -UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height) -{ - int xi, yi, i; - GLubyte texel; - GLubyte c, a; - UINT16* scratch16; - GLenum type; - - if (!src || !scratch) { - return 0; // sanity checking - } - - DeleteTexture(); // free any existing texture - - i = 0; - type = GL_UNSIGNED_BYTE; - scratch16 = (UINT16*)scratch; - - switch (format) - { - default: // Debug texture - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch[i++] = 255; // R - scratch[i++] = 0; // G - scratch[i++] = 0; // B - scratch[i++] = 255; // A - } - } - break; - - case 0: // T1RGB5 <- correct - type = GL_UNSIGNED_SHORT_5_5_5_1; - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch16[i++] = src[yi * 2048 + xi] << 1 | ((src[yi * 2048 + xi] >> 15) ^ 0x1); // flip alpha - } - } - break; - - case 1: // Interleaved A4L4 (low byte) - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - // Interpret as A4L4 - texel = src[yi * 2048 + xi] & 0xFF; - c = (texel & 0xF) * 17; - a = (texel >> 4) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 2: // luminance alpha texture <- this one is correct - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - c = ((texel >> 4) & 0xF) * 17; - a = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 3: // 8-bit, A4L4 (high byte) - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = (texel & 0xF) * 17; - a = (texel >> 4) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 4: // 8-bit, L4A4 (high byte) - - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = ((texel >> 4) & 0xF) * 17; - a = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 5: // 8-bit grayscale - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = (texel==255 ? 0 : 255); - } - } - break; - - case 6: // 8-bit grayscale <-- this one is correct - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = (texel == 255 ? 0 : 255); - } - } - break; - - case 7: // RGBA4 - type = GL_UNSIGNED_SHORT_4_4_4_4; - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch16[i++] = src[yi * 2048 + xi]; - } - } - break; - - // - // 4 bit texture types - all luminance textures (no alpha), only seem to be enabled when contour is enabled ( white = contour value ) - // - - case 8: // low byte, low nibble - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - c = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = (c == 255 ? 0 : 255); - } - } - break; - - case 9: // low byte, high nibble - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - c = ((texel >> 4) & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = (c == 255 ? 0 : 255); - } - } - break; - - case 10: // high byte, low nibble - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = (c == 255 ? 0 : 255); - } - } - break; - - case 11: // high byte, high nibble - - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = ((texel >> 4) & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = (c == 255 ? 0 : 255); - } - } - break; - } - - - GLfloat maxAnistrophy; - - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy); - - if (maxAnistrophy > 8) { - maxAnistrophy = 8.0f; //anymore than 8 can get expensive for little gain - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // rgba is always 4 byte aligned - glGenTextures(1, &m_textureID); - glBindTexture(GL_TEXTURE_2D, m_textureID); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT); //todo this in shaders? - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnistrophy); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, type, scratch); - - // assuming successful we can copy details - - m_x = x; - m_y = y; - m_width = width; - m_height = height; - m_format = format; - m_mirrorU = mirrorU; - m_mirrorV = mirrorV; - - printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height); - - return m_textureID; -} - -void Texture::GetDetails(int& x, int&y, int& width, int& height, int& format) -{ - x = m_x; - y = m_y; - width = m_width; - height = m_height; - format = m_format; -} - -bool Texture::Compare(int x, int y, int width, int height, int format) -{ - if (m_x == x && m_y == y && m_width == width && m_height == height && m_format == format) { - return true; - } - - return false; -} - -bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2) -{ - int bx1 = m_x; - int bx2 = m_x + m_width; - int by1 = m_y; - int by2 = m_y + m_height; - - if (ax1bx1 && - ay1by1) { - return true; // rectangles overlap - } - - return false; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/New3D.cpp b/Src/Graphics/New3D/backup/New3D.cpp deleted file mode 100644 index 60caeaa..0000000 --- a/Src/Graphics/New3D/backup/New3D.cpp +++ /dev/null @@ -1,1415 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include -#include -#include -#include "R3DFloat.h" - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - std::shared_ptr tex1; - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes->empty()) { - continue; - } - - m_r3dShader.SetModelStates(&m); - - for (auto &mesh : *m.meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.textured) { - - int x, y; - CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y); - - if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) { - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - else { - tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height); - if (tex1) { - tex1->BindTexture(); - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - } - - if (mesh.microTexture) { - - int mX, mY; - glActiveTexture(GL_TEXTURE1); - m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY); - auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128); - if (tex2) { - tex2->BindTexture(); - } - glActiveTexture(GL_TEXTURE0); - } - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glDisable(GL_STENCIL_TEST); -} - -void CNew3D::RenderFrame(void) -{ - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - - memset(layerMax, 0, sizeof(UINT32) * 4); - - glDepthFunc (GL_LEQUAL); - glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero - glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value - glStencilMask (0xFF); - - RenderViewport(0x800000); // build model structure - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - //check we haven't blown up the memory buffers - //we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway - if (m_polyBufferRom.size() >= MAX_ROM_POLYS) { - m_polyBufferRom.clear(); - m_romMap.clear(); - m_vbo.Reset(); - } - else { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - printf("layer max %f %f %f %f\n", layerMax[0], layerMax[1], layerMax[2], layerMax[3]); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - bool cached = false; - Model* m; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - m_nodes.back().models.emplace_back(Model()); - - // get the last model in the array - m = &m_nodes.back().models.back(); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - // try to find meshes in the rom cache - - m->meshes = m_romMap[modelAddr]; // will create an entry with a null pointer if empty - - if (m->meshes) { - cached = true; - } - else { - m->meshes = std::make_shared>(); - m_romMap[modelAddr] = m->meshes; // store meshes in our rom map here - } - - m->dynamic = false; - } - else { - m->meshes = std::make_shared>(); - } - - // copy current model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - // update texture offsets - m->textureOffsetX = m_nodeAttribs.currentTexOffsetX; - m->textureOffsetY = m_nodeAttribs.currentTexOffsetY; - m->page = m_nodeAttribs.currentPage; - - if (!cached) { - CacheModel(m, modelAddress); - } - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, child1Ptr, sibling2Ptr; - float x, y, z; - int tx, ty; - BBox bbox; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - child1Ptr = node[0x07 - m_offset] & 0x7FFFFFF; // mask colour table bits - sibling2Ptr = node[0x08 - m_offset] & 0x1FFFFFF; // mask colour table bits - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings - if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) { - DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero - } - } - - if ((node[0x00] & 0x04)) { - m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17); - m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range - } - - x = *(float *)&node[0x04 - m_offset]; - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x1F); - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) { - - float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF); - - auto test = node[9 - m_offset] & 0xFFFF; - - CalcBox(distance, bbox); - TransformBox(m_modelMat, bbox); - - m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes); - - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && test != 0x7fff) { - - for (int i = 0; i < 8; i++) { - layerMax[cLayer] = std::max(layerMax[cLayer], std::abs(bbox.points[i][2])); - } - - } - } - - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) { - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(child1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(child1Ptr); - } - - } - - m_modelMat.PopMatrix(); - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 2 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int index; - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - index = 0; - - while (true) { - - if (list[index] & 0x01000000) { - break; // empty list - } - - nodeAddr = list[index] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - DescendCullingNode(nodeAddr); - - if (list[index] & 0x02000000) { - break; // list end - } - - index++; - } -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - mat.LoadMatrix(m); - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr) -{ - static const GLfloat color[8][3] = - { // RGB1 color translation - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - - // Translate address and obtain pointer - const uint32_t *vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - - if (!(vpnode[0] & 0x20)) { // only if viewport enabled - uint32_t curPri = (vpnode[0x00] >> 3) & 3; // viewport priority - uint32_t nodeAddr = vpnode[0x02]; // scene database node pointer - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - Viewport *vp = &m_nodes.back().viewport; - - vp->priority = curPri; - - cLayer = curPri; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - int vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point) - int vpY = (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f); // viewport Y (12.4) - int vpWidth = (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f); // width (14.2) - int vpHeight = (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f); // height (14.2) - uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - if (vpX) { - vpX += 2; - } - - if (vpY) { - vpY += 2; - } - - LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]); - - float angle_left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]); - float angle_right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]); - float angle_top = atan2(*(float *)&vpnode[14], *(float *)&vpnode[15]); - float angle_bottom = -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]); - - float near = 10.5f; - float far = 1e6; - //float far = 13696.f; - - if (m_step == 0x10) { - near = 8; - } - - //near = 5.02f; - //far = 20000; - - float l = near * tanf(angle_left); - float r = near * tanf(angle_right); - float t = near * tanf(angle_top); - float b = near * tanf(angle_bottom); - - // TO-DO: investigate clipping near/far planes - - if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) - { - float windowAR = (float)m_totalXRes / (float)m_totalYRes; - float originalAR = 496 / 384.f; - float correction = windowAR / originalAR; // expand horizontal frustum planes - - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far); - } - else - { - vp->x = m_xOffs + (GLint)((float)vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = (GLint)((float)vpWidth*m_xRatio); - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l, r, b, t, near, far); - } - - // calculate frustum planes - CalcFrustumPlanes(m_planes, vp->projectionMatrix); - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - - if (vp->spotRange[1] == 0) { // if light extent = 0 light is effectively disabled - spotColorIdx = 0; - } - - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = *(float *)&vpnode[0x23]; // fog density - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - { - //test fog paramaters - float lightFogColour[3]; - int fogColourIdx; - - fogColourIdx = (vpnode[0x20] >> 8) & 7; - - lightFogColour[0] = color[fogColourIdx][0]; - lightFogColour[1] = color[fogColourIdx][1]; - lightFogColour[2] = color[fogColourIdx][2]; - - float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f; - float fogAmbient = ((vpnode[0x25] >> 16) & 0xFF) / 255.f; - int debug = 0; - } - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - float scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21>1.05) || (m21<0.95)) - return; - if ((m32>1.05) || (m32<0.95)) - return; - if ((m13>1.05) || (m13<0.95)) - return; - } - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); - } - - // render next viewport - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01]); - } -} - -void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - } -} - -// non smooth texturing on the pro-1000 seems to sample like gl_nearest -// ie not outside of the texture coordinates, but with bilinear filtering -// this is about as close as we can emulate in hardware -// if we don't do this with gl_repeat enabled, it will wrap around and sample the -// other side of the texture which produces ugly seems -void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]) -{ - for (int i = 0; i < 2; i++) { - - float min = std::numeric_limits::max(); - float max = -std::numeric_limits::max(); - - if (!offset[i]) continue; - - for (int j = 0; j < r3dPoly.number; j++) { - min = std::min(r3dPoly.v[j].texcoords[i], min); - max = std::max(r3dPoly.v[j].texcoords[i], max); - } - - float fTemp; - float iTemp; - bool fractMin; - bool fractMax; - - fTemp = std::modf(min, &iTemp); - fractMin = fTemp > 0; - - fTemp = std::modf(max, &iTemp); - fractMax = fTemp > 0; - - for (int j = 0; j < r3dPoly.number && min != max; j++) { - - if (!fractMin) { - if (r3dPoly.v[j].texcoords[i] == min) { - r3dPoly.v[j].texcoords[i] += offset[i]; - } - } - - if (!fractMax) { - if (r3dPoly.v[j].texcoords[i] == max) { - r3dPoly.v[j].texcoords[i] -= offset[i]; - } - } - } - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - do { - - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - - if (ph.header[6] == 0) { - break; - } - - if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) { - continue; - } - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(); - - if (hash != lastHash) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = false; // we will double up polys - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); - - if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) { - currentMesh->layered = true; - } - - if (currentMesh->lighting) { - if (ph.SpecularEnabled()) { - currentMesh->specular = true; - currentMesh->shininess = 0;// ph.Shininess(); - currentMesh->specularCoefficient = 0; // ph.SpecularValue(); - } - } - - currentMesh->fogIntensity = ph.LightModifier(); - - if (ph.TexEnabled()) { - currentMesh->format = m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest()); - - if (currentMesh->format == 7) { - currentMesh-> alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency - } - - currentMesh->x = ph.X(); - currentMesh->y = ph.Y(); - currentMesh->width = ph.TexWidth(); - currentMesh->height = ph.TexHeight(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - currentMesh->microTexture = ph.MicroTexture(); - currentMesh->microTextureID = ph.MicroTextureID(); - } - } - - currentMesh = &sMap[hash]; - } - - lastHash = hash; - - // Obtain basic polygon parameters - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - // copy face attributes - - if ((ph.header[1] & 2) == 0) { - int colorIdx = ph.ColorIndex(); - p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; - p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; - p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; - } - else { - if (ph.ColorDisabled()) { // no colours were set - p.faceColour[0] = 1.0f; - p.faceColour[1] = 1.0f; - p.faceColour[2] = 1.0f; - } - else { - p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; - p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; - p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; - } - } - - if (cLayer == 3) { - p.faceColour[0] = 1; - p.faceColour[1] = 0; - p.faceColour[2] = 0; - } - - p.faceColour[3] = ph.Transparency() / 255.f; - - // if we have flat shading, we can't re-use normals from shared vertices - for (i = 0; i < p.number && !ph.SmoothShading(); i++) { - p.v[i].normal[0] = p.faceNormal[0]; - p.v[i].normal[1] = p.faceNormal[1]; - p.v[i].normal[2] = p.faceNormal[2]; - } - - UINT32* vData = ph.StartOfData(); // vertex data starts here - - // remaining vertices are new and defined here - for (; j < p.number; j++) - { - // Fetch vertices - UINT32 ix = vData[0]; - UINT32 iy = vData[1]; - UINT32 iz = vData[2]; - UINT32 it = vData[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - // Per vertex normals - if (ph.SmoothShading()) { - p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f; - p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f; - p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f; - } - - if (ph.FixedShading() && ph.LightEnabled()) { - UINT8 shade = (UINT8)((ix + 128) & 0xFF); - p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - p.v[j].color[3] = 255; - } - else { - p.v[j].color[0] = 255; - p.v[j].color[1] = 255; - p.v[j].color[2] = 255; - p.v[j].color[3] = 255; - } - - float texU, texV = 0; - - // tex coords - if (currentMesh->textured) { - Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - vData += 4; - } - - // check if we need to modify the texture coordinates - { - float offset[2] = { 0 }; - - if (ph.TexEnabled()) { - - if (!ph.TexSmoothU() && !ph.TexUMirror()) { - offset[0] = 0.5f / ph.TexWidth(); // half texel - } - - if (!ph.TexSmoothV() && !ph.TexVMirror()) { - offset[1] = 0.5f / ph.TexHeight(); // half texel - } - - OffsetTexCoords(p, offset); - } - } - - // check if we need double up vertices for two sided lighting - if (ph.DoubleSided()) { - - R3DPoly tempP = p; - - // flip normals - V3::inverse(tempP.faceNormal); - - for (int i = 0; i < tempP.number; i++) { - V3::inverse(tempP.v[i].normal); - } - - CopyVertexData(tempP, currentMesh->polys); - } - - // Copy this polygon into the model buffer - CopyVertexData(p, currentMesh->polys); - numPolys++; - - // Copy current vertices into previous vertex array - for (i = 0; i < 4; i++) { - prev[i] = p.v[i]; - } - - } while (ph.NextPoly()); - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes->reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes->push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY) -{ - newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required - - int oldPage = y / 1024; - - y -= (oldPage * 1024); // remove page from tex y - - // calc newY with wrap around, wraps around in the same sheet, not into another memory sheet - - newY = (y + offY) & 1023; - - // add page to Y - - newY += ((oldPage + page) & 1) * 1024; // max page 0-1 -} - -void CNew3D::CalcFrustumPlanes(Plane p[6], const float* matrix) -{ - // Left Plane - p[0].a = matrix[3] + matrix[0]; - p[0].b = matrix[7] + matrix[4]; - p[0].c = matrix[11] + matrix[8]; - p[0].d = matrix[15] + matrix[12]; - p[0].Normalise(); - - // Right Plane - p[1].a = matrix[3] - matrix[0]; - p[1].b = matrix[7] - matrix[4]; - p[1].c = matrix[11] - matrix[8]; - p[1].d = matrix[15] - matrix[12]; - p[1].Normalise(); - - // Bottom Plane - p[2].a = matrix[3] + matrix[1]; - p[2].b = matrix[7] + matrix[5]; - p[2].c = matrix[11] + matrix[9]; - p[2].d = matrix[15] + matrix[13]; - p[2].Normalise(); - - // Top Plane - p[3].a = matrix[3] - matrix[1]; - p[3].b = matrix[7] - matrix[5]; - p[3].c = matrix[11] - matrix[9]; - p[3].d = matrix[15] - matrix[13]; - p[3].Normalise(); - - // Near Plane - p[4].a = matrix[3] + matrix[2]; - p[4].b = matrix[7] + matrix[6]; - p[4].c = matrix[11] + matrix[10]; - p[4].d = matrix[15] + matrix[14]; - p[4].Normalise(); - - // Far Plane - p[5].a = matrix[3] - matrix[2]; - p[5].b = matrix[7] - matrix[6]; - p[5].c = matrix[11] - matrix[10]; - p[5].d = matrix[15] - matrix[14]; - p[5].Normalise(); -} - -void CNew3D::CalcBox(float distance, BBox& box) -{ - //bottom left front - box.points[0][0] = -distance; - box.points[0][1] = -distance; - box.points[0][2] = distance; - box.points[0][3] = 1; - - //bottom left back - box.points[1][0] = -distance; - box.points[1][1] = -distance; - box.points[1][2] = -distance; - box.points[1][3] = 1; - - //bottom right back - box.points[2][0] = distance; - box.points[2][1] = -distance; - box.points[2][2] = -distance; - box.points[2][3] = 1; - - //bottom right front - box.points[3][0] = distance; - box.points[3][1] = -distance; - box.points[3][2] = distance; - box.points[3][3] = 1; - - //top left front - box.points[4][0] = -distance; - box.points[4][1] = distance; - box.points[4][2] = distance; - box.points[4][3] = 1; - - //top left back - box.points[5][0] = -distance; - box.points[5][1] = distance; - box.points[5][2] = -distance; - box.points[5][3] = 1; - - //top right back - box.points[6][0] = distance; - box.points[6][1] = distance; - box.points[6][2] = -distance; - box.points[6][3] = 1; - - //top right front - box.points[7][0] = distance; - box.points[7][1] = distance; - box.points[7][2] = distance; - box.points[7][3] = 1; -} - -void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) -{ - for (int i = 0; i < 4; i++) { - out[i] = - in[0] * matrix[0 * 4 + i] + - in[1] * matrix[1 * 4 + i] + - in[2] * matrix[2 * 4 + i] + - in[3] * matrix[3 * 4 + i]; - } -} - -void CNew3D::TransformBox(const float *m, BBox& box) -{ - for (int i = 0; i < 8; i++) { - float v[4]; - MultVec(m, box.points[i], v); - box.points[i][0] = v[0]; - box.points[i][1] = v[1]; - box.points[i][2] = v[2]; - } -} - -Clip CNew3D::ClipBox(BBox& box, Plane planes[6]) -{ - int count = 0; - - for (int i = 0; i < 8; i++) { - - int temp = 0; - - for (int j = 0; j < 6; j++) { - if (planes[j].DistanceToPoint(box.points[i]) >= 0) { - temp++; - } - } - - if (temp == 6) count++; // point is inside all 6 frustum planes - } - - if (count == 8) return Clip::INSIDE; - if (count > 0) return Clip::INTERCEPT; - - //if we got here all points are outside of the view frustum - //check for all points being side same of any plane, means box outside of view - - for (int i = 0; i < 6; i++) { - - int temp = 0; - - for (int j = 0; j < 8; j++) { - if (planes[i].DistanceToPoint(box.points[j]) >= 0) { - float distance = planes[i].DistanceToPoint(box.points[j]); - temp++; - } - } - - if (temp == 0) return Clip::OUTSIDE; - } - - //if we got here, box is traversing view frustum - - return Clip::INTERCEPT; -} - -} // New3D - diff --git a/Src/Graphics/New3D/backup/New3D.h b/Src/Graphics/New3D/backup/New3D.h deleted file mode 100644 index a35c6ba..0000000 --- a/Src/Graphics/New3D/backup/New3D.h +++ /dev/null @@ -1,239 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" -#include "R3DData.h" -#include "Plane.h" -#include "Vec.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray); - void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - - void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY); - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - - std::vector m_nodes; // this represents the entire render frame - std::vector m_polyBufferRam; // dynamic polys - std::vector m_polyBufferRom; // rom polys - std::unordered_map>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet - - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - R3DShader m_r3dShader; - - Plane m_planes[6]; - - struct BBox - { - V4::Vec4 points[8]; - }; - - void CalcFrustumPlanes (Plane p[6], const float* matrix); - void CalcBox (float distance, BBox& box); - void TransformBox (const float *m, BBox& box); - void MultVec (const float matrix[16], const float in[4], float out[4]); - Clip ClipBox (BBox& box, Plane planes[6]); - - float layerMax[4]; - int cLayer; -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H diff --git a/Src/Graphics/New3D/backup/Texture.cpp b/Src/Graphics/New3D/backup/Texture.cpp deleted file mode 100644 index 3404e29..0000000 --- a/Src/Graphics/New3D/backup/Texture.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include "Texture.h" -#include -#include - -namespace New3D { - -Texture::Texture() -{ - Reset(); -} - -Texture::~Texture() -{ - DeleteTexture(); // make sure to have valid context before destroying -} - -void Texture::DeleteTexture() -{ - if (m_textureID) { - glDeleteTextures(1, &m_textureID); - printf("-----> deleting %i %i %i %i %i\n", m_format, m_x, m_y, m_width, m_height); - Reset(); - } -} - -void Texture::Reset() -{ - m_x = 0; - m_y = 0; - m_width = 0; - m_height = 0; - m_format = 0; - m_textureID = 0; - m_mirrorU = false; - m_mirrorV = false; -} - -void Texture::BindTexture() -{ - glBindTexture(GL_TEXTURE_2D, m_textureID); -} - -void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut) -{ - uOut = (uIn*uvScale) / m_width; - vOut = (vIn*uvScale) / m_height; -} - -void Texture::GetCoordinates(bool mirror, int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut) -{ - uOut = (uIn*uvScale) / width; - vOut = (vIn*uvScale) / height; - /* - - if (!mirror) { - - float flu = uOut - floor(uOut); - float flv = uOut - floor(uOut); - - int iu = (int)uOut; - int iv = (int)vOut; - - float offu = 1 / (width*2.f); - float offv = 1 / (height*2.f); - - if (iu % 2) { - if (!flu) { - flu = 1.0f; - } - } - - if ((iv % 2)) { - if (!flv) { - flv = -1.0f; - } - } - - uOut = flu; - vOut = flv; - - - if (flu < 0.5f) { - uOut += offu; - } - else { - uOut -= offu; - } - - if (flv < 0.5f) { - vOut += offu; - } - else { - vOut -= offu; - } - } - */ -} - -void Texture::SetWrapMode(bool mirrorU, bool mirrorV) -{ - if (mirrorU != m_mirrorU) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT); - m_mirrorU = mirrorU; - } - - if (mirrorV != m_mirrorV) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT); - m_mirrorV = mirrorV; - } -} - -UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height) -{ - int xi, yi, i; - GLubyte texel; - GLubyte c, a; - - if (!src || !scratch) { - return 0; // sanity checking - } - - DeleteTexture(); // free any existing texture - - i = 0; - - switch (format) - { - default: // Debug texture, use TEXTURE_DEBUG mask - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch[i++] = 255; // R - scratch[i++] = 0; // G - scratch[i++] = 0; // B - scratch[i++] = 255; // A - } - } - break; - - case 0: // T1RGB5 <- correct - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 10) & 0x1F) * 255.f / 0x1F); // R - scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 5) & 0x1F) * 255.f / 0x1F); // G - scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 0) & 0x1F) * 255.f / 0x1F); // B - scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255); // T - } - } - break; - - case 1: // Interleaved A4L4 (low byte) - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - // Interpret as A4L4 - texel = src[yi * 2048 + xi] & 0xFF; - c = (texel & 0xF) * 17; - a = (texel >> 4) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 2: // luminance alpha texture <- this one is correct - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - c = ((texel >> 4) & 0xF) * 17; - a = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 3: // 8-bit, A4L4 (high byte) - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = (texel & 0xF) * 17; - a = (texel >> 4) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 4: // 8-bit, L4A4 (high byte) - - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - c = ((texel >> 4) & 0xF) * 17; - a = (texel & 0xF) * 17; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = c; - scratch[i++] = a; - } - } - break; - - case 5: // 8-bit grayscale - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] & 0xFF; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = (texel==255 ? 0 : 255); - } - } - break; - - case 6: // 8-bit grayscale <-- this one is correct - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - texel = src[yi * 2048 + xi] >> 8; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = texel; - scratch[i++] = (texel == 255 ? 0 : 255); - } - } - break; - - case 7: // RGBA4 - for (yi = y; yi < (y + height); yi++) - { - for (xi = x; xi < (x + width); xi++) - { - scratch[i++] = ((src[yi * 2048 + xi] >> 12) & 0xF) * 17;// R - scratch[i++] = ((src[yi * 2048 + xi] >> 8) & 0xF) * 17; // G - scratch[i++] = ((src[yi * 2048 + xi] >> 4) & 0xF) * 17; // B - scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0xF) * 17; // A - } - } - break; - } - - //remove debug mask - format &= 7; - - GLfloat maxAnistrophy; - - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy); - - if (maxAnistrophy > 8) { - maxAnistrophy = 8.0f; //anymore than 8 can get expensive for little gain - } - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // rgba is always 4 byte aligned - glActiveTexture(GL_TEXTURE0); // activate correct texture unit - - glGenTextures(1, &m_textureID); - glBindTexture(GL_TEXTURE_2D, m_textureID); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT); //todo this in shaders? - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnistrophy); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch); - - // assuming successful we can copy details - - m_x = x; - m_y = y; - m_width = width; - m_height = height; - m_format = format; - m_mirrorU = mirrorU; - m_mirrorV = mirrorV; - - printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height); - - return m_textureID; -} - -void Texture::GetDetails(int& x, int&y, int& width, int& height, int& format) -{ - x = m_x; - y = m_y; - width = m_width; - height = m_height; - format = m_format; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/Texture.h b/Src/Graphics/New3D/backup/Texture.h deleted file mode 100644 index cab6518..0000000 --- a/Src/Graphics/New3D/backup/Texture.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _TEXTURE_H_ -#define _TEXTURE_H_ - -#include "Types.h" -#include "Pkgs/glew.h" //arg - -namespace New3D { - -#define TEXTURE_DEBUG 0x8 -#define TEXTURE_DEBUG_MASK 0x7 - -class Texture -{ -public: - - Texture(); - ~Texture(); - - UINT32 UploadTexture (const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height); - void DeleteTexture (); - void BindTexture (); - void GetCoordinates (UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut); - void GetDetails (int& x, int&y, int& width, int& height, int& format); - void SetWrapMode (bool mirrorU, bool mirrorV); - - static void GetCoordinates(bool mirror, int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut); - -private: - - void Reset(); - - int m_x; - int m_y; - int m_width; - int m_height; - int m_format; - bool m_mirrorU; - bool m_mirrorV; - GLuint m_textureID; -}; - -} // New3D - -#endif diff --git a/Src/Graphics/New3D/backup/VBO.cpp b/Src/Graphics/New3D/backup/VBO.cpp deleted file mode 100644 index 364bd24..0000000 --- a/Src/Graphics/New3D/backup/VBO.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "VBO.h" - -namespace New3D { - -VBO::VBO() -{ - m_id = 0; - m_target = 0; - m_capacity = 0; - m_size = 0; -} - -void VBO::Create(GLenum target, GLenum usage, GLsizeiptr size, const void* data) -{ - glGenBuffers(1, &m_id); // create a vbo - glBindBuffer(target, m_id); // activate vbo id to use - glBufferData(target, size, data, usage); // upload data to video card - - m_target = target; - m_capacity = size; - m_size = 0; - - Bind(false); // unbind -} - -void VBO::BufferSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) -{ - glBufferSubData(m_target, offset, size, data); -} - -bool VBO::AppendData(GLsizeiptr size, const GLvoid* data) -{ - if (size == 0 || !data) { - return true; // nothing to do - } - - if (m_size + size >= m_capacity) { - return false; - } - - BufferSubData(m_size, size, data); - - m_size += size; - - return true; -} - -void VBO::Reset() -{ - m_size = 0; -} - -void VBO::Destroy() -{ - if (m_id) { - glDeleteBuffers(1, &m_id); - m_id = 0; - m_target = 0; - m_capacity = 0; - m_size = 0; - } -} - -void VBO::Bind(bool enable) -{ - if (enable) { - glBindBuffer(m_target, m_id); - } - else { - glBindBuffer(m_target, 0); - } -} - -int VBO::GetSize() -{ - return m_size; -} - -int VBO::GetCapacity() -{ - return m_capacity; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/bounding box code/Mat4.h b/Src/Graphics/New3D/backup/bounding box code/Mat4.h deleted file mode 100644 index e9aa647..0000000 --- a/Src/Graphics/New3D/backup/bounding box code/Mat4.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _MAT4_H_ -#define _MAT4_H_ - -#include - -namespace New3D { - -class Mat4 -{ -public: - - Mat4(); - - void LoadIdentity (); - void Translate (float x, float y, float z); - void Rotate (float angle, float x, float y, float z); - void Scale (float x, float y, float z); - void Frustum (float left, float right, float bottom, float top, float nearVal, float farVal); - void Ortho (float left, float right, float bottom, float top, float nearVal, float farVal); - void Perspective (float fovy, float aspect, float zNear, float zFar); - void MultMatrix (const float *m); - void LoadMatrix (const float *m); - void LoadTransposeMatrix (const float *m); - void MultTransposeMatrix (const float *m); - void PushMatrix (); - void PopMatrix (); - void Release (); - - operator const float* () { return currentMatrix; } - - float currentMatrix[16]; - - struct Mat4Container { - float mat[16]; // we must wrap the matrix inside a struct otherwise vector doesn't work - }; - - std::vector m_vMat4; -private: - - void MultiMatrices (const float a[16], const float b[16], float r[16]); - void Copy (const float in[16], float out[16]); - void Transpose (float m[16]); - - - - -}; - -} // New3D - -#endif - diff --git a/Src/Graphics/New3D/backup/bounding box code/New3D.cpp b/Src/Graphics/New3D/backup/bounding box code/New3D.cpp deleted file mode 100644 index b970df9..0000000 --- a/Src/Graphics/New3D/backup/bounding box code/New3D.cpp +++ /dev/null @@ -1,1315 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include -#include -#include - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes->empty()) { - continue; - } - - m_r3dShader.SetModelStates(&m); - - for (auto &mesh : *m.meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.textured) { - - int x, y; - CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y); - - auto tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height); - if (tex1) { - tex1->BindTexture(); - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - - if (mesh.microTexture) { - glActiveTexture(GL_TEXTURE1); - auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, 0, 1024, 128, 128); - if (tex2) { - tex2->BindTexture(); - } - glActiveTexture(GL_TEXTURE0); - } - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glDisable(GL_STENCIL_TEST); -} - -void CNew3D::DrawBoundingBoxes() -{ - glColor3ub(255, 255, 255); - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (m_nodes.size()) { - glViewport(m_nodes[0].viewport.x, m_nodes[0].viewport.y, m_nodes[0].viewport.width, m_nodes[0].viewport.height); - } - - for (auto &b : m_bBoxes) { - glLoadMatrixf(b.mat); - - //top - glBegin(GL_LINE_LOOP); - - for (int i = 0; i < 4; i++) { - glVertex3fv(b.points[i]); - } - - glEnd(); - - //bottom - - glBegin(GL_LINE_LOOP); - - for (int i = 4; i < 8; i++) { - glVertex3fv(b.points[i]); - } - - glEnd(); - - // pillars - glBegin(GL_LINES); - - glVertex3fv(b.points[0]); - glVertex3fv(b.points[4]); - - glVertex3fv(b.points[1]); - glVertex3fv(b.points[5]); - - glVertex3fv(b.points[2]); - glVertex3fv(b.points[6]); - - glVertex3fv(b.points[3]); - glVertex3fv(b.points[7]); - - glEnd(); - } -} - -void CNew3D::RenderFrame(void) -{ - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - m_bBoxes.clear(); - - glDepthFunc (GL_LEQUAL); - glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero - glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value - glStencilMask (0xFF); - - RenderViewport(0x800000); // build model structure - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - //check we haven't blown up the memory buffers - //we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway - if (m_polyBufferRom.size() >= MAX_ROM_POLYS) { - m_polyBufferRom.clear(); - m_romMap.clear(); - m_vbo.Reset(); - } - else { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - DrawBoundingBoxes(); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - bool cached = false; - Model* m; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - m_nodes.back().models.emplace_back(Model()); - - // get the last model in the array - m = &m_nodes.back().models.back(); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - // try to find meshes in the rom cache - - m->meshes = m_romMap[modelAddr]; // will create an entry with a null pointer if empty - - if (m->meshes) { - cached = true; - } - else { - m->meshes = std::make_shared>(); - m_romMap[modelAddr] = m->meshes; // store meshes in our rom map here - } - - m->dynamic = false; - } - else { - m->meshes = std::make_shared>(); - } - - // copy current model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - // update texture offsets - m->textureOffsetX = m_nodeAttribs.currentTexOffsetX; - m->textureOffsetY = m_nodeAttribs.currentTexOffsetY; - m->page = m_nodeAttribs.page; - - if (!cached) { - CacheModel(m, modelAddress); - } - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, child1Ptr, sibling2Ptr; - float x, y, z; - int tx, ty; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - child1Ptr = node[0x07 - m_offset] & 0x7FFFFFF; // mask colour table bits - sibling2Ptr = node[0x08 - m_offset] & 0x1FFFFFF; // mask colour table bits - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - float test = ToFloat(Convert16BitProFloat(node[9 - m_offset]&0xFFFF)); - - if (test > 100000) { - int debugb = 0; - } - - if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings - if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) { - DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero - } - } - - if ((node[0x00] & 0x04)) { - m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17); - m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range - } - - x = *(float *)&node[0x04 - m_offset]; - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x1F); - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.page = (node[0x02] & 0x4000) >> 14; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - - { - if (test < 10000000 ) { - BBox box; - //copy current matrix - - box.mat.LoadMatrix(m_modelMat); - CalcBox(test, box); - - m_bBoxes.emplace_back(box); - } - } - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(child1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(child1Ptr); - } - - m_modelMat.PopMatrix(); - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 2 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int index; - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - index = 0; - - while (true) { - - if (list[index] & 0x01000000) { - break; // empty list - } - - nodeAddr = list[index] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - DescendCullingNode(nodeAddr); - - if (list[index] & 0x02000000) { - break; // list end - } - - index++; - } -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - - mat.LoadMatrix(m); - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr) -{ - static const GLfloat color[8][3] = - { // RGB1 color translation - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - - // Translate address and obtain pointer - const uint32_t *vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - - if (!(vpnode[0] & 0x20)) { // only if viewport enabled - uint32_t curPri = (vpnode[0x00] >> 3) & 3; // viewport priority - uint32_t nodeAddr = vpnode[0x02]; // scene database node pointer - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - Viewport *vp = &m_nodes.back().viewport; - - vp->priority = curPri; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - int vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point) - int vpY = (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f); // viewport Y (12.4) - int vpWidth = (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f); // width (14.2) - int vpHeight = (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f); // height (14.2) - uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - if (vpX) { - vpX += 2; - } - - if (vpY) { - vpY += 2; - } - - LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]); - - float angle_left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]); - float angle_right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]); - float angle_top = atan2(*(float *)&vpnode[14], *(float *)&vpnode[15]); - float angle_bottom = -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]); - - float near = 0.25f; - float far = 2e6; - - if (m_step == 0x10) { - near = 8; - } - - float l = near * tanf(angle_left); - float r = near * tanf(angle_right); - float t = near * tanf(angle_top); - float b = near * tanf(angle_bottom); - - // TO-DO: investigate clipping near/far planes - - if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) - { - float windowAR = (float)m_totalXRes / (float)m_totalYRes; - float originalAR = 496 / 384.f; - float correction = windowAR / originalAR; // expand horizontal frustum planes - - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far); - } - else - { - vp->x = m_xOffs + (GLint)((float)vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = (GLint)((float)vpWidth*m_xRatio); - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l, r, b, t, near, far); - } - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = *(float *)&vpnode[0x23]; // fog density - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - float scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21>1.05) || (m21<0.95)) - return; - if ((m32>1.05) || (m32<0.95)) - return; - if ((m13>1.05) || (m13<0.95)) - return; - } - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); - } - - // render next viewport - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01]); - } -} - -void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - } -} - -// non smooth texturing on the pro-1000 seems to sample like gl_nearest -// ie not outside of the texture coordinates, but with bilinear filtering -// this is about as close as we can emulate in hardware -// if we don't do this with gl_repeat enabled, it will wrap around and sample the -// other side of the texture which produces ugly seems -void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]) -{ - for (int i = 0; i < 2; i++) { - - float min = std::numeric_limits::max(); - float max = -std::numeric_limits::max(); - - if (!offset[i]) continue; - - for (int j = 0; j < r3dPoly.number; j++) { - min = std::min(r3dPoly.v[j].texcoords[i], min); - max = std::max(r3dPoly.v[j].texcoords[i], max); - } - - float fTemp; - float iTemp; - bool fractMin; - bool fractMax; - - fTemp = std::modf(min, &iTemp); - fractMin = fTemp > 0; - - fTemp = std::modf(max, &iTemp); - fractMax = fTemp > 0; - - for (int j = 0; j < r3dPoly.number && min != max; j++) { - - if (!fractMin) { - if (r3dPoly.v[j].texcoords[i] == min) { - r3dPoly.v[j].texcoords[i] += offset[i]; - } - } - - if (!fractMax) { - if (r3dPoly.v[j].texcoords[i] == max) { - r3dPoly.v[j].texcoords[i] -= offset[i]; - } - } - } - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - do { - - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - - if (ph.header[6] == 0) { - break; - } - - if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) { - continue; - } - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(); - - if (hash != lastHash) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = false; // we will double up polys - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); - currentMesh->layered = ph.Layered(); - - if (currentMesh->lighting) { - if (ph.SpecularEnabled()) { - currentMesh->specular = true; - currentMesh->shininess = 0;// ph.Shininess(); - currentMesh->specularCoefficient = 0; // ph.SpecularValue(); - } - } - - currentMesh->fogIntensity = ph.LightModifier(); - - if (ph.TexEnabled()) { - currentMesh->format = m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest()); - - if (currentMesh->format == 7) { - currentMesh-> alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency - } - - currentMesh->x = ph.X(); - currentMesh->y = ph.Y(); - currentMesh->width = ph.TexWidth(); - currentMesh->height = ph.TexHeight(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - currentMesh->microTexture = ph.MicroTexture(); - } - } - - currentMesh = &sMap[hash]; - } - - lastHash = hash; - - // Obtain basic polygon parameters - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - // copy face attributes - - if ((ph.header[1] & 2) == 0) { - int colorIdx = ph.ColorIndex(); - p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; - p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; - p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; - } - else { - if (ph.ColorDisabled()) { // no colours were set - p.faceColour[0] = 1.0f; - p.faceColour[1] = 1.0f; - p.faceColour[2] = 1.0f; - } - else { - p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; - p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; - p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; - } - } - - p.faceColour[3] = ph.Transparency() / 255.f; - - // if we have flat shading, we can't re-use normals from shared vertices - for (i = 0; i < p.number && !ph.SmoothShading(); i++) { - p.v[i].normal[0] = p.faceNormal[0]; - p.v[i].normal[1] = p.faceNormal[1]; - p.v[i].normal[2] = p.faceNormal[2]; - } - - UINT32* vData = ph.StartOfData(); // vertex data starts here - - // remaining vertices are new and defined here - for (; j < p.number; j++) - { - // Fetch vertices - UINT32 ix = vData[0]; - UINT32 iy = vData[1]; - UINT32 iz = vData[2]; - UINT32 it = vData[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - // Per vertex normals - if (ph.SmoothShading()) { - p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f; - p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f; - p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f; - } - - if (ph.FixedShading() && ph.LightEnabled()) { - UINT8 shade = (UINT8)((ix + 128) & 0xFF); - p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - p.v[j].color[3] = 255; - } - else { - p.v[j].color[0] = 255; - p.v[j].color[1] = 255; - p.v[j].color[2] = 255; - p.v[j].color[3] = 255; - } - - float texU, texV = 0; - - // tex coords - if (currentMesh->textured) { - Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - vData += 4; - } - - // check if we need to modify the texture coordinates - { - float offset[2] = { 0 }; - - if (ph.TexEnabled()) { - - if (!ph.TexSmoothU() && !ph.TexUMirror()) { - offset[0] = 0.5f / ph.TexWidth(); // half texel - } - - if (!ph.TexSmoothV() && !ph.TexVMirror()) { - offset[1] = 0.5f / ph.TexHeight(); // half texel - } - - OffsetTexCoords(p, offset); - } - } - - // check if we need double up vertices for two sided lighting - if (ph.DoubleSided()) { - - R3DPoly tempP = p; - - // flip normals - V3::inverse(tempP.faceNormal); - - for (int i = 0; i < tempP.number; i++) { - V3::inverse(tempP.v[i].normal); - } - - CopyVertexData(tempP, currentMesh->polys); - } - - // Copy this polygon into the model buffer - CopyVertexData(p, currentMesh->polys); - numPolys++; - - // Copy current vertices into previous vertex array - for (i = 0; i < 4; i++) { - prev[i] = p.v[i]; - } - - } while (ph.NextPoly()); - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes->reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes->push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY) -{ - newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required - - int oldPage = y / 1024; - - y -= (oldPage * 1024); // remove page from tex y - - // calc newY with wrap around, wraps around in the same sheet, not into another memory sheet - - newY = (y + offY) & 1023; - - // add page to Y - - newY += ((oldPage + page) & 1) * 1024; // max page 0-1 -} - -UINT32 CNew3D::ConvertProFloat(UINT32 a1) -{ - int exponent = (a1 & 0x7E000000) >> 25; - - if (exponent <= 31) { // positive - exponent += 127; - } - else { // negative exponent - exponent -= 64; - exponent += 127; - } - - int mantissa = (a1 & 0x1FFFFFF) >> 2; - - return (a1 & 0x80000000) | (exponent << 23) | mantissa; -} - -UINT32 CNew3D::Convert16BitProFloat(UINT32 a1) -{ - return ConvertProFloat(a1 << 15); -} - -float CNew3D::ToFloat(UINT32 a1) -{ - return *(float*)(&a1); -} - -void CNew3D::CalcBox(float distance, BBox& box) -{ - //bottom - box.points[0][0] = -distance; - box.points[0][1] = -distance; - box.points[0][2] = distance; - - box.points[1][0] = -distance; - box.points[1][1] = -distance; - box.points[1][2] = -distance; - - box.points[2][0] = distance; - box.points[2][1] = -distance; - box.points[2][2] = -distance; - - box.points[3][0] = distance; - box.points[3][1] = -distance; - box.points[3][2] = distance; - - //top - box.points[4][0] = -distance; - box.points[4][1] = distance; - box.points[4][2] = distance; - - box.points[5][0] = -distance; - box.points[5][1] = distance; - box.points[5][2] = -distance; - - box.points[6][0] = distance; - box.points[6][1] = distance; - box.points[6][2] = -distance; - - box.points[7][0] = distance; - box.points[7][1] = distance; - box.points[7][2] = distance; -} - -} // New3D - diff --git a/Src/Graphics/New3D/backup/bounding box code/New3D.h b/Src/Graphics/New3D/backup/bounding box code/New3D.h deleted file mode 100644 index b558a13..0000000 --- a/Src/Graphics/New3D/backup/bounding box code/New3D.h +++ /dev/null @@ -1,237 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" -#include "R3DData.h" -#include "Vec.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr); - void DrawBoundingBoxes(); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray); - void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - - void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY); - - UINT32 ConvertProFloat(UINT32 a1); // return float in hex or integer format - UINT32 Convert16BitProFloat(UINT32 a1); - float ToFloat(UINT32 a1); // integer float to actual IEEE 754 float - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - - std::vector m_nodes; // this represents the entire render frame - std::vector m_polyBufferRam; // dynamic polys - std::vector m_polyBufferRom; // rom polys - std::unordered_map>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet - - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - R3DShader m_r3dShader; - - struct BBox - { - V3::Vec3 points[8]; - Mat4 mat; - }; - - void CalcBox(float distance, BBox& box); - - std::vector m_bBoxes; -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/Model.h b/Src/Graphics/New3D/backup/clipping plane attempt/Model.h deleted file mode 100644 index aa49076..0000000 --- a/Src/Graphics/New3D/backup/clipping plane attempt/Model.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef _MODEL_H_ -#define _MODEL_H_ - -#include "Types.h" -#include -#include -#include -#include -#include "Texture.h" -#include "Mat4.h" - -namespace New3D { - -struct Vertex -{ - float pos[3]; - float normal[3]; - float texcoords[2]; - float color[4]; //rgba -}; - -struct Poly // our polys are always 3 triangles, unlike the real h/w -{ - Vertex p1; - Vertex p2; - Vertex p3; -}; - -struct R3DPoly -{ - Vertex v[4]; // just easier to have them as an array - float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself - float faceColour[4]; // per face colour - int number = 4; -}; - -struct Mesh -{ - // texture - int format, x, y, width, height = 0; - bool microTexture = false; - int microTextureID = 0; - bool mirrorU = false; - bool mirrorV = false; - - // attributes - bool doubleSided = false; - bool textured = false; - bool polyAlpha = false; // specified in the rgba colour - bool textureAlpha = false; // use alpha in texture - bool alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function) - bool clockWise = true; // we need to check if the matrix will change the winding - bool layered = false; // stencil poly - - // lighting - bool lighting = false; - bool specular = false; - float shininess = 0; - float specularCoefficient = 0; - - // fog - float fogIntensity = 1.0f; - - // opengl resources - int vboOffset = 0; // this will be calculated later - int triangleCount = 0; -}; - -struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer -{ - std::vector polys; -}; - -struct Model -{ - std::shared_ptr> meshes; // this reason why this is a shared ptr to an array, is that multiple models might use the same meshes - - //which memory are we in - bool dynamic = true; - - // texture offsets for model - int textureOffsetX = 0; - int textureOffsetY = 0; - int page = 0; - - //matrices - float modelMat[16]; - float determinant; // we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order -}; - -struct Viewport -{ - int vpX, vpY, vpWidth, vpHeight;// real3d viewport paramaters - float left, right, bottom, top; // angles for projection matrix - near/far calculated later - - Mat4 projectionMatrix; // projection matrix - float lightingParams[6]; // lighting parameters (see RenderViewport() and vertex shader) - float spotEllipse[4]; // spotlight ellipse (see RenderViewport()) - float spotRange[2]; // Z range - float spotColor[3]; // color - float fogParams[5]; // fog parameters (...) - float scrollFog; // a transparency value that determines if fog is blended over the bottom 2D layer - int x, y; // viewport coordinates (scaled and in OpenGL format) - int width, height; // viewport dimensions (scaled for display surface size) - int priority; -}; - -enum class Clip { INSIDE, OUTSIDE, INTERCEPT }; - -class NodeAttributes -{ -public: - - NodeAttributes(); - - bool Push(); - bool Pop(); - bool StackLimit(); - void Reset(); - - int currentTexOffsetX; - int currentTexOffsetY; - int currentPage; - Clip currentClipStatus; - -private: - - struct NodeAttribs - { - int texOffsetX; - int texOffsetY; - int page; - Clip clip; - }; - std::vector m_vecAttribs; -}; - -struct Node -{ - Viewport viewport; - std::vector models; -}; - -} // New3D - - -#endif \ No newline at end of file diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp b/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp deleted file mode 100644 index a066b3f..0000000 --- a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp +++ /dev/null @@ -1,1431 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include -#include -#include -#include "R3DFloat.h" - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - if (x >= 1024) { - if (y >= 512 && y < 1024 || y >= 1536 && y < 2048) { - return; - } - } - - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::DrawScrollFog() -{ - for (int i = 0; i < 4; i++) { - - for (auto &n : m_nodes) { - - if (n.viewport.scrollFog > 0 && n.viewport.priority==i) { - - float *rgb = n.viewport.fogParams; - m_r3dScrollFog.DrawScrollFog(rgb[0], rgb[1], rgb[2], n.viewport.scrollFog); - - return; // only allowed once per frame? - } - } - } -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - std::shared_ptr tex1; - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes->empty()) { - continue; - } - - m_r3dShader.SetModelStates(&m); - - for (auto &mesh : *m.meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.textured) { - - int x, y; - CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y); - - if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) { - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - else { - tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height); - if (tex1) { - tex1->BindTexture(); - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - } - - if (mesh.microTexture) { - - int mX, mY; - glActiveTexture(GL_TEXTURE1); - m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY); - auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128); - if (tex2) { - tex2->BindTexture(); - } - glActiveTexture(GL_TEXTURE0); - } - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glDisable(GL_STENCIL_TEST); -} - -void CNew3D::RenderFrame(void) -{ - // reset our min/max near/far planes - for (int i = 0; i < 4; i++) { - m_nfPair[i].nearVal = std::numeric_limits::max(); - m_nfPair[i].farVal = 0; - } - - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - - RenderViewport(0x800000); // build model structure - CalcViewports(); // calculate derived frustum paramaters - DrawScrollFog(); // fog layer if applicable must be drawn here - - glDepthFunc (GL_LEQUAL); - glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero - glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value - glStencilMask (0xFF); - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - //check we haven't blown up the memory buffers - //we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway - if (m_polyBufferRom.size() >= MAX_ROM_POLYS) { - m_polyBufferRom.clear(); - m_romMap.clear(); - m_vbo.Reset(); - } - else { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - for (int i = 0; i < 4; i++) { - printf("index %i - pair %f %f\n", i, m_nfPair[i].nearVal, m_nfPair[i].farVal); - } - printf("\n"); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - bool cached = false; - Model* m; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - m_nodes.back().models.emplace_back(Model()); - - // get the last model in the array - m = &m_nodes.back().models.back(); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - // try to find meshes in the rom cache - - m->meshes = m_romMap[modelAddr]; // will create an entry with a null pointer if empty - - if (m->meshes) { - cached = true; - } - else { - m->meshes = std::make_shared>(); - m_romMap[modelAddr] = m->meshes; // store meshes in our rom map here - } - - m->dynamic = false; - } - else { - m->meshes = std::make_shared>(); - } - - // copy current model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - // update texture offsets - m->textureOffsetX = m_nodeAttribs.currentTexOffsetX; - m->textureOffsetY = m_nodeAttribs.currentTexOffsetY; - m->page = m_nodeAttribs.currentPage; - - if (!cached) { - CacheModel(m, modelAddress); - } - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, child1Ptr, sibling2Ptr; - float x, y, z; - int tx, ty; - BBox bbox; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - child1Ptr = node[0x07 - m_offset] & 0x7FFFFFF; // mask colour table bits - sibling2Ptr = node[0x08 - m_offset] & 0x1FFFFFF; // mask colour table bits - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings - if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) { - DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero - } - } - - if ((node[0x00] & 0x04)) { - m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17); - m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range - } - - x = *(float *)&node[0x04 - m_offset]; - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x1F); - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - if (m_nodeAttribs.currentClipStatus != Clip::INSIDE && !(node[0] & 0x1) && !(node[0] & 0x4)) { // and not root node and not colour table - - float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF); - - if (distance > 1e-7) { // seems to be some 16bit float min value which probably says no values here, im guessing - m_nfPair[m_currentPriority].nearVal = std::min(distance, m_nfPair[m_currentPriority].nearVal); - } - - CalcBox(distance, bbox); - TransformBox(m_modelMat, bbox); - GetBBMaxZ(m_nfPair[m_currentPriority].farVal, bbox); - - m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes); - } - - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) { - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(child1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(child1Ptr); - } - - } - - m_modelMat.PopMatrix(); - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 2 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int index; - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - index = 0; - - while (true) { - - if (list[index] & 0x01000000) { - break; // empty list - } - - nodeAddr = list[index] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - DescendCullingNode(nodeAddr); - - if (list[index] & 0x02000000) { - break; // list end - } - - index++; - } -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - mat.LoadMatrix(m); - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr) -{ - static const GLfloat color[8][3] = - { // RGB1 color translation - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - - // Translate address and obtain pointer - const uint32_t *vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - - if (!(vpnode[0] & 0x20)) { // only if viewport enabled - - uint32_t nodeAddr = vpnode[0x02]; // scene database node pointer - uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - Viewport *vp = &m_nodes.back().viewport; - - vp->priority = (vpnode[0x00] >> 3) & 3; // viewport priority - m_currentPriority = vp->priority; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - vp->vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point) - vp->vpY = (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f); // viewport Y (12.4) - vp->vpWidth = (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f); // width (14.2) - vp->vpHeight = (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f); // height (14.2) - - if (vp->vpX) { - vp->vpX += 2; // bit of a hack but seems to work - } - - if (vp->vpY) { - vp->vpY += 2; - } - - LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]); - - vp->left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]); - vp->right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]); - vp->top = atan2(*(float *)&vpnode[14], *(float *)&vpnode[15]); - vp->bottom = -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]); - - // calculate frustum planes - CalcFrustumPlanes(m_planes, (float *)&vpnode[12]); - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - - if (vp->spotRange[1] == 0) { // if light extent = 0 light is effectively disabled - spotColorIdx = 0; - } - - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = std::abs(*(float *)&vpnode[0x23]); // fog density - ocean hunter uses negative values, but looks the same - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - vp->scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - - { - //test fog paramaters - float lightFogColour[3]; - int fogColourIdx; - - fogColourIdx = (vpnode[0x20] >> 8) & 7; - - lightFogColour[0] = color[fogColourIdx][0]; - lightFogColour[1] = color[fogColourIdx][1]; - lightFogColour[2] = color[fogColourIdx][2]; - - float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f; - float fogAmbient = ((vpnode[0x25] >> 16) & 0xFF) / 255.f; - int debug = 0; - } - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21 > 1.05) || (m21 < 0.95)) - return; - if ((m32 > 1.05) || (m32 < 0.95)) - return; - if ((m13 > 1.05) || (m13 < 0.95)) - return; - } - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); - } - - // render next viewport - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01]); - } -} - -void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; - p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; - p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i]; - p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i]; - p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i]; - } - - polyArray.emplace_back(p); - } -} - -// non smooth texturing on the pro-1000 seems to sample like gl_nearest -// ie not outside of the texture coordinates, but with bilinear filtering -// this is about as close as we can emulate in hardware -// if we don't do this with gl_repeat enabled, it will wrap around and sample the -// other side of the texture which produces ugly seems -void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]) -{ - for (int i = 0; i < 2; i++) { - - float min = std::numeric_limits::max(); - float max = -std::numeric_limits::max(); - - if (!offset[i]) continue; - - for (int j = 0; j < r3dPoly.number; j++) { - min = std::min(r3dPoly.v[j].texcoords[i], min); - max = std::max(r3dPoly.v[j].texcoords[i], max); - } - - float fTemp; - float iTemp; - bool fractMin; - bool fractMax; - - fTemp = std::modf(min, &iTemp); - fractMin = fTemp > 0; - - fTemp = std::modf(max, &iTemp); - fractMax = fTemp > 0; - - for (int j = 0; j < r3dPoly.number && min != max; j++) { - - if (!fractMin) { - if (r3dPoly.v[j].texcoords[i] == min) { - r3dPoly.v[j].texcoords[i] += offset[i]; - } - } - - if (!fractMax) { - if (r3dPoly.v[j].texcoords[i] == max) { - r3dPoly.v[j].texcoords[i] -= offset[i]; - } - } - } - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - do { - - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - - if (ph.header[6] == 0) { - break; - } - - if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) { - continue; - } - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(); - - if (hash != lastHash) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = false; // we will double up polys - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); - - if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) { - currentMesh->layered = true; - } - - if (currentMesh->lighting) { - if (ph.SpecularEnabled()) { - currentMesh->specular = true; - currentMesh->shininess = 0;// ph.Shininess(); - currentMesh->specularCoefficient = 0; // ph.SpecularValue(); - } - } - - currentMesh->fogIntensity = ph.LightModifier(); - - if (ph.TexEnabled()) { - currentMesh->format = m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest()); - - if (currentMesh->format == 7) { - currentMesh-> alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency - } - - currentMesh->x = ph.X(); - currentMesh->y = ph.Y(); - currentMesh->width = ph.TexWidth(); - currentMesh->height = ph.TexHeight(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - currentMesh->microTexture = ph.MicroTexture(); - currentMesh->microTextureID = ph.MicroTextureID(); - } - } - - currentMesh = &sMap[hash]; - } - - lastHash = hash; - - // Obtain basic polygon parameters - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - // copy face attributes - - if ((ph.header[1] & 2) == 0) { - int colorIdx = ph.ColorIndex(); - p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; - p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; - p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; - } - else { - if (ph.ColorDisabled()) { // no colours were set - p.faceColour[0] = 1.0f; - p.faceColour[1] = 1.0f; - p.faceColour[2] = 1.0f; - } - else { - p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; - p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; - p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; - } - } - - p.faceColour[3] = ph.Transparency() / 255.f; - - // if we have flat shading, we can't re-use normals from shared vertices - for (i = 0; i < p.number && !ph.SmoothShading(); i++) { - p.v[i].normal[0] = p.faceNormal[0]; - p.v[i].normal[1] = p.faceNormal[1]; - p.v[i].normal[2] = p.faceNormal[2]; - } - - UINT32* vData = ph.StartOfData(); // vertex data starts here - - // remaining vertices are new and defined here - for (; j < p.number; j++) - { - // Fetch vertices - UINT32 ix = vData[0]; - UINT32 iy = vData[1]; - UINT32 iz = vData[2]; - UINT32 it = vData[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - // Per vertex normals - if (ph.SmoothShading()) { - p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f; - p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f; - p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f; - } - - if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) { // fixed shading seems to be disabled if actual normals are set - float offset = !ph.LightEnabled() ? 1.f : 0.f; // if lighting is disabled colour seems to be an offset - float shade = (((ix + 128) & 0xFF) / 255.f) + offset; - p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - p.v[j].color[3] = 1; - } - else { - p.v[j].color[0] = 1; - p.v[j].color[1] = 1; - p.v[j].color[2] = 1; - p.v[j].color[3] = 1; - } - - float texU, texV = 0; - - // tex coords - if (currentMesh->textured) { - Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - vData += 4; - } - - // check if we need to modify the texture coordinates - { - float offset[2] = { 0 }; - - if (ph.TexEnabled()) { - - if (!ph.TexSmoothU() && !ph.TexUMirror()) { - offset[0] = 0.5f / ph.TexWidth(); // half texel - } - - if (!ph.TexSmoothV() && !ph.TexVMirror()) { - offset[1] = 0.5f / ph.TexHeight(); // half texel - } - - OffsetTexCoords(p, offset); - } - } - - // check if we need double up vertices for two sided lighting - if (ph.DoubleSided()) { - - R3DPoly tempP = p; - - // flip normals - V3::inverse(tempP.faceNormal); - - for (int i = 0; i < tempP.number; i++) { - V3::inverse(tempP.v[i].normal); - } - - CopyVertexData(tempP, currentMesh->polys); - } - - // Copy this polygon into the model buffer - CopyVertexData(p, currentMesh->polys); - numPolys++; - - // Copy current vertices into previous vertex array - for (i = 0; i < 4; i++) { - prev[i] = p.v[i]; - } - - } while (ph.NextPoly()); - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes->reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes->push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY) -{ - newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required - - int oldPage = y / 1024; - - y -= (oldPage * 1024); // remove page from tex y - - // calc newY with wrap around, wraps around in the same sheet, not into another memory sheet - - newY = (y + offY) & 1023; - - // add page to Y - - newY += ((oldPage + page) & 1) * 1024; // max page 0-1 -} - -void CNew3D::CalcFrustumPlanes(Plane p[5], const float *vpNodeData) -{ - // Left Plane - p[0].a = vpNodeData[1]; - p[0].b = 0; - p[0].c = -vpNodeData[0]; - p[0].d = 0; - - // Top Plane - p[1].a = 0; - p[1].b = vpNodeData[3]; - p[1].c = -vpNodeData[2]; - p[1].d = 0; - - // Right Plane - p[2].a = vpNodeData[5]; - p[2].b = 0; - p[2].c = -vpNodeData[4]; - p[2].d = 0; - - // Bottom Plane - p[3].a = 0; - p[3].b = vpNodeData[7]; - p[3].c = -vpNodeData[6]; - p[3].d = 0; - - // Near Plane - p[4].a = 0; - p[4].b = 0; - p[4].c = -1; - p[4].d = 0; -} - -void CNew3D::CalcBox(float distance, BBox& box) -{ - //bottom left front - box.points[0][0] = -distance; - box.points[0][1] = -distance; - box.points[0][2] = distance; - box.points[0][3] = 1; - - //bottom left back - box.points[1][0] = -distance; - box.points[1][1] = -distance; - box.points[1][2] = -distance; - box.points[1][3] = 1; - - //bottom right back - box.points[2][0] = distance; - box.points[2][1] = -distance; - box.points[2][2] = -distance; - box.points[2][3] = 1; - - //bottom right front - box.points[3][0] = distance; - box.points[3][1] = -distance; - box.points[3][2] = distance; - box.points[3][3] = 1; - - //top left front - box.points[4][0] = -distance; - box.points[4][1] = distance; - box.points[4][2] = distance; - box.points[4][3] = 1; - - //top left back - box.points[5][0] = -distance; - box.points[5][1] = distance; - box.points[5][2] = -distance; - box.points[5][3] = 1; - - //top right back - box.points[6][0] = distance; - box.points[6][1] = distance; - box.points[6][2] = -distance; - box.points[6][3] = 1; - - //top right front - box.points[7][0] = distance; - box.points[7][1] = distance; - box.points[7][2] = distance; - box.points[7][3] = 1; -} - -void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) -{ - for (int i = 0; i < 4; i++) { - out[i] = - in[0] * matrix[0 * 4 + i] + - in[1] * matrix[1 * 4 + i] + - in[2] * matrix[2 * 4 + i] + - in[3] * matrix[3 * 4 + i]; - } -} - -void CNew3D::TransformBox(const float *m, BBox& box) -{ - for (int i = 0; i < 8; i++) { - float v[4]; - MultVec(m, box.points[i], v); - box.points[i][0] = v[0]; - box.points[i][1] = v[1]; - box.points[i][2] = v[2]; - } -} - -Clip CNew3D::ClipBox(BBox& box, Plane planes[6]) -{ - int count = 0; - - for (int i = 0; i < 8; i++) { - - int temp = 0; - - for (int j = 0; j < 5; j++) { - if (planes[j].DistanceToPoint(box.points[i]) >= 0) { - temp++; - } - } - - if (temp == 5) count++; // point is inside all 6 frustum planes - } - - if (count == 8) return Clip::INSIDE; - if (count > 0) return Clip::INTERCEPT; - - //if we got here all points are outside of the view frustum - //check for all points being side same of any plane, means box outside of view - - for (int i = 0; i < 5; i++) { - - int temp = 0; - - for (int j = 0; j < 8; j++) { - if (planes[i].DistanceToPoint(box.points[j]) >= 0) { - float distance = planes[i].DistanceToPoint(box.points[j]); - temp++; - } - } - - if (temp == 0) return Clip::OUTSIDE; - } - - //if we got here, box is traversing view frustum - - return Clip::INTERCEPT; -} - -void CNew3D::GetBBMaxZ(float &compare, BBox &box) -{ - for (int i = 0; i < 8; i++) { - compare = std::max(compare, std::abs(box.points[i][2])); - } -} - -void CNew3D::CalcViewports() -{ - for (auto &n : m_nodes) { - - auto *vp = &n.viewport; - - float near = m_nfPair[vp->priority].nearVal * 0.5f; - float far = m_nfPair[vp->priority].farVal; - - float l = near * tanf(vp->left); - float r = near * tanf(vp->right); - float t = near * tanf(vp->top); - float b = near * tanf(vp->bottom); - - if ((vp->vpX == 0) && (vp->vpWidth >= 495) && (vp->vpY == 0) && (vp->vpHeight >= 383)) - { - float windowAR = (float)m_totalXRes / (float)m_totalYRes; - float originalAR = 496 / 384.f; - float correction = windowAR / originalAR; // expand horizontal frustum planes - - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vp->vpY + vp->vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vp->vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far); - } - else - { - vp->x = m_xOffs + (GLint)((float)vp->vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vp->vpY + vp->vpHeight))*m_yRatio); - vp->width = (GLint)((float)vp->vpWidth*m_xRatio); - vp->height = (GLint)((float)vp->vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l, r, b, t, near, far); - } - - } -} - -} // New3D - diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h b/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h deleted file mode 100644 index f5a5aa3..0000000 --- a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h +++ /dev/null @@ -1,252 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" -#include "R3DData.h" -#include "Plane.h" -#include "Vec.h" -#include "R3DScrollFog.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr); - void CalcViewports(); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray); - void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - void DrawScrollFog(); - - void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY); - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - - std::vector m_nodes; // this represents the entire render frame - std::vector m_polyBufferRam; // dynamic polys - std::vector m_polyBufferRom; // rom polys - std::unordered_map>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet - - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - R3DShader m_r3dShader; - R3DScrollFog m_r3dScrollFog; - - Plane m_planes[5]; - - struct NFPair - { - float nearVal; - float farVal; - }; - - NFPair m_nfPair[4]; // near/far value for each priority layer - int m_currentPriority; - - struct BBox - { - V4::Vec4 points[8]; - }; - - void CalcFrustumPlanes (Plane p[6], const float *vpNodeData); - void CalcBox (float distance, BBox& box); - void TransformBox (const float *m, BBox& box); - void MultVec (const float matrix[16], const float in[4], float out[4]); - Clip ClipBox (BBox& box, Plane planes[6]); - void GetBBMaxZ (float &compare, BBox &box); - - float m_minTest; -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H diff --git a/Src/Graphics/New3D/backup/lost world debug/New3D.cpp b/Src/Graphics/New3D/backup/lost world debug/New3D.cpp deleted file mode 100644 index 7d94e18..0000000 --- a/Src/Graphics/New3D/backup/lost world debug/New3D.cpp +++ /dev/null @@ -1,1516 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include -#include -#include -#include "R3DFloat.h" - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::DrawScrollFog() -{ - for (int i = 0; i < 4; i++) { - - for (auto &n : m_nodes) { - - if (n.viewport.scrollFog > 0 && n.viewport.priority==i) { - - float *rgb = n.viewport.fogParams; - m_r3dScrollFog.DrawScrollFog(rgb[0], rgb[1], rgb[2], n.viewport.scrollFog); - - return; // only allowed once per frame? - } - } - } -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - if (n.viewport.priority == 3) { - //return; - } - - std::shared_ptr tex1; - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - int modelIndex = 0; - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes->empty()) { - continue; - } - - - m_r3dShader.SetModelStates(&m); - - for (auto &mesh : *m.meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.textured) { - - int x, y; - CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y); - - if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) { - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - else { - tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height); - if (tex1) { - tex1->BindTexture(); - tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - } - - if (mesh.microTexture) { - - int mX, mY; - glActiveTexture(GL_TEXTURE1); - m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY); - auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128); - if (tex2) { - tex2->BindTexture(); - } - glActiveTexture(GL_TEXTURE0); - } - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset * 3, mesh.triangleCount * 3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glDisable(GL_STENCIL_TEST); -} - -void CNew3D::TestDraw() -{ - for (auto &n : m_nodes) { - - glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(n.viewport.projectionMatrix); - glMatrixMode(GL_MODELVIEW); - - int modelIndex = 0; - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes->empty()) { - continue; - } - - - for (auto &mesh : *m.meshes) { - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - - printf("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f \n\n", - m.modelMat[0], m.modelMat[1], m.modelMat[2], m.modelMat[3], - m.modelMat[4], m.modelMat[5], m.modelMat[6], m.modelMat[7], - m.modelMat[8], m.modelMat[8], m.modelMat[10], m.modelMat[11], - m.modelMat[12], m.modelMat[13], m.modelMat[14], m.modelMat[15]); - } - - - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset * 3, mesh.triangleCount * 3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - glDisable(GL_STENCIL_TEST); - -} - -void CNew3D::RenderFrame(void) -{ - //glClear(GL_COLOR_BUFFER_BIT); - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - - RenderViewport(0x800000); // build model structure - - DrawScrollFog(); // fog layer if applicable must be drawn here - - glDepthFunc (GL_LEQUAL); - //glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - //glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - glStencilFunc (GL_EQUAL, 0, 0xFF); // basically stencil test passes if the value is zero - glStencilOp (GL_KEEP, GL_INCR, GL_INCR); // if the stencil test passes, we incriment the value - glStencilMask (0xFF); - - glUseProgram(0); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-10, 10, -10, 10, -10, 10); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glPointSize(10); - glDisable(GL_TEXTURE_2D); - glColor3f(1, 0, 0); - - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - //check we haven't blown up the memory buffers - //we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway - if (m_polyBufferRom.size() >= MAX_ROM_POLYS) { - m_polyBufferRom.clear(); - m_romMap.clear(); - m_vbo.Reset(); - } - else { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - for (auto &n : m_nodes) { - - //glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode(GL_PROJECTION); - //glLoadMatrixf(n.viewport.projectionMatrix); - glOrtho(-10, 10, -10, 10, -100, 100); - glMatrixMode(GL_MODELVIEW); - - for (auto &m : n.models) { - - glLoadMatrixf(m.modelMat); - - printf("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f \n\n", - m.modelMat[0], m.modelMat[1], m.modelMat[2], m.modelMat[3], - m.modelMat[4], m.modelMat[5], m.modelMat[6], m.modelMat[7], - m.modelMat[8], m.modelMat[8], m.modelMat[10], m.modelMat[11], - m.modelMat[12], m.modelMat[13], m.modelMat[14], m.modelMat[15]); - - for (auto &mesh : *m.meshes) { - glDrawArrays(GL_POINTS, mesh.vboOffset * 3, mesh.triangleCount * 3); // times 3 to convert triangles to vertices - } - } - - } - - m_vbo.Bind(false); - - return; - - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - bool cached = false; - Model* m; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - m_nodes.back().models.emplace_back(Model()); - - // get the last model in the array - m = &m_nodes.back().models.back(); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - // try to find meshes in the rom cache - - m->meshes = m_romMap[modelAddr]; // will create an entry with a null pointer if empty - - if (m->meshes) { - cached = true; - } - else { - m->meshes = std::make_shared>(); - m_romMap[modelAddr] = m->meshes; // store meshes in our rom map here - } - - m->dynamic = false; - } - else { - m->meshes = std::make_shared>(); - } - - // copy current model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - // update texture offsets - m->textureOffsetX = m_nodeAttribs.currentTexOffsetX; - m->textureOffsetY = m_nodeAttribs.currentTexOffsetY; - m->page = m_nodeAttribs.currentPage; - - if (!cached) { - CacheModel(m, modelAddress); - } - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, child1Ptr, sibling2Ptr; - float x, y, z; - int tx, ty; - BBox bbox; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - child1Ptr = node[0x07 - m_offset] & 0x7FFFFFF; // mask colour table bits - sibling2Ptr = node[0x08 - m_offset] & 0x1FFFFFF; // mask colour table bits - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings - if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) { - DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero - } - } - - if ((node[0x00] & 0x04)) { - m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17); - m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range - } - - x = *(float *)&node[0x04 - m_offset]; - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x1F); - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) { - - float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF); - - CalcBox(distance, bbox); - TransformBox(m_modelMat, bbox); - - m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes); - } - - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) { - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(child1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(child1Ptr); - } - - } - - m_modelMat.PopMatrix(); - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 2 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int index; - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - index = 0; - - while (true) { - - if (list[index] & 0x01000000) { - break; // empty list - } - - nodeAddr = list[index] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - DescendCullingNode(nodeAddr); - - if (list[index] & 0x02000000) { - break; // list end - } - - index++; - } -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - mat.LoadMatrix(m); - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr) -{ - static const GLfloat color[8][3] = - { // RGB1 color translation - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - - // Translate address and obtain pointer - const uint32_t *vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - - if (!(vpnode[0] & 0x20)) { // only if viewport enabled - uint32_t curPri = (vpnode[0x00] >> 3) & 3; // viewport priority - uint32_t nodeAddr = vpnode[0x02]; // scene database node pointer - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - Viewport *vp = &m_nodes.back().viewport; - - vp->priority = curPri; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - int vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point) - int vpY = (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f); // viewport Y (12.4) - int vpWidth = (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f); // width (14.2) - int vpHeight = (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f); // height (14.2) - uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - if (vpX) { - vpX += 2; - } - - if (vpY) { - vpY += 2; - } - - LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]); - - float angle_left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]); - float angle_right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]); - float angle_top = atan2(*(float *)&vpnode[14], *(float *)&vpnode[15]); - float angle_bottom = -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]); - - float near = 0.25f; - float far = 2e6; - - if (m_step == 0x10) { - near = 8; - } - - float l = near * tanf(angle_left); - float r = near * tanf(angle_right); - float t = near * tanf(angle_top); - float b = near * tanf(angle_bottom); - - // TO-DO: investigate clipping near/far planes - - if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) - { - float windowAR = (float)m_totalXRes / (float)m_totalYRes; - float originalAR = 496 / 384.f; - float correction = windowAR / originalAR; // expand horizontal frustum planes - - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far); - } - else - { - vp->x = m_xOffs + (GLint)((float)vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = (GLint)((float)vpWidth*m_xRatio); - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Frustum(l, r, b, t, near, far); - } - - // calculate frustum planes - CalcFrustumPlanes(m_planes, vp->projectionMatrix); - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - int spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - - if (vp->spotRange[1] == 0) { // if light extent = 0 light is effectively disabled - spotColorIdx = 0; - } - - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = std::abs(*(float *)&vpnode[0x23]); // fog density - ocean hunter uses negative values, but looks the same - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - vp->scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - - { - //test fog paramaters - float lightFogColour[3]; - int fogColourIdx; - - fogColourIdx = (vpnode[0x20] >> 8) & 7; - - lightFogColour[0] = color[fogColourIdx][0]; - lightFogColour[1] = color[fogColourIdx][1]; - lightFogColour[2] = color[fogColourIdx][2]; - - float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f; - float fogAmbient = ((vpnode[0x25] >> 16) & 0xFF) / 255.f; - int debug = 0; - } - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21>1.05) || (m21<0.95)) - return; - if ((m32>1.05) || (m32<0.95)) - return; - if ((m13>1.05) || (m13<0.95)) - return; - } - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); - } - - // render next viewport - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01]); - } -} - -void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - //multiply face attributes with vertex attributes if required - for (int i = 0; i < 4; i++) { - p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]); - p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]); - p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]); - } - - polyArray.emplace_back(p); - } -} - -// non smooth texturing on the pro-1000 seems to sample like gl_nearest -// ie not outside of the texture coordinates, but with bilinear filtering -// this is about as close as we can emulate in hardware -// if we don't do this with gl_repeat enabled, it will wrap around and sample the -// other side of the texture which produces ugly seems -void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]) -{ - for (int i = 0; i < 2; i++) { - - float min = std::numeric_limits::max(); - float max = -std::numeric_limits::max(); - - if (!offset[i]) continue; - - for (int j = 0; j < r3dPoly.number; j++) { - min = std::min(r3dPoly.v[j].texcoords[i], min); - max = std::max(r3dPoly.v[j].texcoords[i], max); - } - - float fTemp; - float iTemp; - bool fractMin; - bool fractMax; - - fTemp = std::modf(min, &iTemp); - fractMin = fTemp > 0; - - fTemp = std::modf(max, &iTemp); - fractMax = fTemp > 0; - - for (int j = 0; j < r3dPoly.number && min != max; j++) { - - if (!fractMin) { - if (r3dPoly.v[j].texcoords[i] == min) { - r3dPoly.v[j].texcoords[i] += offset[i]; - } - } - - if (!fractMax) { - if (r3dPoly.v[j].texcoords[i] == max) { - r3dPoly.v[j].texcoords[i] -= offset[i]; - } - } - } - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - do { - - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - - if (ph.header[6] == 0) { - break; - } - - if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) { - continue; - } - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(); - - if (hash != lastHash) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = false; // we will double up polys - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled() && !ph.FixedShading(); - - if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) { - currentMesh->layered = true; - } - - if (currentMesh->lighting) { - if (ph.SpecularEnabled()) { - currentMesh->specular = true; - currentMesh->shininess = 0;// ph.Shininess(); - currentMesh->specularCoefficient = 0; // ph.SpecularValue(); - } - } - - currentMesh->fogIntensity = ph.LightModifier(); - - if (ph.TexEnabled()) { - currentMesh->format = m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest()); - - if (currentMesh->format == 7) { - currentMesh-> alphaTest = false; // alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency - } - - currentMesh->x = ph.X(); - currentMesh->y = ph.Y(); - currentMesh->width = ph.TexWidth(); - currentMesh->height = ph.TexHeight(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - currentMesh->microTexture = ph.MicroTexture(); - currentMesh->microTextureID = ph.MicroTextureID(); - } - } - - currentMesh = &sMap[hash]; - } - - lastHash = hash; - - // Obtain basic polygon parameters - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - // copy face attributes - - if ((ph.header[1] & 2) == 0) { - int colorIdx = ph.ColorIndex(); - p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f; - p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f; - p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f; - } - else { - if (ph.ColorDisabled()) { // no colours were set - p.faceColour[0] = 1.0f; - p.faceColour[1] = 1.0f; - p.faceColour[2] = 1.0f; - } - else { - p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f; - p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f; - p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f; - } - } - - p.faceColour[3] = ph.Transparency() / 255.f; - - // if we have flat shading, we can't re-use normals from shared vertices - for (i = 0; i < p.number && !ph.SmoothShading(); i++) { - p.v[i].normal[0] = p.faceNormal[0]; - p.v[i].normal[1] = p.faceNormal[1]; - p.v[i].normal[2] = p.faceNormal[2]; - } - - UINT32* vData = ph.StartOfData(); // vertex data starts here - - // remaining vertices are new and defined here - for (; j < p.number; j++) - { - // Fetch vertices - UINT32 ix = vData[0]; - UINT32 iy = vData[1]; - UINT32 iz = vData[2]; - UINT32 it = vData[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - // Per vertex normals - if (ph.SmoothShading()) { - p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f; - p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f; - p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f; - } - - if (ph.FixedShading() && ph.LightEnabled()) { - UINT8 shade = (UINT8)((ix + 128) & 0xFF); - p.v[j].color[0] = shade; // hardware doesn't really have per vertex colours, only per poly - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - p.v[j].color[3] = 255; - } - else { - p.v[j].color[0] = 255; - p.v[j].color[1] = 255; - p.v[j].color[2] = 255; - p.v[j].color[3] = 255; - } - - float texU, texV = 0; - - // tex coords - if (currentMesh->textured) { - Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - vData += 4; - } - - // check if we need to modify the texture coordinates - { - float offset[2] = { 0 }; - - if (ph.TexEnabled()) { - - if (!ph.TexSmoothU() && !ph.TexUMirror()) { - offset[0] = 0.5f / ph.TexWidth(); // half texel - } - - if (!ph.TexSmoothV() && !ph.TexVMirror()) { - offset[1] = 0.5f / ph.TexHeight(); // half texel - } - - OffsetTexCoords(p, offset); - } - } - - // check if we need double up vertices for two sided lighting - if (ph.DoubleSided()) { - - R3DPoly tempP = p; - - // flip normals - V3::inverse(tempP.faceNormal); - - for (int i = 0; i < tempP.number; i++) { - V3::inverse(tempP.v[i].normal); - } - - CopyVertexData(tempP, currentMesh->polys); - } - - // Copy this polygon into the model buffer - CopyVertexData(p, currentMesh->polys); - numPolys++; - - // Copy current vertices into previous vertex array - for (i = 0; i < 4; i++) { - prev[i] = p.v[i]; - } - - } while (ph.NextPoly()); - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes->reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes->push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY) -{ - newX = (x + offX) & 2047; // wrap around 2048, shouldn't be required - - int oldPage = y / 1024; - - y -= (oldPage * 1024); // remove page from tex y - - // calc newY with wrap around, wraps around in the same sheet, not into another memory sheet - - newY = (y + offY) & 1023; - - // add page to Y - - newY += ((oldPage + page) & 1) * 1024; // max page 0-1 -} - -void CNew3D::CalcFrustumPlanes(Plane p[6], const float* matrix) -{ - // Left Plane - p[0].a = matrix[3] + matrix[0]; - p[0].b = matrix[7] + matrix[4]; - p[0].c = matrix[11] + matrix[8]; - p[0].d = matrix[15] + matrix[12]; - p[0].Normalise(); - - // Right Plane - p[1].a = matrix[3] - matrix[0]; - p[1].b = matrix[7] - matrix[4]; - p[1].c = matrix[11] - matrix[8]; - p[1].d = matrix[15] - matrix[12]; - p[1].Normalise(); - - // Bottom Plane - p[2].a = matrix[3] + matrix[1]; - p[2].b = matrix[7] + matrix[5]; - p[2].c = matrix[11] + matrix[9]; - p[2].d = matrix[15] + matrix[13]; - p[2].Normalise(); - - // Top Plane - p[3].a = matrix[3] - matrix[1]; - p[3].b = matrix[7] - matrix[5]; - p[3].c = matrix[11] - matrix[9]; - p[3].d = matrix[15] - matrix[13]; - p[3].Normalise(); - - // Near Plane - p[4].a = matrix[3] + matrix[2]; - p[4].b = matrix[7] + matrix[6]; - p[4].c = matrix[11] + matrix[10]; - p[4].d = matrix[15] + matrix[14]; - p[4].Normalise(); - - // Far Plane - p[5].a = matrix[3] - matrix[2]; - p[5].b = matrix[7] - matrix[6]; - p[5].c = matrix[11] - matrix[10]; - p[5].d = matrix[15] - matrix[14]; - p[5].Normalise(); -} - -void CNew3D::CalcBox(float distance, BBox& box) -{ - //bottom left front - box.points[0][0] = -distance; - box.points[0][1] = -distance; - box.points[0][2] = distance; - box.points[0][3] = 1; - - //bottom left back - box.points[1][0] = -distance; - box.points[1][1] = -distance; - box.points[1][2] = -distance; - box.points[1][3] = 1; - - //bottom right back - box.points[2][0] = distance; - box.points[2][1] = -distance; - box.points[2][2] = -distance; - box.points[2][3] = 1; - - //bottom right front - box.points[3][0] = distance; - box.points[3][1] = -distance; - box.points[3][2] = distance; - box.points[3][3] = 1; - - //top left front - box.points[4][0] = -distance; - box.points[4][1] = distance; - box.points[4][2] = distance; - box.points[4][3] = 1; - - //top left back - box.points[5][0] = -distance; - box.points[5][1] = distance; - box.points[5][2] = -distance; - box.points[5][3] = 1; - - //top right back - box.points[6][0] = distance; - box.points[6][1] = distance; - box.points[6][2] = -distance; - box.points[6][3] = 1; - - //top right front - box.points[7][0] = distance; - box.points[7][1] = distance; - box.points[7][2] = distance; - box.points[7][3] = 1; -} - -void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) -{ - for (int i = 0; i < 4; i++) { - out[i] = - in[0] * matrix[0 * 4 + i] + - in[1] * matrix[1 * 4 + i] + - in[2] * matrix[2 * 4 + i] + - in[3] * matrix[3 * 4 + i]; - } -} - -void CNew3D::TransformBox(const float *m, BBox& box) -{ - for (int i = 0; i < 8; i++) { - float v[4]; - MultVec(m, box.points[i], v); - box.points[i][0] = v[0]; - box.points[i][1] = v[1]; - box.points[i][2] = v[2]; - } -} - -Clip CNew3D::ClipBox(BBox& box, Plane planes[6]) -{ - int count = 0; - - for (int i = 0; i < 8; i++) { - - int temp = 0; - - for (int j = 0; j < 6; j++) { - if (planes[j].DistanceToPoint(box.points[i]) >= 0) { - temp++; - } - } - - if (temp == 6) count++; // point is inside all 6 frustum planes - } - - if (count == 8) return Clip::INSIDE; - if (count > 0) return Clip::INTERCEPT; - - //if we got here all points are outside of the view frustum - //check for all points being side same of any plane, means box outside of view - - for (int i = 0; i < 6; i++) { - - int temp = 0; - - for (int j = 0; j < 8; j++) { - if (planes[i].DistanceToPoint(box.points[j]) >= 0) { - float distance = planes[i].DistanceToPoint(box.points[j]); - temp++; - } - } - - if (temp == 0) return Clip::OUTSIDE; - } - - //if we got here, box is traversing view frustum - - return Clip::INTERCEPT; -} - -} // New3D - diff --git a/Src/Graphics/New3D/backup/lost world debug/New3D.h b/Src/Graphics/New3D/backup/lost world debug/New3D.h deleted file mode 100644 index 4ff0b41..0000000 --- a/Src/Graphics/New3D/backup/lost world debug/New3D.h +++ /dev/null @@ -1,241 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" -#include "R3DData.h" -#include "Plane.h" -#include "Vec.h" -#include "R3DScrollFog.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(const R3DPoly& r3dPoly, std::vector& polyArray); - void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - void DrawScrollFog(); - - void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY); - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - - std::vector m_nodes; // this represents the entire render frame - std::vector m_polyBufferRam; // dynamic polys - std::vector m_polyBufferRom; // rom polys - std::unordered_map>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet - - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - R3DShader m_r3dShader; - R3DScrollFog m_r3dScrollFog; - - Plane m_planes[6]; - - struct BBox - { - V4::Vec4 points[8]; - }; - - void CalcFrustumPlanes (Plane p[6], const float* matrix); - void CalcBox (float distance, BBox& box); - void TransformBox (const float *m, BBox& box); - void MultVec (const float matrix[16], const float in[4], float out[4]); - Clip ClipBox (BBox& box, Plane planes[6]); - - void TestDraw(); -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H diff --git a/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp b/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp deleted file mode 100644 index c6044b0..0000000 --- a/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#include "R3DShader.h" -#include "Graphics/Shader.h" - -namespace New3D { - -static const char *vertexShaderBasic = - -// uniforms -"uniform float fogIntensity;\n" -"uniform float fogDensity;\n" -"uniform float fogStart;\n" - -//outputs to fragment shader -"varying float fsFogFactor;\n" -"varying float fsSpecularTerm;\n" // specular light term (additive) -"varying vec3 fsViewVertex;\n" -"varying vec3 fsViewNormal;\n" // per vertex normal vector - -"void main(void)\n" -"{\n" - "fsViewVertex = vec3(gl_ModelViewMatrix * gl_Vertex);\n" - "fsViewNormal = normalize(gl_NormalMatrix *gl_Normal);\n" - "float z = length(fsViewVertex);\n" - "fsFogFactor = fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);\n" - - "gl_FrontColor = gl_Color;\n" - "gl_TexCoord[0] = gl_MultiTexCoord0;\n" - "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" -"}\n"; - -static const char *fragmentShaderBasic = - -"uniform sampler2D tex1;\n" // base tex -"uniform sampler2D tex2;\n" // micro tex (optional) - -"uniform int textureEnabled;\n" -"uniform int microTexture;\n" -"uniform int alphaTest;\n" -"uniform int textureAlpha;\n" -"uniform vec3 fogColour;\n" -"uniform vec4 spotEllipse;\n" // spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height) -"uniform vec2 spotRange;\n" // spotlight Z range: .x=start (viewspace coordinates), .y=limit -"uniform vec3 spotColor;\n" // spotlight RGB color -"uniform vec3 lighting[2];\n" // lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0) -"uniform int lightEnable;\n" // lighting enabled (1.0) or luminous (0.0), drawn at full intensity -"uniform float specularCoefficient;\n" // specular coefficient -"uniform float shininess;\n" // specular shininess - -//interpolated inputs from vertex shader -"varying float fsFogFactor;\n" -"varying float fsSpecularTerm;\n" // specular light term (additive) -"varying vec3 fsViewVertex;\n" -"varying vec3 fsViewNormal;\n" // per vertex normal vector - -"void main()\n" -"{\n" - "vec4 tex1Data;\n" - "vec4 colData;\n" - "vec4 finalData;\n" - - "bool discardFragment = false;\n" - - "tex1Data = vec4(1.0, 1.0, 1.0, 1.0);\n" - - "if(textureEnabled==1) {\n" - - "tex1Data = texture2D( tex1, gl_TexCoord[0].st);\n" - - "if (microTexture==1) {\n" - "vec4 tex2Data = texture2D( tex2, gl_TexCoord[0].st * 4.0);\n" - "tex1Data = (tex1Data+tex2Data)/2.0;\n" - "}\n" - - "if (alphaTest==1) {\n" // does it make any sense to do this later? - "if (tex1Data.a < (8.0/16.0)) {\n" - "discardFragment = true;\n" - "}\n" - "}\n" - - "if (textureAlpha == 0) {\n" - "tex1Data.a = 1.0;\n" - "}\n" - "}\n" - - "colData = gl_Color;\n" - - "finalData = tex1Data * colData;\n" - "if (finalData.a < (1.0/16.0)) {\n" // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports - "discardFragment = true;\n" - "}\n" - - "if (discardFragment) {\n" - "discard;\n" - "}\n" - - "if (lightEnable==1) {\n" - "vec3 lightIntensity;\n" - "vec3 sunVector;\n" // sun lighting vector (as reflecting away from vertex) - "float sunFactor;\n" // sun light projection along vertex normal (0.0 to 1.0) - - // Real3D -> OpenGL view space convention (TO-DO: do this outside of shader) - "sunVector = lighting[0] * vec3(1.0, -1.0, -1.0);\n" - - // Compute diffuse factor for sunlight - "sunFactor = max(dot(sunVector, fsViewNormal), 0.0);\n" - - // Total light intensity: sum of all components - "lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y);\n" // ambient + diffuse - - "lightIntensity = clamp(lightIntensity,0.0,1.0);\n" - - "vec2 ellipse;\n" - "float insideSpot;\n" - - // Compute spotlight and apply lighting - "ellipse = (gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw;\n" - "insideSpot = dot(ellipse, ellipse);\n" - - "if ((insideSpot <= 1.0) && (-fsViewVertex.z >= spotRange.x)) {\n" - "lightIntensity.rgb += (1.0 - insideSpot)*spotColor;\n" - "}\n" - - - "finalData.rgb *= lightIntensity;\n" - - "if (sunFactor > 0.0 && specularCoefficient > 0.0) {\n" - - "vec3 v = normalize(-fsViewVertex);\n" - "vec3 h = normalize(sunVector + v);\n" // halfway vector - - "float NdotHV = max(dot(fsViewNormal,h),0.0);\n" - - "finalData.rgb += vec3(specularCoefficient * pow(NdotHV,shininess));\n" - "}\n" - "}\n" - - - "finalData.rgb = mix(finalData.rgb, fogColour, fsFogFactor);\n" - - "gl_FragColor = finalData;\n" -"}\n"; - -R3DShader::R3DShader() -{ - m_shaderProgram = 0; - m_vertexShader = 0; - m_fragmentShader = 0; - - Start(); // reset attributes -} - -void R3DShader::Start() -{ - m_textured1 = false; - m_textured2 = false; - m_textureAlpha = false; // use alpha in texture - m_alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function) - m_doubleSided = false; - m_lightEnabled = false; - m_layered = false; - - m_shininess = 0; - m_specularCoefficient = 0; - - m_matDet = MatDet::notset; - - m_dirtyMesh = true; // dirty means all the above are dirty, ie first run - m_dirtyModel = true; -} - -bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader) -{ - const char* vShader; - const char* fShader; - bool success; - - if (vertexShader) { - vShader = vertexShader; - } - else { - vShader = vertexShaderBasic; - } - - if (fragmentShader) { - fShader = fragmentShader; - } - else { - fShader = fragmentShaderBasic; - } - - success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, nullptr, nullptr, vShader, fShader); - - m_locTexture1 = glGetUniformLocation(m_shaderProgram, "tex1"); - m_locTexture2 = glGetUniformLocation(m_shaderProgram, "tex2"); - m_locTexture1Enabled= glGetUniformLocation(m_shaderProgram, "textureEnabled"); - m_locTexture2Enabled= glGetUniformLocation(m_shaderProgram, "microTexture"); - m_locTextureAlpha = glGetUniformLocation(m_shaderProgram, "textureAlpha"); - m_locAlphaTest = glGetUniformLocation(m_shaderProgram, "alphaTest"); - - m_locFogIntensity = glGetUniformLocation(m_shaderProgram, "fogIntensity"); - m_locFogDensity = glGetUniformLocation(m_shaderProgram, "fogDensity"); - m_locFogStart = glGetUniformLocation(m_shaderProgram, "fogStart"); - m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour"); - - m_locLighting = glGetUniformLocation(m_shaderProgram, "lighting"); - m_locLightEnable = glGetUniformLocation(m_shaderProgram, "lightEnable"); - m_locShininess = glGetUniformLocation(m_shaderProgram, "shininess"); - m_locSpecCoefficient= glGetUniformLocation(m_shaderProgram, "specularCoefficient"); - m_locSpotEllipse = glGetUniformLocation(m_shaderProgram, "spotEllipse"); - m_locSpotRange = glGetUniformLocation(m_shaderProgram, "spotRange"); - m_locSpotColor = glGetUniformLocation(m_shaderProgram, "spotColor"); - - return success; -} - -void R3DShader::SetShader(bool enable) -{ - if (enable) { - glUseProgram(m_shaderProgram); - Start(); - } - else { - glUseProgram(0); - } -} - -void R3DShader::SetMeshUniforms(const Mesh* m) -{ - if (m == nullptr) { - return; // sanity check - } - - if (m_dirtyMesh) { - glUniform1i(m_locTexture1, 0); - glUniform1i(m_locTexture2, 1); - } - - if (m_dirtyMesh || m->textured != m_textured1) { - glUniform1i(m_locTexture1Enabled, m->textured); - m_textured1 = m->textured; - } - - if (m_dirtyMesh || m->microTexture != m_textured2) { - glUniform1i(m_locTexture2Enabled, m->microTexture); - m_textured2 = m->microTexture; - } - - if (m_dirtyMesh || m->alphaTest != m_alphaTest) { - glUniform1i(m_locAlphaTest, m->alphaTest); - m_alphaTest = m->alphaTest; - } - - if (m_dirtyMesh || m->textureAlpha != m_textureAlpha) { - glUniform1i(m_locTextureAlpha, m->textureAlpha); - m_textureAlpha = m->textureAlpha; - } - - if (m_dirtyMesh || m->fogIntensity != m_fogIntensity) { - glUniform1f(m_locFogIntensity, m->fogIntensity); - m_fogIntensity = m->fogIntensity; - } - - if (m_dirtyMesh || m->lighting != m_lightEnabled) { - glUniform1i(m_locLightEnable, m->lighting); - m_lightEnabled = m->lighting; - } - - if (m_dirtyMesh || m->shininess != m_shininess) { - glUniform1f(m_locShininess, (m->shininess + 1) * 4); - m_shininess = m->shininess; - } - - if (m_dirtyMesh || m->specularCoefficient != m_specularCoefficient) { - glUniform1f(m_locSpecCoefficient, m->specularCoefficient); - m_specularCoefficient = m->specularCoefficient; - } - - if (m_dirtyMesh || m->layered != m_layered) { - m_layered = m->layered; - if (m_layered) { - glEnable(GL_STENCIL_TEST); - } - else { - glDisable(GL_STENCIL_TEST); - } - } - - if (m_matDet!=MatDet::zero) { - - if (m_dirtyMesh || m->doubleSided != m_doubleSided) { - - m_doubleSided = m->doubleSided; - - if (m_doubleSided) { - glDisable(GL_CULL_FACE); - } - else { - //glEnable(GL_CULL_FACE); - } - } - } - - - m_dirtyMesh = false; -} - -void R3DShader::SetViewportUniforms(const Viewport *vp) -{ - //didn't bother caching these, they don't get frequently called anyway - glUniform1f (m_locFogDensity, vp->fogParams[3]); - glUniform1f (m_locFogStart, vp->fogParams[4]); - glUniform3fv(m_locFogColour, 1, vp->fogParams); - - glUniform3fv(m_locLighting, 2, vp->lightingParams); - glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse); - glUniform2fv(m_locSpotRange, 1, vp->spotRange); - glUniform3fv(m_locSpotColor, 1, vp->spotColor); -} - -void R3DShader::SetModelStates(const Model* model) -{ - //========== - MatDet test; - //========== - - test = MatDet::notset; // happens for bad matrices with NaN - - if (model->determinant < 0) { test = MatDet::negative; } - else if (model->determinant > 0) { test = MatDet::positive; } - else if (model->determinant == 0) { test = MatDet::zero; } - - if (m_dirtyModel || m_matDet!=test) { - - switch (test) { - case MatDet::negative: - glCullFace(GL_FRONT); - //glEnable(GL_CULL_FACE); - m_doubleSided = false; - break; - case MatDet::positive: - glCullFace(GL_BACK); - //glEnable(GL_CULL_FACE); - m_doubleSided = false; - break; - default: - glDisable(GL_CULL_FACE); - m_doubleSided = true; // basically drawing on both sides now - } - } - - m_matDet = test; - m_dirtyModel = false; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/static model attempt 1/Model.h b/Src/Graphics/New3D/backup/static model attempt 1/Model.h deleted file mode 100644 index 590a1bd..0000000 --- a/Src/Graphics/New3D/backup/static model attempt 1/Model.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef _MODEL_H_ -#define _MODEL_H_ - -#include "types.h" -#include -#include -#include -#include -#include "Texture.h" -#include "Mat4.h" - -namespace New3D { - -struct Vertex -{ - float pos[3]; - float normal[3]; - float texcoords[2]; - UINT8 color[4]; //rgba -}; - -struct Poly // our polys are always 3 triangles, unlike the real h/w -{ - Vertex p1; - Vertex p2; - Vertex p3; -}; - -struct R3DPoly -{ - Vertex v[4]; // just easier to have them as an array - float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself - int number = 4; -}; - -struct Mesh -{ - // texture - int format, x, y, width, height; - bool mirrorU = false; - bool mirrorV = false; - - // attributes - bool doubleSided = false; - bool textured = false; - bool polyAlpha = false; // specified in the rgba colour - bool textureAlpha = false; // use alpha in texture - bool alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function) - bool lighting = false; - bool testBit = false; - bool clockWise = true; // we need to check if the matrix will change the winding - - float fogIntensity = 1.0f; - - // opengl resources - int vboOffset = 0; // this will be calculated later - int triangleCount = 0; -}; - -struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer -{ - std::vector polys; -}; - -struct Model -{ - std::vector meshes; - - bool dynamic = true; - - //matrices - float modelMat[16]; - float determinant; // we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order -}; - -struct Viewport -{ - Mat4 projectionMatrix; // projection matrix - float lightingParams[6]; // lighting parameters (see RenderViewport() and vertex shader) - float spotEllipse[4]; // spotlight ellipse (see RenderViewport()) - float spotRange[2]; // Z range - float spotColor[3]; // color - float fogParams[5]; // fog parameters (...) - int x, y; // viewport coordinates (scaled and in OpenGL format) - int width, height; // viewport dimensions (scaled for display surface size) - int priority; -}; - -class NodeAttributes -{ -public: - - NodeAttributes(); - - bool Push(); - bool Pop(); - bool StackLimit(); - void Reset(); - - int currentTexOffsetX; - int currentTexOffsetY; - int currentTexOffset; // raw value - -private: - - struct NodeAttribs - { - int texOffsetX; - int texOffsetY; - int texOffset; - }; - std::vector m_vecAttribs; -}; - -struct Node -{ - Viewport viewport; - std::vector> models; -}; - -} // New3D - - -#endif \ No newline at end of file diff --git a/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp b/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp deleted file mode 100644 index e1eb1f8..0000000 --- a/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp +++ /dev/null @@ -1,1058 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include // needed by gcc - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m->meshes.empty()) { - continue; - } - - m_r3dShader.SetModelStates(m.get()); - - for (auto &mesh : m->meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m->modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.textured) { - auto tex = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, mesh.x, mesh.y, mesh.width, mesh.height); - if (tex) { - tex->BindTexture(); - tex->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); -} - -void CNew3D::RenderFrame(void) -{ - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - - glDepthFunc (GL_LEQUAL); - glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - for (int pri = 0; pri <= 3; pri++) { - RenderViewport(0x800000, pri); // build model structure - } - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - std::shared_ptr m; - bool cached = false; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - //m_nodes.back().models.emplace_back(Model()); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - // try to find the model in our cache - - auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset); - - if (m_romMap.count(key)) { - m = m_romMap[key]; // probably better using a shared_ptr instead of copying, but for now it'll do - cached = true; - } - else { - m = std::make_shared(); - m->dynamic = false; - m_romMap[key] = m; // store model in our rom map here - } - } - else { - m = std::make_shared(); - } - - // copy model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - if (!cached) { - CacheModel(m.get(), modelAddress); - } - - m_nodes.back().models.push_back(m); // add model to scene - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, node1Ptr, node2Ptr; - float x, y, z; - int tx, ty; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - node1Ptr = node[0x07 - m_offset]; - node2Ptr = node[0x08 - m_offset]; - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - x = *(float *)&node[0x04 - m_offset]; // magic numbers everywhere ! - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x3F) + ((node[0x02] & 0x4000) ? 1024 : 0); // TODO: 5 or 6 bits for Y coord? - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.currentTexOffset = node[0x02] & 0x7FFF; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(node1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(node1Ptr); - } - - // Proceed to second link - m_modelMat.PopMatrix(); - - // seems to indicate second link is invalid (fixes circular references) - if ((node[0x00] & 0x07) != 0x06) { - DescendNodePtr(node2Ptr); - } - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 1 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - //printf("ATTENTION: Unknown pointer format: %08X\n\n", nodeAddr); - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int listEnd; - - if (m_listDepth > 2) { // several Step 2.1 games require this safeguard - return; - } - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - m_listDepth++; - - // Traverse the list forward and print it out - listEnd = 0; - - while (1) - { - if ((list[listEnd] & 0x02000000)) { // end of list (?) - break; - } - - if ((list[listEnd] == 0) || (((list[listEnd]) >> 24) != 0)) { - listEnd--; // back up to last valid list element - break; - } - - listEnd++; - } - - for (int i = 0; i <= listEnd; i++) { - - nodeAddr = list[i] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - if (!(list[i] & 0x01000000)) { //Fighting Vipers - - if ((nodeAddr != 0) && (nodeAddr != 0x800800)) { - DescendCullingNode(nodeAddr); - } - } - } - - - /* - // Traverse the list backward and descend into each pointer - while (listEnd >= 0) - { - nodeAddr = list[listEnd] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - if (!(list[listEnd] & 0x01000000)) { //Fighting Vipers - - if ((nodeAddr != 0) && (nodeAddr != 0x800800)) { - DescendCullingNode(nodeAddr); - } - } - - listEnd--; - } - */ - - m_listDepth--; -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - if (m_step > 0x10) { - mat.LoadMatrix(m); - } - else { - // Scaling seems to help w/ Step 1.0's extremely large coordinates - GLfloat s = 1.0f / 2048.0f; // this will fuck up normals - mat.LoadIdentity(); - mat.Scale(s, s, s); - mat.MultMatrix(m); - } - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr, int pri) -{ - GLfloat color[8][3] = // RGB1 translation - { - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - const UINT32 *vpnode; - UINT32 nextAddr, nodeAddr, matrixBase; - int curPri; - int vpX, vpY, vpWidth, vpHeight; - int spotColorIdx; - GLfloat vpTopAngle, vpBotAngle, fovYDegrees; - GLfloat scrollFog, scrollAtt; - Viewport* vp; - - // Translate address and obtain pointer - vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - curPri = (vpnode[0x00] >> 3) & 3; // viewport priority - nextAddr = vpnode[0x01] & 0xFFFFFF; // next viewport - nodeAddr = vpnode[0x02]; // scene database node pointer - - // Recursively process next viewport - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01], pri); - } - - // If the priority doesn't match, do not process - if (curPri != pri) { - return; - } - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - vp = &m_nodes.back().viewport; - - vp->priority = pri; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - vpX = (vpnode[0x1A] & 0xFFFF) >> 4; // viewport X (12.4 fixed point) - vpY = (vpnode[0x1A] >> 20) & 0xFFF; // viewport Y (12.4) - vpWidth = (vpnode[0x14] & 0xFFFF) >> 2; // width (14.2) - vpHeight = (vpnode[0x14] >> 18) & 0x3FFF; // height (14.2) - matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - // Field of view and clipping - vpTopAngle = (float)asin(*(float *)&vpnode[0x0E]); // FOV Y upper half-angle (radians) - vpBotAngle = (float)asin(*(float *)&vpnode[0x12]); // FOV Y lower half-angle - fovYDegrees = (vpTopAngle + vpBotAngle)*(float)(180.0 / 3.14159265358979323846); - - // TO-DO: investigate clipping planes - - //if (g_Config.wideScreen && (vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) // only expand viewports that occupy whole screen - //if (0) - if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) - { - // Wide screen hack only modifies X axis and not the Y FOV - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vp->width / (GLfloat)vp->height, 0.1f, 1e5); // use actual full screen ratio to get proper X FOV - } - else - { - vp->x = m_xOffs + (GLint)((float)vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = (GLint)((float)vpWidth*m_xRatio); - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vpWidth / (GLfloat)vpHeight, 0.1f, 1e5); // use Model 3 viewport ratio - } - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = *(float *)&vpnode[0x23]; // fog density - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21>1.05) || (m21<0.95)) - return; - if ((m32>1.05) || (m32<0.95)) - return; - if ((m13>1.05) || (m13<0.95)) - return; - } - - m_listDepth = 0; - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); -} - -void CNew3D::CopyVertexData(R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - polyArray.emplace_back(p); - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - bool done = false; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::shared_ptr tex; - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - while (!done) - { - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - bool validPoly = true; - - ph = data; - - if (ph.header[6] == 0) { - break; - } - - if ((ph.header[0] & 0x100) && (ph.header[0] & 0x200)) { // assuming these two bits mean z and colour writes are disabled - validPoly = false; - } - else { - if (!numPolys && (ph.NumSharedVerts() != 0)) { // sharing vertices, but we haven't started the model yet - printf("incomplete data\n"); - validPoly = false; - } - } - - // Set current header pointer (header is 7 words) - data += 7; // data will now point to first vertex - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(m_nodeAttribs.currentTexOffsetX, m_nodeAttribs.currentTexOffsetY); - - if (hash != lastHash && validPoly) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = ph.DoubleSided(); - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled(); - - if (!ph.Luminous()) { - currentMesh->fogIntensity = 1.0f; - } - else { - currentMesh->fogIntensity = ph.LightModifier(); - } - - if (ph.TexEnabled()) { - currentMesh->format = ph.TexFormat(); - currentMesh->x = ph.X(m_nodeAttribs.currentTexOffsetX); - currentMesh->y = ph.Y(m_nodeAttribs.currentTexOffsetX); - currentMesh->width = ph.TexWidth(); - currentMesh->height = ph.TexHeight(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - tex = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight()); - } - } - - currentMesh = &sMap[hash]; - - if (ph.TexEnabled()) { - tex = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight()); - } - else { - tex = nullptr; - } - } - - if (validPoly) { - lastHash = hash; - } - - // Obtain basic polygon parameters - done = ph.LastPoly(); - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - for (; j < p.number; j++) // remaining vertices are new and defined here - { - // Fetch vertices - UINT32 ix = data[0]; - UINT32 iy = data[1]; - UINT32 iz = data[2]; - UINT32 it = data[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - p.v[j].normal[0] = p.faceNormal[0] + (GLfloat)(INT8)(ix & 0xFF); // vertex normals are offset from polygon normal - we can normalise them in the shader - p.v[j].normal[1] = p.faceNormal[1] + (GLfloat)(INT8)(iy & 0xFF); - p.v[j].normal[2] = p.faceNormal[2] + (GLfloat)(INT8)(iz & 0xFF); - - if ((ph.header[1] & 2) == 0) { - UINT32 colorIdx = ((ph.header[4] >> 20) & 0x7FF); - p.v[j].color[0] = (m_polyRAM[0x400 + colorIdx] & 0xFF); - p.v[j].color[1] = (m_polyRAM[0x400 + colorIdx] >> 8) & 0xFF; - p.v[j].color[2] = (m_polyRAM[0x400 + colorIdx] >> 16) & 0xFF; - } - else if (ph.FixedShading()) { - UINT8 shade = ph.ShadeValue(); - p.v[j].color[0] = shade; - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - } - else { - p.v[j].color[0] = (ph.header[4] >> 24); - p.v[j].color[1] = (ph.header[4] >> 16) & 0xFF; - p.v[j].color[2] = (ph.header[4] >> 8) & 0xFF; - } - - if ((ph.header[6] & 0x00800000)) { // if set, polygon is opaque - p.v[j].color[3] = 255; - } - else { - p.v[j].color[3] = ph.Transparency(); - } - - float texU, texV = 0; - - // tex coords - if (tex) { - tex->GetCoordinates((UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - data += 4; - } - - // Copy current vertices into previous vertex array - for (i = 0; i < 4 && validPoly; i++) { - prev[i] = p.v[i]; - } - - // Copy this polygon into the model buffer - if (validPoly) { - CopyVertexData(p, currentMesh->polys); - numPolys++; - } - } - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes.reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes.push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -UINT64 CNew3D::GetRomMapKey(int address, int texOffset) -{ - return (UINT64)address << 32 | texOffset; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/static model attempt 1/New3D.h b/Src/Graphics/New3D/backup/static model attempt 1/New3D.h deleted file mode 100644 index 065b342..0000000 --- a/Src/Graphics/New3D/backup/static model attempt 1/New3D.h +++ /dev/null @@ -1,221 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr, int pri); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(R3DPoly& r3dPoly, std::vector& polyArray); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - UINT64 GetRomMapKey(int address, int texOffset); - - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - int m_listDepth; - - std::vector m_nodes; // this represents the entire render frame - std::vector m_polyBufferRam; // dynamic polys - std::vector m_polyBufferRom; // rom polys - std::unordered_map> m_romMap; // a hash table for all the ROM models - - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - - R3DShader m_r3dShader; - int m_currentVPPriority; -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H diff --git a/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp b/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp deleted file mode 100644 index 364bd24..0000000 --- a/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "VBO.h" - -namespace New3D { - -VBO::VBO() -{ - m_id = 0; - m_target = 0; - m_capacity = 0; - m_size = 0; -} - -void VBO::Create(GLenum target, GLenum usage, GLsizeiptr size, const void* data) -{ - glGenBuffers(1, &m_id); // create a vbo - glBindBuffer(target, m_id); // activate vbo id to use - glBufferData(target, size, data, usage); // upload data to video card - - m_target = target; - m_capacity = size; - m_size = 0; - - Bind(false); // unbind -} - -void VBO::BufferSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data) -{ - glBufferSubData(m_target, offset, size, data); -} - -bool VBO::AppendData(GLsizeiptr size, const GLvoid* data) -{ - if (size == 0 || !data) { - return true; // nothing to do - } - - if (m_size + size >= m_capacity) { - return false; - } - - BufferSubData(m_size, size, data); - - m_size += size; - - return true; -} - -void VBO::Reset() -{ - m_size = 0; -} - -void VBO::Destroy() -{ - if (m_id) { - glDeleteBuffers(1, &m_id); - m_id = 0; - m_target = 0; - m_capacity = 0; - m_size = 0; - } -} - -void VBO::Bind(bool enable) -{ - if (enable) { - glBindBuffer(m_target, m_id); - } - else { - glBindBuffer(m_target, 0); - } -} - -int VBO::GetSize() -{ - return m_size; -} - -int VBO::GetCapacity() -{ - return m_capacity; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/static vbo/Model.h b/Src/Graphics/New3D/backup/static vbo/Model.h deleted file mode 100644 index db94306..0000000 --- a/Src/Graphics/New3D/backup/static vbo/Model.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef _MODEL_H_ -#define _MODEL_H_ - -#include "types.h" -#include -#include -#include -#include -#include "Texture.h" -#include "Mat4.h" - -namespace New3D { - -struct Vertex -{ - float pos[3]; - float normal[3]; - float texcoords[2]; - UINT8 color[4]; //rgba -}; - -struct Poly // our polys are always 3 triangles, unlike the real h/w -{ - Vertex p1; - Vertex p2; - Vertex p3; -}; - -struct R3DPoly -{ - Vertex v[4]; // just easier to have them as an array - float faceNormal[3]; // we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself - int number = 4; -}; - -struct Mesh -{ - std::shared_ptr texture; - - // attributes - bool doubleSided = false; - bool textured = false; - bool polyAlpha = false; // specified in the rgba colour - bool textureAlpha = false; // use alpha in texture - bool alphaTest = false; // discard fragment based on alpha (ogl does this with fixed function) - bool lighting = false; - bool testBit = false; - bool clockWise = true; // we need to check if the matrix will change the winding - - float fogIntensity = 1.0f; - - // texture - bool mirrorU = false; - bool mirrorV = false; - - // opengl resources - int vboOffset = 0; // this will be calculated later - int triangleCount = 0; -}; - -struct SortingMesh : public Mesh // This struct temporarily holds the model data, before it gets copied to the main buffer -{ - std::vector polys; -}; - -struct Model -{ - std::vector meshes; - - bool dynamic = true; - - //matrices - float modelMat[16]; - float determinant; // we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order -}; - -struct Viewport -{ - Mat4 projectionMatrix; // projection matrix - float lightingParams[6]; // lighting parameters (see RenderViewport() and vertex shader) - float spotEllipse[4]; // spotlight ellipse (see RenderViewport()) - float spotRange[2]; // Z range - float spotColor[3]; // color - float fogParams[5]; // fog parameters (...) - int x, y; // viewport coordinates (scaled and in OpenGL format) - int width, height; // viewport dimensions (scaled for display surface size) - int priority; -}; - -class NodeAttributes -{ -public: - - NodeAttributes(); - - bool Push(); - bool Pop(); - bool StackLimit(); - void Reset(); - - int currentTexOffsetX; - int currentTexOffsetY; - int currentTexOffset; // raw value - -private: - - struct NodeAttribs - { - int texOffsetX; - int texOffsetY; - int texOffset; - }; - std::vector m_vecAttribs; -}; - -struct Node -{ - Viewport viewport; - std::vector models; -}; - -} // New3D - - -#endif \ No newline at end of file diff --git a/Src/Graphics/New3D/backup/static vbo/New3D.cpp b/Src/Graphics/New3D/backup/static vbo/New3D.cpp deleted file mode 100644 index ecfec4d..0000000 --- a/Src/Graphics/New3D/backup/static vbo/New3D.cpp +++ /dev/null @@ -1,1055 +0,0 @@ -#include "New3D.h" -#include "PolyHeader.h" -#include "Texture.h" -#include "Vec.h" -#include // needed by gcc - -#define MAX_RAM_POLYS 100000 -#define MAX_ROM_POLYS 500000 - -#ifndef M_PI -#define M_PI 3.14159265359 -#endif - -namespace New3D { - -CNew3D::CNew3D() -{ - m_cullingRAMLo = nullptr; - m_cullingRAMHi = nullptr; - m_polyRAM = nullptr; - m_vrom = nullptr; - m_textureRAM = nullptr; -} - -CNew3D::~CNew3D() -{ - m_vbo.Destroy(); -} - -void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr) -{ - m_cullingRAMLo = cullingRAMLoPtr; - m_cullingRAMHi = cullingRAMHiPtr; - m_polyRAM = polyRAMPtr; - m_vrom = vromPtr; - m_textureRAM = textureRAMPtr; -} - -void CNew3D::SetStep(int stepID) -{ - m_step = stepID; - - if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) { - m_step = 0x10; - } - - if (m_step > 0x10) { - m_offset = 0; // culling nodes are 10 words - m_vertexFactor = (1.0f / 2048.0f); // vertices are in 13.11 format - } - else { - m_offset = 2; // 8 words - m_vertexFactor = (1.0f / 128.0f); // 17.7 - } - - m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS)); -} - -bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam) -{ - // Resolution and offset within physical display area - m_xRatio = xRes / 496.0f; - m_yRatio = yRes / 384.0f; - m_xOffs = xOffset; - m_yOffs = yOffset; - m_totalXRes = totalXResParam; - m_totalYRes = totalYResParam; - - m_r3dShader.LoadShader(); - - glUseProgram(0); - - return OKAY; // OKAY ? wtf .. -} - -void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height) -{ - m_texSheet.Invalidate(x, y, width, height); -} - -void CNew3D::RenderScene(int priority, bool alpha) -{ - if (alpha) { - glEnable(GL_BLEND); - } - - for (auto &n : m_nodes) { - - if (n.viewport.priority != priority || n.models.empty()) { - continue; - } - - glViewport (n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height); - glMatrixMode (GL_PROJECTION); - glLoadMatrixf (n.viewport.projectionMatrix); - glMatrixMode (GL_MODELVIEW); - - m_r3dShader.SetViewportUniforms(&n.viewport); - - for (auto &m : n.models) { - - bool matrixLoaded = false; - - if (m.meshes.empty()) { - continue; - } - - m_r3dShader.SetModelStates(&m); - - for (auto &mesh : m.meshes) { - - if (alpha) { - if (!mesh.textureAlpha && !mesh.polyAlpha) { - continue; - } - } - else { - if (mesh.textureAlpha || mesh.polyAlpha) { - continue; - } - } - - if (!matrixLoaded) { - glLoadMatrixf(m.modelMat); - matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc - } - - if (mesh.texture) { - mesh.texture->BindTexture(); - mesh.texture->SetWrapMode(mesh.mirrorU, mesh.mirrorV); - } - - m_r3dShader.SetMeshUniforms(&mesh); - glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3); // times 3 to convert triangles to vertices - } - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); -} - -void CNew3D::RenderFrame(void) -{ - // release any resources from last frame - m_polyBufferRam.clear(); // clear dyanmic model memory buffer - m_nodes.clear(); // memory will grow during the object life time, that's fine, no need to shrink to fit - m_modelMat.Release(); // would hope we wouldn't need this but no harm in checking - m_nodeAttribs.Reset(); - - glDepthFunc (GL_LEQUAL); - glEnable (GL_DEPTH_TEST); - glActiveTexture (GL_TEXTURE0); - glEnable (GL_CULL_FACE); - glFrontFace (GL_CW); - - for (int pri = 0; pri <= 3; pri++) { - RenderViewport(0x800000, pri); // build model structure - } - - m_vbo.Bind(true); - m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data()); // upload all the dynamic data to GPU in one go - - if (m_polyBufferRom.size()) { - - // sync rom memory with vbo - int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly); - int vboBytes = m_vbo.GetSize(); - int size = romBytes - vboBytes; - - if (size) { - m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]); - } - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil .. - glVertexPointer (3, GL_FLOAT, sizeof(Vertex), 0); - glNormalPointer (GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); - glTexCoordPointer (2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords)); - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color)); - - m_r3dShader.SetShader(true); - - for (int pri = 0; pri <= 3; pri++) { - glClear (GL_DEPTH_BUFFER_BIT); - RenderScene (pri, false); - RenderScene (pri, true); - } - - m_r3dShader.SetShader(false); // unbind shader - m_vbo.Bind(false); - - glDisable(GL_CULL_FACE); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); -} - -void CNew3D::BeginFrame(void) -{ -} - -void CNew3D::EndFrame(void) -{ -} - -/****************************************************************************** -Real3D Address Translation - -Functions that interpret word-granular Real3D addresses and return pointers. -******************************************************************************/ - -// Translates 24-bit culling RAM addresses -const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr) -{ - addr &= 0x00FFFFFF; // caller should have done this already - - if ((addr >= 0x800000) && (addr < 0x840000)) { - return &m_cullingRAMHi[addr & 0x3FFFF]; - } - else if (addr < 0x100000) { - return &m_cullingRAMLo[addr]; - } - - return NULL; -} - -// Translates model references -const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr) -{ - modelAddr &= 0x00FFFFFF; // caller should have done this already - - if (modelAddr < 0x100000) { - return &m_polyRAM[modelAddr]; - } - else { - return &m_vrom[modelAddr]; - } -} - -bool CNew3D::DrawModel(UINT32 modelAddr) -{ - const UINT32* modelAddress; - Model* m; - bool cached = false; - - modelAddress = TranslateModelAddress(modelAddr); - - // create a new model to push onto the vector - m_nodes.back().models.emplace_back(Model()); - - // get the pointer to the last element in the array - m = &m_nodes.back().models.back(); - - if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) { - - m->dynamic = false; - - // try to find the model in our cache - - auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset); - - if (m_romMap.count(key)) { - (*m) = m_romMap[key]; // probably better using a shared_ptr instead of copying, but for now it'll do - cached = true; - } - } - - // copy model matrix - for (int i = 0; i < 16; i++) { - m->modelMat[i] = m_modelMat.currentMatrix[i]; - } - - //calculate determinant - m->determinant = Determinant3x3(m_modelMat); - - if (!cached) { - CacheModel(m, modelAddress); - } - - //if it was a ROM model, add it to the hash map for later if it wasn't already there - if (!m->dynamic && !cached) { - auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset); - m_romMap[key] = *m; - } - - return true; -} - -// Descends into a 10-word culling node -void CNew3D::DescendCullingNode(UINT32 addr) -{ - const UINT32 *node, *lodTable; - UINT32 matrixOffset, node1Ptr, node2Ptr; - float x, y, z; - int tx, ty; - - if (m_nodeAttribs.StackLimit()) { - return; - } - - node = TranslateCullingAddress(addr); - - if (NULL == node) { - return; - } - - // Extract known fields - node1Ptr = node[0x07 - m_offset]; - node2Ptr = node[0x08 - m_offset]; - matrixOffset = node[0x03 - m_offset] & 0xFFF; - - x = *(float *)&node[0x04 - m_offset]; // magic numbers everywhere ! - y = *(float *)&node[0x05 - m_offset]; - z = *(float *)&node[0x06 - m_offset]; - - m_nodeAttribs.Push(); // save current attribs - - if (!m_offset) // Step 1.5+ - { - tx = 32 * ((node[0x02] >> 7) & 0x3F); - ty = 32 * (node[0x02] & 0x3F) + ((node[0x02] & 0x4000) ? 1024 : 0); // TODO: 5 or 6 bits for Y coord? - - // apply texture offsets, else retain current ones - if ((node[0x02] & 0x8000)) { - m_nodeAttribs.currentTexOffsetX = tx; - m_nodeAttribs.currentTexOffsetY = ty; - m_nodeAttribs.currentTexOffset = node[0x02] & 0x7FFF; - } - } - - // Apply matrix and translation - m_modelMat.PushMatrix(); - - // apply translation vector - if ((node[0x00] & 0x10)) { - m_modelMat.Translate(x, y, z); - } - // multiply matrix, if specified - else if (matrixOffset) { - MultMatrix(matrixOffset,m_modelMat); - } - - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(node1Ptr); - - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO - } - } - } - else { - DescendNodePtr(node1Ptr); - } - - // Proceed to second link - m_modelMat.PopMatrix(); - - // seems to indicate second link is invalid (fixes circular references) - if ((node[0x00] & 0x07) != 0x06) { - DescendNodePtr(node2Ptr); - } - - // Restore old texture offsets - m_nodeAttribs.Pop(); -} - -void CNew3D::DescendNodePtr(UINT32 nodeAddr) -{ - // Ignore null links - if ((nodeAddr & 0x00FFFFFF) == 0) { - return; - } - - switch ((nodeAddr >> 24) & 0xFF) // pointer type encoded in upper 8 bits - { - case 0x00: // culling node - DescendCullingNode(nodeAddr & 0xFFFFFF); - break; - case 0x01: // model (perhaps bit 1 is a flag in this case?) - case 0x03: - DrawModel(nodeAddr & 0xFFFFFF); - break; - case 0x04: // pointer list - DescendPointerList(nodeAddr & 0xFFFFFF); - break; - default: - //printf("ATTENTION: Unknown pointer format: %08X\n\n", nodeAddr); - break; - } -} - -void CNew3D::DescendPointerList(UINT32 addr) -{ - const UINT32* list; - UINT32 nodeAddr; - int listEnd; - - if (m_listDepth > 2) { // several Step 2.1 games require this safeguard - return; - } - - list = TranslateCullingAddress(addr); - - if (NULL == list) { - return; - } - - m_listDepth++; - - // Traverse the list forward and print it out - listEnd = 0; - - while (1) - { - if ((list[listEnd] & 0x02000000)) { // end of list (?) - break; - } - - if ((list[listEnd] == 0) || (((list[listEnd]) >> 24) != 0)) { - listEnd--; // back up to last valid list element - break; - } - - listEnd++; - } - - for (int i = 0; i <= listEnd; i++) { - - nodeAddr = list[i] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - if (!(list[i] & 0x01000000)) { //Fighting Vipers - - if ((nodeAddr != 0) && (nodeAddr != 0x800800)) { - DescendCullingNode(nodeAddr); - } - } - } - - - /* - // Traverse the list backward and descend into each pointer - while (listEnd >= 0) - { - nodeAddr = list[listEnd] & 0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node - - if (!(list[listEnd] & 0x01000000)) { //Fighting Vipers - - if ((nodeAddr != 0) && (nodeAddr != 0x800800)) { - DescendCullingNode(nodeAddr); - } - } - - listEnd--; - } - */ - - m_listDepth--; -} - - -/****************************************************************************** -Matrix Stack -******************************************************************************/ - -// Macro to generate column-major (OpenGL) index from y,x subscripts -#define CMINDEX(y,x) (x*4+y) - -/* -* MultMatrix(): -* -* Multiplies the matrix stack by the specified Real3D matrix. The matrix -* index is a 12-bit number specifying a matrix number relative to the base. -* The base matrix MUST be set up before calling this function. -*/ -void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat) -{ - GLfloat m[4*4]; - const float *src = &m_matrixBasePtr[matrixOffset * 12]; - - if (m_matrixBasePtr == NULL) // LA Machineguns - return; - - m[CMINDEX(0, 0)] = src[3]; - m[CMINDEX(0, 1)] = src[4]; - m[CMINDEX(0, 2)] = src[5]; - m[CMINDEX(0, 3)] = src[0]; - m[CMINDEX(1, 0)] = src[6]; - m[CMINDEX(1, 1)] = src[7]; - m[CMINDEX(1, 2)] = src[8]; - m[CMINDEX(1, 3)] = src[1]; - m[CMINDEX(2, 0)] = src[9]; - m[CMINDEX(2, 1)] = src[10]; - m[CMINDEX(2, 2)] = src[11]; - m[CMINDEX(2, 3)] = src[2]; - m[CMINDEX(3, 0)] = 0.0; - m[CMINDEX(3, 1)] = 0.0; - m[CMINDEX(3, 2)] = 0.0; - m[CMINDEX(3, 3)] = 1.0; - - mat.MultMatrix(m); -} - -/* -* InitMatrixStack(): -* -* Initializes the modelview (model space -> view space) matrix stack and -* Real3D coordinate system. These are the last transforms to be applied (and -* the first to be defined on the stack) before projection. -* -* Model 3 games tend to define the following unusual base matrix: -* -* 0 0 -1 0 -* 1 0 0 0 -* 0 -1 0 0 -* 0 0 0 1 -* -* When this is multiplied by a column vector, the output is: -* -* -Z -* X -* -Y -* 1 -* -* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games -* store everything as X,Y,Z and perform the translation at the end. The Real3D -* also has Y and Z coordinates opposite of the OpenGL convention. This -* function inserts a compensating matrix to undo these things. -* -* NOTE: This function assumes we are in GL_MODELVIEW matrix mode. -*/ - -void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat) -{ - GLfloat m[4 * 4]; - - // This matrix converts vectors back from the weird Model 3 Z,X,Y ordering - // and also into OpenGL viewspace (-Y,-Z) - m[CMINDEX(0, 0)] = 0.0; m[CMINDEX(0, 1)] = 1.0; m[CMINDEX(0, 2)] = 0.0; m[CMINDEX(0, 3)] = 0.0; - m[CMINDEX(1, 0)] = 0.0; m[CMINDEX(1, 1)] = 0.0; m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0; - m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0; m[CMINDEX(2, 2)] = 0.0; m[CMINDEX(2, 3)] = 0.0; - m[CMINDEX(3, 0)] = 0.0; m[CMINDEX(3, 1)] = 0.0; m[CMINDEX(3, 2)] = 0.0; m[CMINDEX(3, 3)] = 1.0; - - if (m_step > 0x10) { - mat.LoadMatrix(m); - } - else { - // Scaling seems to help w/ Step 1.0's extremely large coordinates - GLfloat s = 1.0f / 2048.0f; // this will fuck up normals - mat.LoadIdentity(); - mat.Scale(s, s, s); - mat.MultMatrix(m); - } - - // Set matrix base address and apply matrix #0 (coordinate system matrix) - m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr); - MultMatrix(0, mat); -} - -// Draws viewports of the given priority -void CNew3D::RenderViewport(UINT32 addr, int pri) -{ - GLfloat color[8][3] = // RGB1 translation - { - { 0.0, 0.0, 0.0 }, // off - { 0.0, 0.0, 1.0 }, // blue - { 0.0, 1.0, 0.0 }, // green - { 0.0, 1.0, 1.0 }, // cyan - { 1.0, 0.0, 0.0 }, // red - { 1.0, 0.0, 1.0 }, // purple - { 1.0, 1.0, 0.0 }, // yellow - { 1.0, 1.0, 1.0 } // white - }; - const UINT32 *vpnode; - UINT32 nextAddr, nodeAddr, matrixBase; - int curPri; - int vpX, vpY, vpWidth, vpHeight; - int spotColorIdx; - GLfloat vpTopAngle, vpBotAngle, fovYDegrees; - GLfloat scrollFog, scrollAtt; - Viewport* vp; - - // Translate address and obtain pointer - vpnode = TranslateCullingAddress(addr); - - if (NULL == vpnode) { - return; - } - - curPri = (vpnode[0x00] >> 3) & 3; // viewport priority - nextAddr = vpnode[0x01] & 0xFFFFFF; // next viewport - nodeAddr = vpnode[0x02]; // scene database node pointer - - // Recursively process next viewport - if (vpnode[0x01] == 0) { // memory probably hasn't been set up yet, abort - return; - } - if (vpnode[0x01] != 0x01000000) { - RenderViewport(vpnode[0x01], pri); - } - - // If the priority doesn't match, do not process - if (curPri != pri) { - return; - } - - // create node object - m_nodes.emplace_back(Node()); - m_nodes.back().models.reserve(2048); // create space for models - - // get pointer to its viewport - vp = &m_nodes.back().viewport; - - vp->priority = pri; - - // Fetch viewport parameters (TO-DO: would rounding make a difference?) - vpX = (vpnode[0x1A] & 0xFFFF) >> 4; // viewport X (12.4 fixed point) - vpY = (vpnode[0x1A] >> 20) & 0xFFF; // viewport Y (12.4) - vpWidth = (vpnode[0x14] & 0xFFFF) >> 2; // width (14.2) - vpHeight = (vpnode[0x14] >> 18) & 0x3FFF; // height (14.2) - matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address - - // Field of view and clipping - vpTopAngle = (float)asin(*(float *)&vpnode[0x0E]); // FOV Y upper half-angle (radians) - vpBotAngle = (float)asin(*(float *)&vpnode[0x12]); // FOV Y lower half-angle - fovYDegrees = (vpTopAngle + vpBotAngle)*(float)(180.0 / 3.14159265358979323846); - - // TO-DO: investigate clipping planes - - //if (g_Config.wideScreen && (vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) // only expand viewports that occupy whole screen - //if (0) - if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383)) - { - // Wide screen hack only modifies X axis and not the Y FOV - vp->x = 0; - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = m_totalXRes; - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vp->width / (GLfloat)vp->height, 0.1f, 1e5); // use actual full screen ratio to get proper X FOV - } - else - { - vp->x = m_xOffs + (GLint)((float)vpX*m_xRatio); - vp->y = m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio); - vp->width = (GLint)((float)vpWidth*m_xRatio); - vp->height = (GLint)((float)vpHeight*m_yRatio); - - vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vpWidth / (GLfloat)vpHeight, 0.1f, 1e5); // use Model 3 viewport ratio - } - - // Lighting (note that sun vector points toward sun -- away from vertex) - vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X - vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y - vp->lightingParams[2] = *(float *)&vpnode[0x04]; // sun Z - vp->lightingParams[3] = *(float *)&vpnode[0x07]; // sun intensity - vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f); // ambient intensity - vp->lightingParams[5] = 0.0; // reserved - - // Spotlight - spotColorIdx = (vpnode[0x20] >> 11) & 7; // spotlight color index - vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF); // spotlight X position (fractional component?) - vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF); // spotlight Y - vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF); // spotlight X size (16-bit? May have fractional component below bit 16) - vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF); // spotlight Y size - - vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]); // spotlight start - vp->spotRange[1] = *(float *)&vpnode[0x1F]; // spotlight extent - vp->spotColor[0] = color[spotColorIdx][0]; // spotlight color - vp->spotColor[1] = color[spotColorIdx][1]; - vp->spotColor[2] = color[spotColorIdx][2]; - - // Spotlight is applied on a per pixel basis, must scale its position and size to screen - vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1]; - vp->spotRange[1] += vp->spotRange[0]; // limit - vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]); // spotlight appears to be specified in terms of physical resolution (unconfirmed) - vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]); - - // Scale the spotlight to the OpenGL viewport - vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs; - vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs; - vp->spotEllipse[2] *= m_xRatio; - vp->spotEllipse[3] *= m_yRatio; - - // Fog - vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f); // fog color R - vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f); // fog color G - vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f); // fog color B - vp->fogParams[3] = *(float *)&vpnode[0x23]; // fog density - vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f); // fog start - - - if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) { // Star Wars Trilogy - vp->fogParams[3] = vp->fogParams[4] = 0.0f; - } - - // Unknown light/fog parameters - scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f); // scroll fog - scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f); // scroll attenuation - - // Clear texture offsets before proceeding - m_nodeAttribs.Reset(); - - // Set up coordinate system and base matrix - InitMatrixStack(matrixBase, m_modelMat); - - // Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer - if (NULL != m_matrixBasePtr) - { - float m21, m32, m13; - - // Get the three elements that are usually set and see if their magnitudes are 1 - m21 = m_matrixBasePtr[6]; - m32 = m_matrixBasePtr[10]; - m13 = m_matrixBasePtr[5]; - - m21 *= m21; - m32 *= m32; - m13 *= m13; - - if ((m21>1.05) || (m21<0.95)) - return; - if ((m32>1.05) || (m32<0.95)) - return; - if ((m13>1.05) || (m13<0.95)) - return; - } - - m_listDepth = 0; - - // Descend down the node link: Use recursive traversal - DescendNodePtr(nodeAddr); -} - -void CNew3D::CopyVertexData(R3DPoly& r3dPoly, std::vector& polyArray) -{ - //==================== - Poly p; - V3::Vec3 normal; - float dotProd; - bool clockWise; - //==================== - - V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal); - - dotProd = V3::dotProduct(normal, r3dPoly.faceNormal); - clockWise = dotProd >= 0.0; - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[2]; - } - else { - p.p1 = r3dPoly.v[2]; - p.p2 = r3dPoly.v[1]; - p.p3 = r3dPoly.v[0]; - } - - polyArray.emplace_back(p); - - if (r3dPoly.number == 4) { - - if (clockWise) { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[2]; - p.p3 = r3dPoly.v[3]; - } - else { - p.p1 = r3dPoly.v[0]; - p.p2 = r3dPoly.v[3]; - p.p3 = r3dPoly.v[2]; - } - - polyArray.emplace_back(p); - } -} - -void CNew3D::CacheModel(Model *m, const UINT32 *data) -{ - Vertex prev[4]; - PolyHeader ph; - int numPolys = 0; - bool done = false; - UINT64 lastHash = -1; - SortingMesh* currentMesh = nullptr; - - std::shared_ptr tex; - std::map sMap; - - if (data == NULL) - return; - - ph = data; - int numTriangles = ph.NumTrianglesTotal(); - - // Cache all polygons - while (!done) - { - R3DPoly p; // current polygon - GLfloat uvScale; - int i, j; - bool validPoly = true; - - ph = data; - - if (ph.header[6] == 0) { - break; - } - - if ((ph.header[0] & 0x100) && (ph.header[0] & 0x200)) { // assuming these two bits mean z and colour writes are disabled - validPoly = false; - } - else { - if (!numPolys && (ph.NumSharedVerts() != 0)) { // sharing vertices, but we haven't started the model yet - printf("incomplete data\n"); - validPoly = false; - } - } - - // Set current header pointer (header is 7 words) - data += 7; // data will now point to first vertex - - // create a hash value based on poly attributes -todo add more attributes - auto hash = ph.Hash(m_nodeAttribs.currentTexOffsetX, m_nodeAttribs.currentTexOffsetY); - - if (hash != lastHash && validPoly) { - - if (sMap.count(hash) == 0) { - - sMap[hash] = SortingMesh(); - - currentMesh = &sMap[hash]; - - //make space for our vertices - currentMesh->polys.reserve(numTriangles); - - //copy attributes - currentMesh->doubleSided = ph.DoubleSided(); - currentMesh->mirrorU = ph.TexUMirror(); - currentMesh->mirrorV = ph.TexVMirror(); - currentMesh->textured = ph.TexEnabled(); - currentMesh->alphaTest = ph.AlphaTest(); - currentMesh->textureAlpha = ph.TextureAlpha(); - currentMesh->polyAlpha = ph.PolyAlpha(); - currentMesh->lighting = ph.LightEnabled(); - - if (ph.header[6] & 0x10000) { - currentMesh->testBit = true; - } - - if (!ph.Luminous()) { - currentMesh->fogIntensity = 1.0f; - } - else { - currentMesh->fogIntensity = ph.LightModifier(); - } - - if (ph.TexEnabled()) { - currentMesh->texture = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight()); - } - } - - currentMesh = &sMap[hash]; - - if (ph.TexEnabled()) { - tex = currentMesh->texture; - } - else { - tex = nullptr; - } - } - - if (validPoly) { - lastHash = hash; - } - - // Obtain basic polygon parameters - done = ph.LastPoly(); - p.number = ph.NumVerts(); - uvScale = ph.UVScale(); - - ph.FaceNormal(p.faceNormal); - - // Fetch reused vertices according to bitfield, then new verts - i = 0; - j = 0; - for (i = 0; i < 4; i++) // up to 4 reused vertices - { - if (ph.SharedVertex(i)) - { - p.v[j] = prev[i]; - ++j; - } - } - - for (; j < p.number; j++) // remaining vertices are new and defined here - { - // Fetch vertices - UINT32 ix = data[0]; - UINT32 iy = data[1]; - UINT32 iz = data[2]; - UINT32 it = data[3]; - - // Decode vertices - p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor; - p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor; - p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor; - - p.v[j].normal[0] = p.faceNormal[0] + (GLfloat)(INT8)(ix & 0xFF); // vertex normals are offset from polygon normal - we can normalise them in the shader - p.v[j].normal[1] = p.faceNormal[1] + (GLfloat)(INT8)(iy & 0xFF); - p.v[j].normal[2] = p.faceNormal[2] + (GLfloat)(INT8)(iz & 0xFF); - - if ((ph.header[1] & 2) == 0) { - UINT32 colorIdx = ((ph.header[4] >> 20) & 0x7FF); - p.v[j].color[0] = (m_polyRAM[0x400 + colorIdx] & 0xFF); - p.v[j].color[1] = (m_polyRAM[0x400 + colorIdx] >> 8) & 0xFF; - p.v[j].color[2] = (m_polyRAM[0x400 + colorIdx] >> 16) & 0xFF; - } - else if (ph.FixedShading()) { - UINT8 shade = ph.ShadeValue(); - p.v[j].color[0] = shade; - p.v[j].color[1] = shade; - p.v[j].color[2] = shade; - } - else { - p.v[j].color[0] = (ph.header[4] >> 24); - p.v[j].color[1] = (ph.header[4] >> 16) & 0xFF; - p.v[j].color[2] = (ph.header[4] >> 8) & 0xFF; - } - - if ((ph.header[6] & 0x00800000)) { // if set, polygon is opaque - p.v[j].color[3] = 255; - } - else { - p.v[j].color[3] = ph.Transparency(); - } - - float texU, texV = 0; - - // tex coords - if (tex) { - tex->GetCoordinates((UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV); - } - - p.v[j].texcoords[0] = texU; - p.v[j].texcoords[1] = texV; - - data += 4; - } - - // Copy current vertices into previous vertex array - for (i = 0; i < 4 && validPoly; i++) { - prev[i] = p.v[i]; - } - - // Copy this polygon into the model buffer - if (validPoly) { - CopyVertexData(p, currentMesh->polys); - numPolys++; - } - } - - //sorted the data, now copy to main data structures - - // we know how many meshes we have so reserve appropriate space - m->meshes.reserve(sMap.size()); - - for (auto& it : sMap) { - - if (m->dynamic) { - - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRam.size() + MAX_ROM_POLYS; - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end()); - } - else { - // calculate VBO values for current mesh - it.second.vboOffset = m_polyBufferRom.size(); - it.second.triangleCount = it.second.polys.size(); - - // copy poly data to main buffer - m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end()); - } - - //copy the temp mesh into the model structure - //this will lose the associated vertex data, which is now copied to the main buffer anyway - m->meshes.push_back(it.second); - } -} - -float CNew3D::Determinant3x3(const float m[16]) { - - /* - | A B C | - M = | D E F | - | G H I | - - then the determinant is calculated as follows: - - det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) - */ - - return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5])); -} - -bool CNew3D::IsDynamicModel(UINT32 *data) -{ - if (data == NULL) { - return false; - } - - PolyHeader p(data); - - do { - - if ((p.header[1] & 2) == 0) { // model has rgb colour palette - return true; - } - - if (p.header[6] == 0) { - break; - } - - } while (p.NextPoly()); - - return false; -} - -bool CNew3D::IsVROMModel(UINT32 modelAddr) -{ - return modelAddr >= 0x100000; -} - -UINT64 CNew3D::GetRomMapKey(int address, int texOffset) -{ - return (UINT64)address << 32 | texOffset; -} - -} // New3D diff --git a/Src/Graphics/New3D/backup/static vbo/New3D.h b/Src/Graphics/New3D/backup/static vbo/New3D.h deleted file mode 100644 index d5071dd..0000000 --- a/Src/Graphics/New3D/backup/static vbo/New3D.h +++ /dev/null @@ -1,226 +0,0 @@ -/** -** Supermodel -** A Sega Model 3 Arcade Emulator. -** Copyright 2011 Bart Trzynadlowski, Nik Henson -** -** This file is part of Supermodel. -** -** Supermodel 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. -** -** Supermodel 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 Supermodel. If not, see . -**/ - -/* -* New3D.h -* -* Header file defining the CNew3D class: OpenGL Real3D graphics engine. -*/ - -#ifndef INCLUDED_NEW3D_H -#define INCLUDED_NEW3D_H - -#include "Pkgs/glew.h" -#include "Types.h" -#include "TextureSheet.h" -#include "Graphics/IRender3D.h" -#include "Model.h" -#include "Mat4.h" -#include "R3DShader.h" -#include "VBO.h" - -namespace New3D { - -class CNew3D : public IRender3D -{ -public: - /* - * RenderFrame(void): - * - * Renders the complete scene database. Must be called between BeginFrame() and - * EndFrame(). This function traverses the scene database and builds up display - * lists. - */ - void RenderFrame(void); - - /* - * BeginFrame(void): - * - * Prepare to render a new frame. Must be called once per frame prior to - * drawing anything. - */ - void BeginFrame(void); - - /* - * EndFrame(void): - * - * Signals the end of rendering for this frame. Must be called last during - * the frame. - */ - void EndFrame(void); - - /* - * UploadTextures(x, y, width, height): - * - * Signals that a portion of texture RAM has been updated. - * - * Parameters: - * x X position within texture RAM. - * y Y position within texture RAM. - * width Width of texture data in texels. - * height Height. - */ - void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height); - - /* - * AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr, - * textureRAMPtr): - * - * Attaches RAM and ROM areas. This must be done prior to any rendering - * otherwise the program may crash with an access violation. - * - * Parameters: - * cullingRAMLoPtr Pointer to low culling RAM (4 MB). - * cullingRAMHiPtr Pointer to high culling RAM (1 MB). - * polyRAMPtr Pointer to polygon RAM (4 MB). - * vromPtr Pointer to video ROM (64 MB). - * textureRAMPtr Pointer to texture RAM (8 MB). - */ - void AttachMemory(const UINT32 *cullingRAMLoPtr, - const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, - const UINT32 *vromPtr, const UINT16 *textureRAMPtr); - - /* - * SetStep(stepID): - * - * Sets the Model 3 hardware stepping, which also determines the Real3D - * functionality. The default is Step 1.0. This should be called prior to - * any other emulation functions and after Init(). - * - * Parameters: - * stepID 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, - * or 0x21 for Step 2.1. Anything else defaults to 1.0. - */ - void SetStep(int stepID); - - /* - * Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes): - * - * One-time initialization of the context. Must be called before any other - * members (meaning it should be called even before being attached to any - * other objects that want to use it). - * - * External shader files are loaded according to configuration settings. - * - * Parameters: - * xOffset X offset of the viewable area within OpenGL display - * surface, in pixels. - * yOffset Y offset. - * xRes Horizontal resolution of the viewable area. - * yRes Vertical resolution. - * totalXRes Horizontal resolution of the complete display area. - * totalYRes Vertical resolution. - * - * Returns: - * OKAY is successful, otherwise FAILED if a non-recoverable error - * occurred. Any allocated memory will not be freed until the - * destructor is called. Prints own error messages. - */ - bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes); - - /* - * CRender3D(void): - * ~CRender3D(void): - * - * Constructor and destructor. - */ - CNew3D(void); - ~CNew3D(void); - -private: - /* - * Private Members - */ - - // Real3D address translation - const UINT32 *TranslateCullingAddress(UINT32 addr); - const UINT32 *TranslateModelAddress(UINT32 addr); - - // Matrix stack - void MultMatrix(UINT32 matrixOffset, Mat4& mat); - void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat); - - // Scene database traversal - bool DrawModel(UINT32 modelAddr); - void DescendCullingNode(UINT32 addr); - void DescendPointerList(UINT32 addr); - void DescendNodePtr(UINT32 nodeAddr); - void RenderViewport(UINT32 addr, int pri); - - // building the scene - void CacheModel(Model *m, const UINT32 *data); - void CopyVertexData(R3DPoly& r3dPoly, std::vector& polyArray); - - void RenderScene(int priority, bool alpha); - float Determinant3x3(const float m[16]); - bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette - bool IsVROMModel(UINT32 modelAddr); - UINT64 GetRomMapKey(int address, int texOffset); - - - /* - * Data - */ - - // Stepping - int m_step; - int m_offset; // offset to subtract for words 3 and higher of culling nodes - float m_vertexFactor; // fixed-point conversion factor for vertices - - // Memory (passed from outside) - const UINT32 *m_cullingRAMLo; // 4 MB - const UINT32 *m_cullingRAMHi; // 1 MB - const UINT32 *m_polyRAM; // 4 MB - const UINT32 *m_vrom; // 64 MB - const UINT16 *m_textureRAM; // 8 MB - - // Resolution and scaling factors (to support resolutions higher than 496x384) and offsets - float m_xRatio, m_yRatio; - unsigned m_xOffs, m_yOffs; - unsigned m_totalXRes, m_totalYRes; - - // Real3D Base Matrix Pointer - const float *m_matrixBasePtr; - - TextureSheet m_texSheet; - NodeAttributes m_nodeAttribs; - Mat4 m_modelMat; // current modelview matrix - int m_listDepth; - - std::vector m_nodes; // build the scene - std::vector m_polyBufferRam; - std::vector m_polyBufferRom; - VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow - - struct ModelKey { - int lutIdx; - int texOffset; - }; - - std::unordered_map m_romMap; - - R3DShader m_r3dShader; - int m_currentVPPriority; -}; - -} // New3D - -#endif // INCLUDED_NEW3D_H