dolphin/Source/Core/VideoCommon/VertexShaderManager.cpp
Linktothepast 82f772fdcc Remove the extra parameters field from the PH.
Metroid: Other M was the only game which required this field, but the
issue in that game can be fixed properly by enabling format change
emulation. Hence, there's no point in having this around anymore.
Fixes issue 6644.
2014-03-15 15:04:39 +02:00

694 lines
21 KiB
C++

// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <cmath>
#include <sstream>
#include "Common/Common.h"
#include "Common/MathUtil.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
float GC_ALIGNED16(g_fProjectionMatrix[16]);
// track changes
static bool bTexMatricesChanged[2], bPosNormalMatrixChanged, bProjectionChanged, bViewportChanged;
static int nMaterialsChanged;
static int nTransformMatricesChanged[2]; // min,max
static int nNormalMatricesChanged[2]; // min,max
static int nPostTransformMatricesChanged[2]; // min,max
static int nLightsChanged[2]; // min,max
static Matrix44 s_viewportCorrection;
static Matrix33 s_viewRotationMatrix;
static Matrix33 s_viewInvRotationMatrix;
static float s_fViewTranslationVector[3];
static float s_fViewRotation[2];
VertexShaderConstants VertexShaderManager::constants;
bool VertexShaderManager::dirty;
struct ProjectionHack
{
float sign;
float value;
ProjectionHack() { }
ProjectionHack(float new_sign, float new_value)
: sign(new_sign), value(new_value) {}
};
namespace
{
// Control Variables
static ProjectionHack g_ProjHack1;
static ProjectionHack g_ProjHack2;
} // Namespace
float PHackValue(std::string sValue)
{
float f = 0;
bool fp = false;
const char *cStr = sValue.c_str();
char *c = new char[strlen(cStr)+1];
std::istringstream sTof("");
for (unsigned int i=0; i<=strlen(cStr); ++i)
{
if (i == 20)
{
c[i] = '\0';
break;
}
c[i] = (cStr[i] == ',') ? '.' : *(cStr+i);
if (c[i] == '.')
fp = true;
}
cStr = c;
sTof.str(cStr);
sTof >> f;
if (!fp)
f /= 0xF4240;
delete [] c;
return f;
}
void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[])
{
float fhackvalue1 = 0, fhackvalue2 = 0;
float fhacksign1 = 1.0, fhacksign2 = 1.0;
const char *sTemp[2];
if (iPhackvalue[0] == 1)
{
NOTICE_LOG(VIDEO, "\t\t--- Orthographic Projection Hack ON ---");
fhacksign1 *= (iPhackvalue[1] == 1) ? -1.0f : fhacksign1;
sTemp[0] = (iPhackvalue[1] == 1) ? " * (-1)" : "";
fhacksign2 *= (iPhackvalue[2] == 1) ? -1.0f : fhacksign2;
sTemp[1] = (iPhackvalue[2] == 1) ? " * (-1)" : "";
fhackvalue1 = PHackValue(sPhackvalue[0]);
NOTICE_LOG(VIDEO, "- zNear Correction = (%f + zNear)%s", fhackvalue1, sTemp[0]);
fhackvalue2 = PHackValue(sPhackvalue[1]);
NOTICE_LOG(VIDEO, "- zFar Correction = (%f + zFar)%s", fhackvalue2, sTemp[1]);
}
// Set the projections hacks
g_ProjHack1 = ProjectionHack(fhacksign1, fhackvalue1);
g_ProjHack2 = ProjectionHack(fhacksign2, fhackvalue2);
}
// Viewport correction:
// In D3D, the viewport rectangle must fit within the render target.
// Say you want a viewport at (ix, iy) with size (iw, ih),
// but your viewport must be clamped at (ax, ay) with size (aw, ah).
// Just multiply the projection matrix with the following to get the same
// effect:
// [ (iw/aw) 0 0 ((iw - 2*(ax-ix)) / aw - 1) ]
// [ 0 (ih/ah) 0 ((-ih + 2*(ay-iy)) / ah + 1) ]
// [ 0 0 1 0 ]
// [ 0 0 0 1 ]
static void ViewportCorrectionMatrix(Matrix44& result)
{
int scissorXOff = bpmem.scissorOffset.x * 2;
int scissorYOff = bpmem.scissorOffset.y * 2;
// TODO: ceil, floor or just cast to int?
// TODO: Directly use the floats instead of rounding them?
float intendedX = xfregs.viewport.xOrig - xfregs.viewport.wd - scissorXOff;
float intendedY = xfregs.viewport.yOrig + xfregs.viewport.ht - scissorYOff;
float intendedWd = 2.0f * xfregs.viewport.wd;
float intendedHt = -2.0f * xfregs.viewport.ht;
if (intendedWd < 0.f)
{
intendedX += intendedWd;
intendedWd = -intendedWd;
}
if (intendedHt < 0.f)
{
intendedY += intendedHt;
intendedHt = -intendedHt;
}
// fit to EFB size
float X = (intendedX >= 0.f) ? intendedX : 0.f;
float Y = (intendedY >= 0.f) ? intendedY : 0.f;
float Wd = (X + intendedWd <= EFB_WIDTH) ? intendedWd : (EFB_WIDTH - X);
float Ht = (Y + intendedHt <= EFB_HEIGHT) ? intendedHt : (EFB_HEIGHT - Y);
Matrix44::LoadIdentity(result);
if (Wd == 0 || Ht == 0)
return;
result.data[4*0+0] = intendedWd / Wd;
result.data[4*0+3] = (intendedWd - 2.f * (X - intendedX)) / Wd - 1.f;
result.data[4*1+1] = intendedHt / Ht;
result.data[4*1+3] = (-intendedHt + 2.f * (Y - intendedY)) / Ht + 1.f;
}
void VertexShaderManager::Init()
{
Dirty();
memset(&xfregs, 0, sizeof(xfregs));
memset(xfmem, 0, sizeof(xfmem));
memset(&constants, 0 , sizeof(constants));
ResetView();
// TODO: should these go inside ResetView()?
Matrix44::LoadIdentity(s_viewportCorrection);
memset(g_fProjectionMatrix, 0, sizeof(g_fProjectionMatrix));
for (int i = 0; i < 4; ++i)
g_fProjectionMatrix[i*5] = 1.0f;
}
void VertexShaderManager::Shutdown()
{
}
void VertexShaderManager::Dirty()
{
nTransformMatricesChanged[0] = 0;
nTransformMatricesChanged[1] = 256;
nNormalMatricesChanged[0] = 0;
nNormalMatricesChanged[1] = 96;
nPostTransformMatricesChanged[0] = 0;
nPostTransformMatricesChanged[1] = 256;
nLightsChanged[0] = 0;
nLightsChanged[1] = 0x80;
bPosNormalMatrixChanged = true;
bTexMatricesChanged[0] = true;
bTexMatricesChanged[1] = true;
bProjectionChanged = true;
nMaterialsChanged = 15;
dirty = true;
}
// Syncs the shader constant buffers with xfmem
// TODO: A cleaner way to control the matrices without making a mess in the parameters field
void VertexShaderManager::SetConstants()
{
if (nTransformMatricesChanged[0] >= 0)
{
int startn = nTransformMatricesChanged[0] / 4;
int endn = (nTransformMatricesChanged[1] + 3) / 4;
memcpy(constants.transformmatrices[startn], &xfmem[startn * 4], (endn - startn) * 16);
dirty = true;
nTransformMatricesChanged[0] = nTransformMatricesChanged[1] = -1;
}
if (nNormalMatricesChanged[0] >= 0)
{
int startn = nNormalMatricesChanged[0] / 3;
int endn = (nNormalMatricesChanged[1] + 2) / 3;
for (int i=startn; i<endn; i++)
{
memcpy(constants.normalmatrices[i], &xfmem[XFMEM_NORMALMATRICES + 3*i], 12);
}
dirty = true;
nNormalMatricesChanged[0] = nNormalMatricesChanged[1] = -1;
}
if (nPostTransformMatricesChanged[0] >= 0)
{
int startn = nPostTransformMatricesChanged[0] / 4;
int endn = (nPostTransformMatricesChanged[1] + 3 ) / 4;
memcpy(constants.posttransformmatrices[startn], &xfmem[XFMEM_POSTMATRICES + startn * 4], (endn - startn) * 16);
dirty = true;
nPostTransformMatricesChanged[0] = nPostTransformMatricesChanged[1] = -1;
}
if (nLightsChanged[0] >= 0)
{
// TODO: Outdated comment
// lights don't have a 1 to 1 mapping, the color component needs to be converted to 4 floats
int istart = nLightsChanged[0] / 0x10;
int iend = (nLightsChanged[1] + 15) / 0x10;
const float* xfmemptr = (const float*)&xfmem[0x10 * istart + XFMEM_LIGHTS];
for (int i = istart; i < iend; ++i)
{
u32 color = *(const u32*)(xfmemptr + 3);
constants.light_colors[i][0] = (color >> 24) & 0xFF;
constants.light_colors[i][1] = (color >> 16) & 0xFF;
constants.light_colors[i][2] = (color >> 8) & 0xFF;
constants.light_colors[i][3] = (color) & 0xFF;
xfmemptr += 4;
for (int j = 0; j < 4; ++j, xfmemptr += 3)
{
if (j == 1 &&
fabs(xfmemptr[0]) < 0.00001f &&
fabs(xfmemptr[1]) < 0.00001f &&
fabs(xfmemptr[2]) < 0.00001f)
{
// dist attenuation, make sure not equal to 0!!!
constants.lights[4*i+j][0] = 0.00001f;
}
else
constants.lights[4*i+j][0] = xfmemptr[0];
constants.lights[4*i+j][1] = xfmemptr[1];
constants.lights[4*i+j][2] = xfmemptr[2];
}
}
dirty = true;
nLightsChanged[0] = nLightsChanged[1] = -1;
}
if (nMaterialsChanged)
{
for (int i = 0; i < 2; ++i)
{
if (nMaterialsChanged & (1 << i))
{
u32 data = *(xfregs.ambColor + i);
constants.materials[i][0] = (data >> 24) & 0xFF;
constants.materials[i][1] = (data >> 16) & 0xFF;
constants.materials[i][2] = (data >> 8) & 0xFF;
constants.materials[i][3] = data & 0xFF;
}
}
for (int i = 0; i < 2; ++i)
{
if (nMaterialsChanged & (1 << (i + 2)))
{
u32 data = *(xfregs.matColor + i);
constants.materials[i+2][0] = (data >> 24) & 0xFF;
constants.materials[i+2][1] = (data >> 16) & 0xFF;
constants.materials[i+2][2] = (data >> 8) & 0xFF;
constants.materials[i+2][3] = data & 0xFF;
}
}
dirty = true;
nMaterialsChanged = 0;
}
if (bPosNormalMatrixChanged)
{
bPosNormalMatrixChanged = false;
const float *pos = (const float *)xfmem + MatrixIndexA.PosNormalMtxIdx * 4;
const float *norm = (const float *)xfmem + XFMEM_NORMALMATRICES + 3 * (MatrixIndexA.PosNormalMtxIdx & 31);
memcpy(constants.posnormalmatrix, pos, 3*16);
memcpy(constants.posnormalmatrix[3], norm, 12);
memcpy(constants.posnormalmatrix[4], norm+3, 12);
memcpy(constants.posnormalmatrix[5], norm+6, 12);
dirty = true;
}
if (bTexMatricesChanged[0])
{
bTexMatricesChanged[0] = false;
const float *fptrs[] =
{
(const float *)xfmem + MatrixIndexA.Tex0MtxIdx * 4, (const float *)xfmem + MatrixIndexA.Tex1MtxIdx * 4,
(const float *)xfmem + MatrixIndexA.Tex2MtxIdx * 4, (const float *)xfmem + MatrixIndexA.Tex3MtxIdx * 4
};
for (int i = 0; i < 4; ++i)
{
memcpy(constants.texmatrices[3*i], fptrs[i], 3*16);
}
dirty = true;
}
if (bTexMatricesChanged[1])
{
bTexMatricesChanged[1] = false;
const float *fptrs[] = {
(const float *)xfmem + MatrixIndexB.Tex4MtxIdx * 4, (const float *)xfmem + MatrixIndexB.Tex5MtxIdx * 4,
(const float *)xfmem + MatrixIndexB.Tex6MtxIdx * 4, (const float *)xfmem + MatrixIndexB.Tex7MtxIdx * 4
};
for (int i = 0; i < 4; ++i)
{
memcpy(constants.texmatrices[3*i+12], fptrs[i], 3*16);
}
dirty = true;
}
if (bViewportChanged)
{
bViewportChanged = false;
constants.depthparams[0] = xfregs.viewport.farZ / 16777216.0f;
constants.depthparams[1] = xfregs.viewport.zRange / 16777216.0f;
dirty = true;
// This is so implementation-dependent that we can't have it here.
g_renderer->SetViewport();
// Update projection if the viewport isn't 1:1 useable
if (!g_ActiveConfig.backend_info.bSupportsOversizedViewports)
{
ViewportCorrectionMatrix(s_viewportCorrection);
bProjectionChanged = true;
}
}
if (bProjectionChanged)
{
bProjectionChanged = false;
float *rawProjection = xfregs.projection.rawProjection;
switch (xfregs.projection.type)
{
case GX_PERSPECTIVE:
g_fProjectionMatrix[0] = rawProjection[0] * g_ActiveConfig.fAspectRatioHackW;
g_fProjectionMatrix[1] = 0.0f;
g_fProjectionMatrix[2] = rawProjection[1];
g_fProjectionMatrix[3] = 0.0f;
g_fProjectionMatrix[4] = 0.0f;
g_fProjectionMatrix[5] = rawProjection[2] * g_ActiveConfig.fAspectRatioHackH;
g_fProjectionMatrix[6] = rawProjection[3];
g_fProjectionMatrix[7] = 0.0f;
g_fProjectionMatrix[8] = 0.0f;
g_fProjectionMatrix[9] = 0.0f;
g_fProjectionMatrix[10] = rawProjection[4];
g_fProjectionMatrix[11] = rawProjection[5];
g_fProjectionMatrix[12] = 0.0f;
g_fProjectionMatrix[13] = 0.0f;
// donkopunchstania suggested the GC GPU might round differently
// He had thus changed this to -(1 + epsilon) to fix clipping issues.
// I (neobrain) don't think his conjecture is true and thus reverted his change.
g_fProjectionMatrix[14] = -1.0f;
g_fProjectionMatrix[15] = 0.0f;
SETSTAT_FT(stats.gproj_0, g_fProjectionMatrix[0]);
SETSTAT_FT(stats.gproj_1, g_fProjectionMatrix[1]);
SETSTAT_FT(stats.gproj_2, g_fProjectionMatrix[2]);
SETSTAT_FT(stats.gproj_3, g_fProjectionMatrix[3]);
SETSTAT_FT(stats.gproj_4, g_fProjectionMatrix[4]);
SETSTAT_FT(stats.gproj_5, g_fProjectionMatrix[5]);
SETSTAT_FT(stats.gproj_6, g_fProjectionMatrix[6]);
SETSTAT_FT(stats.gproj_7, g_fProjectionMatrix[7]);
SETSTAT_FT(stats.gproj_8, g_fProjectionMatrix[8]);
SETSTAT_FT(stats.gproj_9, g_fProjectionMatrix[9]);
SETSTAT_FT(stats.gproj_10, g_fProjectionMatrix[10]);
SETSTAT_FT(stats.gproj_11, g_fProjectionMatrix[11]);
SETSTAT_FT(stats.gproj_12, g_fProjectionMatrix[12]);
SETSTAT_FT(stats.gproj_13, g_fProjectionMatrix[13]);
SETSTAT_FT(stats.gproj_14, g_fProjectionMatrix[14]);
SETSTAT_FT(stats.gproj_15, g_fProjectionMatrix[15]);
break;
case GX_ORTHOGRAPHIC:
g_fProjectionMatrix[0] = rawProjection[0];
g_fProjectionMatrix[1] = 0.0f;
g_fProjectionMatrix[2] = 0.0f;
g_fProjectionMatrix[3] = rawProjection[1];
g_fProjectionMatrix[4] = 0.0f;
g_fProjectionMatrix[5] = rawProjection[2];
g_fProjectionMatrix[6] = 0.0f;
g_fProjectionMatrix[7] = rawProjection[3];
g_fProjectionMatrix[8] = 0.0f;
g_fProjectionMatrix[9] = 0.0f;
g_fProjectionMatrix[10] = (g_ProjHack1.value + rawProjection[4]) * ((g_ProjHack1.sign == 0) ? 1.0f : g_ProjHack1.sign);
g_fProjectionMatrix[11] = (g_ProjHack2.value + rawProjection[5]) * ((g_ProjHack2.sign == 0) ? 1.0f : g_ProjHack2.sign);
g_fProjectionMatrix[12] = 0.0f;
g_fProjectionMatrix[13] = 0.0f;
g_fProjectionMatrix[14] = 0.0f;
g_fProjectionMatrix[15] = 1.0f;
SETSTAT_FT(stats.g2proj_0, g_fProjectionMatrix[0]);
SETSTAT_FT(stats.g2proj_1, g_fProjectionMatrix[1]);
SETSTAT_FT(stats.g2proj_2, g_fProjectionMatrix[2]);
SETSTAT_FT(stats.g2proj_3, g_fProjectionMatrix[3]);
SETSTAT_FT(stats.g2proj_4, g_fProjectionMatrix[4]);
SETSTAT_FT(stats.g2proj_5, g_fProjectionMatrix[5]);
SETSTAT_FT(stats.g2proj_6, g_fProjectionMatrix[6]);
SETSTAT_FT(stats.g2proj_7, g_fProjectionMatrix[7]);
SETSTAT_FT(stats.g2proj_8, g_fProjectionMatrix[8]);
SETSTAT_FT(stats.g2proj_9, g_fProjectionMatrix[9]);
SETSTAT_FT(stats.g2proj_10, g_fProjectionMatrix[10]);
SETSTAT_FT(stats.g2proj_11, g_fProjectionMatrix[11]);
SETSTAT_FT(stats.g2proj_12, g_fProjectionMatrix[12]);
SETSTAT_FT(stats.g2proj_13, g_fProjectionMatrix[13]);
SETSTAT_FT(stats.g2proj_14, g_fProjectionMatrix[14]);
SETSTAT_FT(stats.g2proj_15, g_fProjectionMatrix[15]);
SETSTAT_FT(stats.proj_0, rawProjection[0]);
SETSTAT_FT(stats.proj_1, rawProjection[1]);
SETSTAT_FT(stats.proj_2, rawProjection[2]);
SETSTAT_FT(stats.proj_3, rawProjection[3]);
SETSTAT_FT(stats.proj_4, rawProjection[4]);
SETSTAT_FT(stats.proj_5, rawProjection[5]);
break;
default:
ERROR_LOG(VIDEO, "Unknown projection type: %d", xfregs.projection.type);
}
PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]);
if ((g_ActiveConfig.bFreeLook || g_ActiveConfig.bAnaglyphStereo ) && xfregs.projection.type == GX_PERSPECTIVE)
{
Matrix44 mtxA;
Matrix44 mtxB;
Matrix44 viewMtx;
Matrix44::Translate(mtxA, s_fViewTranslationVector);
Matrix44::LoadMatrix33(mtxB, s_viewRotationMatrix);
Matrix44::Multiply(mtxB, mtxA, viewMtx); // view = rotation x translation
Matrix44::Set(mtxB, g_fProjectionMatrix);
Matrix44::Multiply(mtxB, viewMtx, mtxA); // mtxA = projection x view
Matrix44::Multiply(s_viewportCorrection, mtxA, mtxB); // mtxB = viewportCorrection x mtxA
memcpy(constants.projection, mtxB.data, 4*16);
}
else
{
Matrix44 projMtx;
Matrix44::Set(projMtx, g_fProjectionMatrix);
Matrix44 correctedMtx;
Matrix44::Multiply(s_viewportCorrection, projMtx, correctedMtx);
memcpy(constants.projection, correctedMtx.data, 4*16);
}
dirty = true;
}
}
void VertexShaderManager::InvalidateXFRange(int start, int end)
{
if (((u32)start >= (u32)MatrixIndexA.PosNormalMtxIdx * 4 &&
(u32)start < (u32)MatrixIndexA.PosNormalMtxIdx * 4 + 12) ||
((u32)start >= XFMEM_NORMALMATRICES + ((u32)MatrixIndexA.PosNormalMtxIdx & 31) * 3 &&
(u32)start < XFMEM_NORMALMATRICES + ((u32)MatrixIndexA.PosNormalMtxIdx & 31) * 3 + 9))
{
bPosNormalMatrixChanged = true;
}
if (((u32)start >= (u32)MatrixIndexA.Tex0MtxIdx*4 && (u32)start < (u32)MatrixIndexA.Tex0MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexA.Tex1MtxIdx*4 && (u32)start < (u32)MatrixIndexA.Tex1MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexA.Tex2MtxIdx*4 && (u32)start < (u32)MatrixIndexA.Tex2MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexA.Tex3MtxIdx*4 && (u32)start < (u32)MatrixIndexA.Tex3MtxIdx*4+12))
{
bTexMatricesChanged[0] = true;
}
if (((u32)start >= (u32)MatrixIndexB.Tex4MtxIdx*4 && (u32)start < (u32)MatrixIndexB.Tex4MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexB.Tex5MtxIdx*4 && (u32)start < (u32)MatrixIndexB.Tex5MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexB.Tex6MtxIdx*4 && (u32)start < (u32)MatrixIndexB.Tex6MtxIdx*4+12) ||
((u32)start >= (u32)MatrixIndexB.Tex7MtxIdx*4 && (u32)start < (u32)MatrixIndexB.Tex7MtxIdx*4+12))
{
bTexMatricesChanged[1] = true;
}
if (start < XFMEM_POSMATRICES_END)
{
if (nTransformMatricesChanged[0] == -1)
{
nTransformMatricesChanged[0] = start;
nTransformMatricesChanged[1] = end>XFMEM_POSMATRICES_END?XFMEM_POSMATRICES_END:end;
}
else
{
if (nTransformMatricesChanged[0] > start) nTransformMatricesChanged[0] = start;
if (nTransformMatricesChanged[1] < end) nTransformMatricesChanged[1] = end>XFMEM_POSMATRICES_END?XFMEM_POSMATRICES_END:end;
}
}
if (start < XFMEM_NORMALMATRICES_END && end > XFMEM_NORMALMATRICES)
{
int _start = start < XFMEM_NORMALMATRICES ? 0 : start-XFMEM_NORMALMATRICES;
int _end = end < XFMEM_NORMALMATRICES_END ? end-XFMEM_NORMALMATRICES : XFMEM_NORMALMATRICES_END-XFMEM_NORMALMATRICES;
if (nNormalMatricesChanged[0] == -1)
{
nNormalMatricesChanged[0] = _start;
nNormalMatricesChanged[1] = _end;
}
else
{
if (nNormalMatricesChanged[0] > _start) nNormalMatricesChanged[0] = _start;
if (nNormalMatricesChanged[1] < _end) nNormalMatricesChanged[1] = _end;
}
}
if (start < XFMEM_POSTMATRICES_END && end > XFMEM_POSTMATRICES)
{
int _start = start < XFMEM_POSTMATRICES ? XFMEM_POSTMATRICES : start-XFMEM_POSTMATRICES;
int _end = end < XFMEM_POSTMATRICES_END ? end-XFMEM_POSTMATRICES : XFMEM_POSTMATRICES_END-XFMEM_POSTMATRICES;
if (nPostTransformMatricesChanged[0] == -1)
{
nPostTransformMatricesChanged[0] = _start;
nPostTransformMatricesChanged[1] = _end;
}
else
{
if (nPostTransformMatricesChanged[0] > _start) nPostTransformMatricesChanged[0] = _start;
if (nPostTransformMatricesChanged[1] < _end) nPostTransformMatricesChanged[1] = _end;
}
}
if (start < XFMEM_LIGHTS_END && end > XFMEM_LIGHTS)
{
int _start = start < XFMEM_LIGHTS ? XFMEM_LIGHTS : start-XFMEM_LIGHTS;
int _end = end < XFMEM_LIGHTS_END ? end-XFMEM_LIGHTS : XFMEM_LIGHTS_END-XFMEM_LIGHTS;
if (nLightsChanged[0] == -1 )
{
nLightsChanged[0] = _start;
nLightsChanged[1] = _end;
}
else
{
if (nLightsChanged[0] > _start) nLightsChanged[0] = _start;
if (nLightsChanged[1] < _end) nLightsChanged[1] = _end;
}
}
}
void VertexShaderManager::SetTexMatrixChangedA(u32 Value)
{
if (MatrixIndexA.Hex != Value)
{
VertexManager::Flush();
if (MatrixIndexA.PosNormalMtxIdx != (Value&0x3f))
bPosNormalMatrixChanged = true;
bTexMatricesChanged[0] = true;
MatrixIndexA.Hex = Value;
}
}
void VertexShaderManager::SetTexMatrixChangedB(u32 Value)
{
if (MatrixIndexB.Hex != Value)
{
VertexManager::Flush();
bTexMatricesChanged[1] = true;
MatrixIndexB.Hex = Value;
}
}
void VertexShaderManager::SetViewportChanged()
{
bViewportChanged = true;
}
void VertexShaderManager::SetProjectionChanged()
{
bProjectionChanged = true;
}
void VertexShaderManager::SetMaterialColorChanged(int index, u32 color)
{
nMaterialsChanged |= (1 << index);
}
void VertexShaderManager::TranslateView(float x, float y, float z)
{
float result[3];
float vector[3] = { x,z,y };
Matrix33::Multiply(s_viewInvRotationMatrix, vector, result);
for (int i = 0; i < 3; i++)
s_fViewTranslationVector[i] += result[i];
bProjectionChanged = true;
}
void VertexShaderManager::RotateView(float x, float y)
{
s_fViewRotation[0] += x;
s_fViewRotation[1] += y;
Matrix33 mx;
Matrix33 my;
Matrix33::RotateX(mx, s_fViewRotation[1]);
Matrix33::RotateY(my, s_fViewRotation[0]);
Matrix33::Multiply(mx, my, s_viewRotationMatrix);
// reverse rotation
Matrix33::RotateX(mx, -s_fViewRotation[1]);
Matrix33::RotateY(my, -s_fViewRotation[0]);
Matrix33::Multiply(my, mx, s_viewInvRotationMatrix);
bProjectionChanged = true;
}
void VertexShaderManager::ResetView()
{
memset(s_fViewTranslationVector, 0, sizeof(s_fViewTranslationVector));
Matrix33::LoadIdentity(s_viewRotationMatrix);
Matrix33::LoadIdentity(s_viewInvRotationMatrix);
s_fViewRotation[0] = s_fViewRotation[1] = 0.0f;
bProjectionChanged = true;
}
void VertexShaderManager::DoState(PointerWrap &p)
{
p.Do(g_fProjectionMatrix);
p.Do(s_viewportCorrection);
p.Do(s_viewRotationMatrix);
p.Do(s_viewInvRotationMatrix);
p.Do(s_fViewTranslationVector);
p.Do(s_fViewRotation);
p.Do(constants);
p.Do(dirty);
if (p.GetMode() == PointerWrap::MODE_READ)
{
Dirty();
}
}