mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-04-10 19:15:14 +00:00
Cache rom models, for better performance.
This commit is contained in:
parent
8488f22ac5
commit
4992e59673
|
@ -35,7 +35,10 @@ struct R3DPoly
|
||||||
|
|
||||||
struct Mesh
|
struct Mesh
|
||||||
{
|
{
|
||||||
std::shared_ptr<Texture> texture;
|
// texture
|
||||||
|
int format, x, y, width, height = 0;
|
||||||
|
bool mirrorU = false;
|
||||||
|
bool mirrorV = false;
|
||||||
|
|
||||||
// attributes
|
// attributes
|
||||||
bool doubleSided = false;
|
bool doubleSided = false;
|
||||||
|
@ -49,10 +52,6 @@ struct Mesh
|
||||||
|
|
||||||
float fogIntensity = 1.0f;
|
float fogIntensity = 1.0f;
|
||||||
|
|
||||||
// texture
|
|
||||||
bool mirrorU = false;
|
|
||||||
bool mirrorV = false;
|
|
||||||
|
|
||||||
// opengl resources
|
// opengl resources
|
||||||
int vboOffset = 0; // this will be calculated later
|
int vboOffset = 0; // this will be calculated later
|
||||||
int triangleCount = 0;
|
int triangleCount = 0;
|
||||||
|
@ -65,14 +64,18 @@ struct SortingMesh : public Mesh // This struct temporarily holds the model dat
|
||||||
|
|
||||||
struct Model
|
struct Model
|
||||||
{
|
{
|
||||||
std::vector<Mesh> meshes;
|
std::shared_ptr<std::vector<Mesh>> 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;
|
||||||
|
|
||||||
//matrices
|
//matrices
|
||||||
float modelMat[16];
|
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
|
float determinant; // we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order
|
||||||
|
|
||||||
// misc
|
|
||||||
int lutIdx = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Viewport
|
struct Viewport
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#include "Vec.h"
|
#include "Vec.h"
|
||||||
#include <cmath> // needed by gcc
|
#include <cmath> // needed by gcc
|
||||||
|
|
||||||
|
#define MAX_RAM_POLYS 100000
|
||||||
|
#define MAX_ROM_POLYS 500000
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265359
|
#define M_PI 3.14159265359
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,7 +24,7 @@ CNew3D::CNew3D()
|
||||||
|
|
||||||
CNew3D::~CNew3D()
|
CNew3D::~CNew3D()
|
||||||
{
|
{
|
||||||
m_vboDynamic.Destroy();
|
m_vbo.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
|
void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
|
||||||
|
@ -50,8 +53,7 @@ void CNew3D::SetStep(int stepID)
|
||||||
m_vertexFactor = (1.0f / 128.0f); // 17.7
|
m_vertexFactor = (1.0f / 128.0f); // 17.7
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vboDynamic.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly)* 100000); // allocate space for 100k polys ~ 10meg
|
m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
|
||||||
//m_vboStatic.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 0x80000); // 64meg buffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
|
bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
|
||||||
|
@ -99,13 +101,13 @@ void CNew3D::RenderScene(int priority, bool alpha)
|
||||||
|
|
||||||
bool matrixLoaded = false;
|
bool matrixLoaded = false;
|
||||||
|
|
||||||
if (m.meshes.empty()) {
|
if (m.meshes->empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_r3dShader.SetModelStates(&m);
|
m_r3dShader.SetModelStates(&m);
|
||||||
|
|
||||||
for (auto &mesh : m.meshes) {
|
for (auto &mesh : *m.meshes) {
|
||||||
|
|
||||||
if (alpha) {
|
if (alpha) {
|
||||||
if (!mesh.textureAlpha && !mesh.polyAlpha) {
|
if (!mesh.textureAlpha && !mesh.polyAlpha) {
|
||||||
|
@ -123,9 +125,12 @@ void CNew3D::RenderScene(int priority, bool alpha)
|
||||||
matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
|
matrixLoaded = true; // do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh.texture) {
|
if (mesh.textured) {
|
||||||
mesh.texture->BindTexture();
|
auto tex = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, mesh.x + m.textureOffsetX, mesh.y + m.textureOffsetY, mesh.width, mesh.height);
|
||||||
mesh.texture->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
|
if (tex) {
|
||||||
|
tex->BindTexture();
|
||||||
|
tex->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_r3dShader.SetMeshUniforms(&mesh);
|
m_r3dShader.SetMeshUniforms(&mesh);
|
||||||
|
@ -141,7 +146,7 @@ void CNew3D::RenderScene(int priority, bool alpha)
|
||||||
void CNew3D::RenderFrame(void)
|
void CNew3D::RenderFrame(void)
|
||||||
{
|
{
|
||||||
// release any resources from last frame
|
// release any resources from last frame
|
||||||
m_polyBuffer.clear(); // clear dyanmic model memory buffer
|
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_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_modelMat.Release(); // would hope we wouldn't need this but no harm in checking
|
||||||
m_nodeAttribs.Reset();
|
m_nodeAttribs.Reset();
|
||||||
|
@ -156,9 +161,29 @@ void CNew3D::RenderFrame(void)
|
||||||
RenderViewport(0x800000, pri); // build model structure
|
RenderViewport(0x800000, pri); // build model structure
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vboDynamic.Bind(true);
|
m_vbo.Bind(true);
|
||||||
m_vboDynamic.BufferSubData(0, m_polyBuffer.size()*sizeof(Poly), m_polyBuffer.data()); // upload all the data to GPU in one go
|
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_vbo.Reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
@ -179,7 +204,7 @@ void CNew3D::RenderFrame(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_r3dShader.SetShader(false); // unbind shader
|
m_r3dShader.SetShader(false); // unbind shader
|
||||||
m_vboDynamic.Bind(false);
|
m_vbo.Bind(false);
|
||||||
|
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
@ -232,7 +257,8 @@ const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
|
||||||
|
|
||||||
bool CNew3D::DrawModel(UINT32 modelAddr)
|
bool CNew3D::DrawModel(UINT32 modelAddr)
|
||||||
{
|
{
|
||||||
const UINT32 *modelAddress;
|
const UINT32* modelAddress;
|
||||||
|
bool cached = false;
|
||||||
Model* m;
|
Model* m;
|
||||||
|
|
||||||
modelAddress = TranslateModelAddress(modelAddr);
|
modelAddress = TranslateModelAddress(modelAddr);
|
||||||
|
@ -240,13 +266,28 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
|
||||||
// create a new model to push onto the vector
|
// create a new model to push onto the vector
|
||||||
m_nodes.back().models.emplace_back(Model());
|
m_nodes.back().models.emplace_back(Model());
|
||||||
|
|
||||||
// get the pointer to the last element in the array
|
// get the last model in the array
|
||||||
m = &m_nodes.back().models.back();
|
m = &m_nodes.back().models.back();
|
||||||
|
|
||||||
// copy lutidx - wtf is this
|
if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
|
||||||
m->lutIdx = modelAddr & 0xFFFFFF;
|
|
||||||
|
|
||||||
// copy model matrix
|
// try to find meshes in the rom cache
|
||||||
|
|
||||||
|
if (m_romMap.count(modelAddr)) {
|
||||||
|
m->meshes = m_romMap[modelAddr];
|
||||||
|
cached = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m->meshes = std::make_shared<std::vector<Mesh>>();
|
||||||
|
m->dynamic = false;
|
||||||
|
m_romMap[modelAddr] = m->meshes; // store meshes in our rom map here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m->meshes = std::make_shared<std::vector<Mesh>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy current model matrix
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
m->modelMat[i] = m_modelMat.currentMatrix[i];
|
m->modelMat[i] = m_modelMat.currentMatrix[i];
|
||||||
}
|
}
|
||||||
|
@ -254,7 +295,13 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
|
||||||
//calculate determinant
|
//calculate determinant
|
||||||
m->determinant = Determinant3x3(m_modelMat);
|
m->determinant = Determinant3x3(m_modelMat);
|
||||||
|
|
||||||
CacheModel(m, modelAddress);
|
// update texture offsets
|
||||||
|
m->textureOffsetX = m_nodeAttribs.currentTexOffsetX;
|
||||||
|
m->textureOffsetY = m_nodeAttribs.currentTexOffsetY;
|
||||||
|
|
||||||
|
if (!cached) {
|
||||||
|
CacheModel(m, modelAddress);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -763,7 +810,6 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
UINT64 lastHash = -1;
|
UINT64 lastHash = -1;
|
||||||
SortingMesh* currentMesh = nullptr;
|
SortingMesh* currentMesh = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<Texture> tex;
|
|
||||||
std::map<UINT64, SortingMesh> sMap;
|
std::map<UINT64, SortingMesh> sMap;
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
|
@ -800,7 +846,7 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
data += 7; // data will now point to first vertex
|
data += 7; // data will now point to first vertex
|
||||||
|
|
||||||
// create a hash value based on poly attributes -todo add more attributes
|
// create a hash value based on poly attributes -todo add more attributes
|
||||||
auto hash = ph.Hash(m_nodeAttribs.currentTexOffsetX, m_nodeAttribs.currentTexOffsetY);
|
auto hash = ph.Hash();
|
||||||
|
|
||||||
if (hash != lastHash && validPoly) {
|
if (hash != lastHash && validPoly) {
|
||||||
|
|
||||||
|
@ -815,18 +861,12 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
|
|
||||||
//copy attributes
|
//copy attributes
|
||||||
currentMesh->doubleSided = ph.DoubleSided();
|
currentMesh->doubleSided = ph.DoubleSided();
|
||||||
currentMesh->mirrorU = ph.TexUMirror();
|
|
||||||
currentMesh->mirrorV = ph.TexVMirror();
|
|
||||||
currentMesh->textured = ph.TexEnabled();
|
currentMesh->textured = ph.TexEnabled();
|
||||||
currentMesh->alphaTest = ph.AlphaTest();
|
currentMesh->alphaTest = ph.AlphaTest();
|
||||||
currentMesh->textureAlpha = ph.TextureAlpha();
|
currentMesh->textureAlpha = ph.TextureAlpha();
|
||||||
currentMesh->polyAlpha = ph.PolyAlpha();
|
currentMesh->polyAlpha = ph.PolyAlpha();
|
||||||
currentMesh->lighting = ph.LightEnabled();
|
currentMesh->lighting = ph.LightEnabled();
|
||||||
|
|
||||||
if (ph.header[6] & 0x10000) {
|
|
||||||
currentMesh->testBit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ph.Luminous()) {
|
if (!ph.Luminous()) {
|
||||||
currentMesh->fogIntensity = 1.0f;
|
currentMesh->fogIntensity = 1.0f;
|
||||||
}
|
}
|
||||||
|
@ -835,18 +875,17 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ph.TexEnabled()) {
|
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->format = ph.TexFormat();
|
||||||
|
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 = &sMap[hash];
|
currentMesh = &sMap[hash];
|
||||||
|
|
||||||
if (ph.TexEnabled()) {
|
|
||||||
tex = currentMesh->texture;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tex = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validPoly) {
|
if (validPoly) {
|
||||||
|
@ -917,8 +956,8 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
float texU, texV = 0;
|
float texU, texV = 0;
|
||||||
|
|
||||||
// tex coords
|
// tex coords
|
||||||
if (tex) {
|
if (validPoly && currentMesh->textured) {
|
||||||
tex->GetCoordinates((UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
|
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[0] = texU;
|
||||||
|
@ -942,21 +981,31 @@ void CNew3D::CacheModel(Model *m, const UINT32 *data)
|
||||||
//sorted the data, now copy to main data structures
|
//sorted the data, now copy to main data structures
|
||||||
|
|
||||||
// we know how many meshes we have so reserve appropriate space
|
// we know how many meshes we have so reserve appropriate space
|
||||||
m->meshes.reserve(sMap.size());
|
m->meshes->reserve(sMap.size());
|
||||||
|
|
||||||
for (auto& it : sMap) {
|
for (auto& it : sMap) {
|
||||||
|
|
||||||
// calculate VBO values for current mesh
|
if (m->dynamic) {
|
||||||
it.second.vboOffset = m_polyBuffer.size();
|
|
||||||
it.second.triangleCount = it.second.polys.size();
|
|
||||||
//it.second.clockWise = cw;
|
|
||||||
|
|
||||||
// copy poly data to main buffer
|
// calculate VBO values for current mesh
|
||||||
m_polyBuffer.insert(m_polyBuffer.end(), it.second.polys.begin(), it.second.polys.end());
|
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
|
//copy the temp mesh into the model structure
|
||||||
//this will lose the associated vertex data, which is now copied to the main buffer anyway
|
//this will lose the associated vertex data, which is now copied to the main buffer anyway
|
||||||
m->meshes.push_back(it.second);
|
m->meshes->push_back(it.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,4 +1047,9 @@ bool CNew3D::IsDynamicModel(UINT32 *data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNew3D::IsVROMModel(UINT32 modelAddr)
|
||||||
|
{
|
||||||
|
return modelAddr >= 0x100000;
|
||||||
|
}
|
||||||
|
|
||||||
} // New3D
|
} // New3D
|
||||||
|
|
|
@ -172,6 +172,8 @@ private:
|
||||||
void RenderScene(int priority, bool alpha);
|
void RenderScene(int priority, bool alpha);
|
||||||
float Determinant3x3(const float m[16]);
|
float Determinant3x3(const float m[16]);
|
||||||
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
|
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
|
||||||
|
bool IsVROMModel(UINT32 modelAddr);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data
|
* Data
|
||||||
|
@ -199,14 +201,15 @@ private:
|
||||||
|
|
||||||
TextureSheet m_texSheet;
|
TextureSheet m_texSheet;
|
||||||
NodeAttributes m_nodeAttribs;
|
NodeAttributes m_nodeAttribs;
|
||||||
Mat4 m_modelMat; // current modelview matrix
|
Mat4 m_modelMat; // current modelview matrix
|
||||||
int m_listDepth;
|
int m_listDepth;
|
||||||
|
|
||||||
std::vector<Node> m_nodes; // build the scene
|
std::vector<Node> m_nodes; // this represents the entire render frame
|
||||||
std::vector<Poly> m_polyBuffer; // we actually hold the vertex data here, one buffer to send to opengl, instead of 2000+ small ones.
|
std::vector<Poly> m_polyBufferRam; // dynamic polys
|
||||||
|
std::vector<Poly> m_polyBufferRom; // rom polys
|
||||||
|
std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
|
||||||
|
|
||||||
VBO m_vboDynamic; // dynamic data from poly ram, rom polys can go in a different buffer
|
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
|
||||||
VBO m_vboStatic; // for ROM models
|
|
||||||
|
|
||||||
R3DShader m_r3dShader;
|
R3DShader m_r3dShader;
|
||||||
int m_currentVPPriority;
|
int m_currentVPPriority;
|
||||||
|
|
|
@ -190,18 +190,18 @@ int PolyHeader::Page()
|
||||||
// header 5
|
// header 5
|
||||||
//
|
//
|
||||||
|
|
||||||
int PolyHeader::X(int textureXOffset)
|
int PolyHeader::X()
|
||||||
{
|
{
|
||||||
//====
|
//====
|
||||||
int x;
|
int x;
|
||||||
//====
|
//====
|
||||||
|
|
||||||
x = (32 * (((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 1))) + textureXOffset;
|
x = (32 * (((header[4] & 0x1F) << 1) | ((header[5] >> 7) & 1)));
|
||||||
x &= 2047;
|
x &= 2047;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PolyHeader::Y(int textureYOffset)
|
int PolyHeader::Y()
|
||||||
{
|
{
|
||||||
//=======
|
//=======
|
||||||
int y;
|
int y;
|
||||||
|
@ -215,7 +215,7 @@ int PolyHeader::Y(int textureYOffset)
|
||||||
page = 0;
|
page = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
y = (32 * (header[5] & 0x1F) + page) + textureYOffset; // if we hit 2nd page add 1024 to y coordinate
|
y = (32 * (header[5] & 0x1F) + page); // if we hit 2nd page add 1024 to y coordinate
|
||||||
y &= 2047;
|
y &= 2047;
|
||||||
|
|
||||||
return y;
|
return y;
|
||||||
|
@ -289,15 +289,15 @@ float PolyHeader::LightModifier()
|
||||||
// misc
|
// misc
|
||||||
//
|
//
|
||||||
|
|
||||||
UINT64 PolyHeader::Hash(int textureXOffset, int textureYOffset)
|
UINT64 PolyHeader::Hash()
|
||||||
{
|
{
|
||||||
UINT64 hash = 0;
|
UINT64 hash = 0;
|
||||||
|
|
||||||
hash |= (header[2] & 3); // bits 0-1 uv mirror bits
|
hash |= (header[2] & 3); // bits 0-1 uv mirror bits
|
||||||
hash |= (UINT64)((header[3] >> 0) & 7) << 2; // bits 2-4 tex height
|
hash |= (UINT64)((header[3] >> 0) & 7) << 2; // bits 2-4 tex height
|
||||||
hash |= (UINT64)((header[3] >> 3) & 7) << 5; // bits 5-7 tex width
|
hash |= (UINT64)((header[3] >> 3) & 7) << 5; // bits 5-7 tex width
|
||||||
hash |= (UINT64)X(textureXOffset) << 8; // bits 8-17 x offset
|
hash |= (UINT64)X() << 8; // bits 8-17 x offset
|
||||||
hash |= (UINT64)Y(textureYOffset) << 18; // bits 18-27 y offset
|
hash |= (UINT64)Y() << 18; // bits 18-27 y offset
|
||||||
hash |= (UINT64)TexFormat() << 28; // bits 28-30 tex format
|
hash |= (UINT64)TexFormat() << 28; // bits 28-30 tex format
|
||||||
hash |= (UINT64)TexEnabled() << 31; // bits 31 textures enabled
|
hash |= (UINT64)TexEnabled() << 31; // bits 31 textures enabled
|
||||||
hash |= (UINT64)LightEnabled() << 32; // bits 32 light enabled
|
hash |= (UINT64)LightEnabled() << 32; // bits 32 light enabled
|
||||||
|
|
|
@ -108,8 +108,8 @@ public:
|
||||||
int Page();
|
int Page();
|
||||||
|
|
||||||
// header 5
|
// header 5
|
||||||
int X(int textureXOffset);
|
int X();
|
||||||
int Y(int textureYOffset);
|
int Y();
|
||||||
|
|
||||||
//header 6
|
//header 6
|
||||||
int TexFormat();
|
int TexFormat();
|
||||||
|
@ -126,7 +126,7 @@ public:
|
||||||
float LightModifier();
|
float LightModifier();
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
UINT64 Hash(int textureXOffset, int textureYOffset); // make a unique hash for sorting by state
|
UINT64 Hash(); // make a unique hash for sorting by state
|
||||||
|
|
||||||
|
|
||||||
//=============
|
//=============
|
||||||
|
|
|
@ -42,8 +42,14 @@ void Texture::BindTexture()
|
||||||
|
|
||||||
void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
|
void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
|
||||||
{
|
{
|
||||||
uOut = ((uIn*uvScale)+0.0f) / m_width;
|
uOut = (uIn*uvScale) / m_width;
|
||||||
vOut = ((vIn*uvScale)+0.0f) / m_height;
|
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)
|
void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
|
||||||
|
|
|
@ -23,6 +23,8 @@ public:
|
||||||
void GetDetails (int& x, int&y, int& width, int& height, int& format);
|
void GetDetails (int& x, int&y, int& width, int& height, int& format);
|
||||||
void SetWrapMode (bool mirrorU, bool mirrorV);
|
void SetWrapMode (bool mirrorU, bool mirrorV);
|
||||||
|
|
||||||
|
static void GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
|
@ -30,6 +30,10 @@ void VBO::BufferSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data)
|
||||||
|
|
||||||
bool VBO::AppendData(GLsizeiptr size, const GLvoid* data)
|
bool VBO::AppendData(GLsizeiptr size, const GLvoid* data)
|
||||||
{
|
{
|
||||||
|
if (size == 0 || !data) {
|
||||||
|
return true; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
if (m_size + size >= m_capacity) {
|
if (m_size + size >= m_capacity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue