mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -35,8 +35,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
|
||||
@ -46,399 +46,412 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
namespace Clipper
|
||||
{
|
||||
enum
|
||||
{
|
||||
NUM_CLIPPED_VERTICES = 33,
|
||||
NUM_INDICES = NUM_CLIPPED_VERTICES + 3
|
||||
};
|
||||
|
||||
static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
|
||||
static OutputVertexData *Vertices[NUM_INDICES];
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
|
||||
Vertices[i+3] = &ClippedVertices[i];
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SKIP_FLAG = -1,
|
||||
CLIP_POS_X_BIT = 0x01,
|
||||
CLIP_NEG_X_BIT = 0x02,
|
||||
CLIP_POS_Y_BIT = 0x04,
|
||||
CLIP_NEG_Y_BIT = 0x08,
|
||||
CLIP_POS_Z_BIT = 0x10,
|
||||
CLIP_NEG_Z_BIT = 0x20
|
||||
};
|
||||
|
||||
static inline int CalcClipMask(OutputVertexData *v)
|
||||
{
|
||||
int cmask = 0;
|
||||
Vec4 pos = v->projectedPosition;
|
||||
|
||||
if (pos.w - pos.x < 0)
|
||||
cmask |= CLIP_POS_X_BIT;
|
||||
|
||||
if (pos.x + pos.w < 0)
|
||||
cmask |= CLIP_NEG_X_BIT;
|
||||
|
||||
if (pos.w - pos.y < 0)
|
||||
cmask |= CLIP_POS_Y_BIT;
|
||||
|
||||
if (pos.y + pos.w < 0)
|
||||
cmask |= CLIP_NEG_Y_BIT;
|
||||
|
||||
if (pos.w * pos.z > 0)
|
||||
cmask |= CLIP_POS_Z_BIT;
|
||||
|
||||
if (pos.z + pos.w < 0)
|
||||
cmask |= CLIP_NEG_Z_BIT;
|
||||
|
||||
return cmask;
|
||||
}
|
||||
|
||||
static inline void AddInterpolatedVertex(float t, int out, int in, int* numVertices)
|
||||
{
|
||||
Vertices[(*numVertices)++]->Lerp(t, Vertices[out], Vertices[in]);
|
||||
}
|
||||
|
||||
#define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0))
|
||||
|
||||
#define CLIP_DOTPROD(I, A, B, C, D) \
|
||||
(Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D)
|
||||
|
||||
#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) { \
|
||||
int idxPrev = inlist[0]; \
|
||||
float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
|
||||
int outcount = 0; \
|
||||
\
|
||||
inlist[n] = inlist[0]; \
|
||||
for (int j = 1; j <= n; j++) { \
|
||||
int idx = inlist[j]; \
|
||||
float dp = CLIP_DOTPROD(idx, A, B, C, D ); \
|
||||
if (dpPrev >= 0) { \
|
||||
outlist[outcount++] = idxPrev; \
|
||||
} \
|
||||
\
|
||||
if (DIFFERENT_SIGNS(dp, dpPrev)) { \
|
||||
if (dp < 0) { \
|
||||
float t = dp / (dp - dpPrev); \
|
||||
AddInterpolatedVertex(t, idx, idxPrev, &numVertices); \
|
||||
} else { \
|
||||
float t = dpPrev / (dpPrev - dp); \
|
||||
AddInterpolatedVertex(t, idxPrev, idx, &numVertices); \
|
||||
} \
|
||||
outlist[outcount++] = numVertices - 1; \
|
||||
} \
|
||||
\
|
||||
idxPrev = idx; \
|
||||
dpPrev = dp; \
|
||||
} \
|
||||
\
|
||||
if (outcount < 3) \
|
||||
continue; \
|
||||
\
|
||||
{ \
|
||||
int *tmp = inlist; \
|
||||
inlist = outlist; \
|
||||
outlist = tmp; \
|
||||
n = outcount; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LINE_CLIP(PLANE_BIT, A, B, C, D ) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) { \
|
||||
const float dp0 = CLIP_DOTPROD( 0, A, B, C, D ); \
|
||||
const float dp1 = CLIP_DOTPROD( 1, A, B, C, D ); \
|
||||
const bool neg_dp0 = dp0 < 0; \
|
||||
const bool neg_dp1 = dp1 < 0; \
|
||||
\
|
||||
if (neg_dp0 && neg_dp1) \
|
||||
return; \
|
||||
\
|
||||
if (neg_dp1) { \
|
||||
float t = dp1 / (dp1 - dp0); \
|
||||
if (t > t1) t1 = t; \
|
||||
} else if (neg_dp0) { \
|
||||
float t = dp0 / (dp0 - dp1); \
|
||||
if (t > t0) t0 = t; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
static void ClipTriangle(int *indices, int* numIndices)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
mask |= CalcClipMask(Vertices[0]);
|
||||
mask |= CalcClipMask(Vertices[1]);
|
||||
mask |= CalcClipMask(Vertices[2]);
|
||||
|
||||
if (mask != 0)
|
||||
{
|
||||
for (int i = 0; i < 3; i += 3)
|
||||
{
|
||||
int vlist[2][2*6+1];
|
||||
int *inlist = vlist[0], *outlist = vlist[1];
|
||||
int n = 3;
|
||||
int numVertices = 3;
|
||||
|
||||
inlist[0] = 0;
|
||||
inlist[1] = 1;
|
||||
inlist[2] = 2;
|
||||
|
||||
// mark this triangle as unused in case it should be completely
|
||||
// clipped
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
indices[2] = SKIP_FLAG;
|
||||
|
||||
POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
INCSTAT(stats.thisFrame.numTrianglesClipped);
|
||||
|
||||
// transform the poly in inlist into triangles
|
||||
indices[0] = inlist[0];
|
||||
indices[1] = inlist[1];
|
||||
indices[2] = inlist[2];
|
||||
for (int j = 3; j < n; ++j)
|
||||
{
|
||||
indices[(*numIndices)++] = inlist[0];
|
||||
indices[(*numIndices)++] = inlist[j - 1];
|
||||
indices[(*numIndices)++] = inlist[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ClipLine(int *indices)
|
||||
{
|
||||
int mask = 0;
|
||||
int clip_mask[2] = { 0, 0 };
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
clip_mask[i] = CalcClipMask(Vertices[i]);
|
||||
mask |= clip_mask[i];
|
||||
}
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
float t0 = 0;
|
||||
float t1 = 0;
|
||||
|
||||
// Mark unused in case of early termination
|
||||
// of the macros below. (When fully clipped)
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
|
||||
LINE_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Z_BIT, 0, 0, -1, 1);
|
||||
LINE_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
// Restore the old values as this line
|
||||
// was not fully clipped.
|
||||
indices[0] = 0;
|
||||
indices[1] = 1;
|
||||
|
||||
int numVertices = 2;
|
||||
|
||||
if (clip_mask[0])
|
||||
{
|
||||
indices[0] = numVertices;
|
||||
AddInterpolatedVertex(t0, 0, 1, &numVertices);
|
||||
}
|
||||
|
||||
if (clip_mask[1])
|
||||
{
|
||||
indices[1] = numVertices;
|
||||
AddInterpolatedVertex(t1, 1, 0, &numVertices);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesIn)
|
||||
|
||||
bool backface;
|
||||
|
||||
if (!CullTest(v0, v1, v2, backface))
|
||||
return;
|
||||
|
||||
int indices[NUM_INDICES] = {
|
||||
0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG
|
||||
};
|
||||
int numIndices = 3;
|
||||
|
||||
if (backface)
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v2;
|
||||
Vertices[2] = v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v1;
|
||||
Vertices[2] = v2;
|
||||
}
|
||||
|
||||
ClipTriangle(indices, &numIndices);
|
||||
|
||||
for (int i = 0; i+3 <= numIndices; i+=3)
|
||||
{
|
||||
_assert_(i < NUM_INDICES);
|
||||
if (indices[i] != SKIP_FLAG)
|
||||
{
|
||||
PerspectiveDivide(Vertices[indices[i]]);
|
||||
PerspectiveDivide(Vertices[indices[i+1]]);
|
||||
PerspectiveDivide(Vertices[indices[i+2]]);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i+1]], Vertices[indices[i+2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CopyVertex(OutputVertexData *dst, OutputVertexData *src, float dx, float dy, unsigned int sOffset)
|
||||
{
|
||||
dst->screenPosition.x = src->screenPosition.x + dx;
|
||||
dst->screenPosition.y = src->screenPosition.y + dy;
|
||||
dst->screenPosition.z = src->screenPosition.z;
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
dst->normal[i] = src->normal[i];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
dst->color[0][i] = src->color[0][i];
|
||||
|
||||
// todo - s offset
|
||||
for (int i = 0; i < 8; ++i)
|
||||
dst->texCoords[i] = src->texCoords[i];
|
||||
}
|
||||
|
||||
void ProcessLine(OutputVertexData *lineV0, OutputVertexData *lineV1)
|
||||
{
|
||||
int indices[4] = { 0, 1, SKIP_FLAG, SKIP_FLAG };
|
||||
|
||||
Vertices[0] = lineV0;
|
||||
Vertices[1] = lineV1;
|
||||
|
||||
// point to a valid vertex to store to when clipping
|
||||
Vertices[2] = &ClippedVertices[17];
|
||||
|
||||
ClipLine(indices);
|
||||
|
||||
if (indices[0] != SKIP_FLAG)
|
||||
{
|
||||
OutputVertexData *v0 = Vertices[indices[0]];
|
||||
OutputVertexData *v1 = Vertices[indices[1]];
|
||||
|
||||
PerspectiveDivide(v0);
|
||||
PerspectiveDivide(v1);
|
||||
|
||||
float dx = v1->screenPosition.x - v0->screenPosition.x;
|
||||
float dy = v1->screenPosition.y - v0->screenPosition.y;
|
||||
|
||||
float screenDx = 0;
|
||||
float screenDy = 0;
|
||||
|
||||
if (fabsf(dx) > fabsf(dy))
|
||||
{
|
||||
if (dx > 0)
|
||||
screenDy = bpmem.lineptwidth.linesize / -12.0f;
|
||||
else
|
||||
screenDy = bpmem.lineptwidth.linesize / 12.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dy > 0)
|
||||
screenDx = bpmem.lineptwidth.linesize / 12.0f;
|
||||
else
|
||||
screenDx = bpmem.lineptwidth.linesize / -12.0f;
|
||||
}
|
||||
|
||||
OutputVertexData triangle[3];
|
||||
|
||||
CopyVertex(&triangle[0], v0, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[1], v1, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
// ccw winding
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]);
|
||||
|
||||
CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface)
|
||||
{
|
||||
int mask = CalcClipMask(v0);
|
||||
mask &= CalcClipMask(v1);
|
||||
mask &= CalcClipMask(v2);
|
||||
|
||||
if (mask)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesRejected)
|
||||
return false;
|
||||
}
|
||||
|
||||
float x0 = v0->projectedPosition.x;
|
||||
float x1 = v1->projectedPosition.x;
|
||||
float x2 = v2->projectedPosition.x;
|
||||
float y1 = v1->projectedPosition.y;
|
||||
float y0 = v0->projectedPosition.y;
|
||||
float y2 = v2->projectedPosition.y;
|
||||
float w0 = v0->projectedPosition.w;
|
||||
float w1 = v1->projectedPosition.w;
|
||||
float w2 = v2->projectedPosition.w;
|
||||
|
||||
float normalZDir = (x0*w2 - x2*w0)*y1 + (x2*y0 - x0*y2)*w1 + (y2*w0 - y0*w2)*x1;
|
||||
|
||||
backface = normalZDir <= 0.0f;
|
||||
|
||||
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerspectiveDivide(OutputVertexData *vertex)
|
||||
{
|
||||
Vec4 &projected = vertex->projectedPosition;
|
||||
Vec3 &screen = vertex->screenPosition;
|
||||
|
||||
float wInverse = 1.0f/projected.w;
|
||||
screen.x = projected.x * wInverse * xfmem.viewport.wd + xfmem.viewport.xOrig - 342;
|
||||
screen.y = projected.y * wInverse * xfmem.viewport.ht + xfmem.viewport.yOrig - 342;
|
||||
screen.z = projected.z * wInverse * xfmem.viewport.zRange + xfmem.viewport.farZ;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
NUM_CLIPPED_VERTICES = 33,
|
||||
NUM_INDICES = NUM_CLIPPED_VERTICES + 3
|
||||
};
|
||||
|
||||
static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
|
||||
static OutputVertexData* Vertices[NUM_INDICES];
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
|
||||
Vertices[i + 3] = &ClippedVertices[i];
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
SKIP_FLAG = -1,
|
||||
CLIP_POS_X_BIT = 0x01,
|
||||
CLIP_NEG_X_BIT = 0x02,
|
||||
CLIP_POS_Y_BIT = 0x04,
|
||||
CLIP_NEG_Y_BIT = 0x08,
|
||||
CLIP_POS_Z_BIT = 0x10,
|
||||
CLIP_NEG_Z_BIT = 0x20
|
||||
};
|
||||
|
||||
static inline int CalcClipMask(OutputVertexData* v)
|
||||
{
|
||||
int cmask = 0;
|
||||
Vec4 pos = v->projectedPosition;
|
||||
|
||||
if (pos.w - pos.x < 0)
|
||||
cmask |= CLIP_POS_X_BIT;
|
||||
|
||||
if (pos.x + pos.w < 0)
|
||||
cmask |= CLIP_NEG_X_BIT;
|
||||
|
||||
if (pos.w - pos.y < 0)
|
||||
cmask |= CLIP_POS_Y_BIT;
|
||||
|
||||
if (pos.y + pos.w < 0)
|
||||
cmask |= CLIP_NEG_Y_BIT;
|
||||
|
||||
if (pos.w * pos.z > 0)
|
||||
cmask |= CLIP_POS_Z_BIT;
|
||||
|
||||
if (pos.z + pos.w < 0)
|
||||
cmask |= CLIP_NEG_Z_BIT;
|
||||
|
||||
return cmask;
|
||||
}
|
||||
|
||||
static inline void AddInterpolatedVertex(float t, int out, int in, int* numVertices)
|
||||
{
|
||||
Vertices[(*numVertices)++]->Lerp(t, Vertices[out], Vertices[in]);
|
||||
}
|
||||
|
||||
#define DIFFERENT_SIGNS(x, y) ((x <= 0 && y > 0) || (x > 0 && y <= 0))
|
||||
|
||||
#define CLIP_DOTPROD(I, A, B, C, D) \
|
||||
(Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + \
|
||||
Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D)
|
||||
|
||||
#define POLY_CLIP(PLANE_BIT, A, B, C, D) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) \
|
||||
{ \
|
||||
int idxPrev = inlist[0]; \
|
||||
float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D); \
|
||||
int outcount = 0; \
|
||||
\
|
||||
inlist[n] = inlist[0]; \
|
||||
for (int j = 1; j <= n; j++) \
|
||||
{ \
|
||||
int idx = inlist[j]; \
|
||||
float dp = CLIP_DOTPROD(idx, A, B, C, D); \
|
||||
if (dpPrev >= 0) \
|
||||
{ \
|
||||
outlist[outcount++] = idxPrev; \
|
||||
} \
|
||||
\
|
||||
if (DIFFERENT_SIGNS(dp, dpPrev)) \
|
||||
{ \
|
||||
if (dp < 0) \
|
||||
{ \
|
||||
float t = dp / (dp - dpPrev); \
|
||||
AddInterpolatedVertex(t, idx, idxPrev, &numVertices); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
float t = dpPrev / (dpPrev - dp); \
|
||||
AddInterpolatedVertex(t, idxPrev, idx, &numVertices); \
|
||||
} \
|
||||
outlist[outcount++] = numVertices - 1; \
|
||||
} \
|
||||
\
|
||||
idxPrev = idx; \
|
||||
dpPrev = dp; \
|
||||
} \
|
||||
\
|
||||
if (outcount < 3) \
|
||||
continue; \
|
||||
\
|
||||
{ \
|
||||
int* tmp = inlist; \
|
||||
inlist = outlist; \
|
||||
outlist = tmp; \
|
||||
n = outcount; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LINE_CLIP(PLANE_BIT, A, B, C, D) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) \
|
||||
{ \
|
||||
const float dp0 = CLIP_DOTPROD(0, A, B, C, D); \
|
||||
const float dp1 = CLIP_DOTPROD(1, A, B, C, D); \
|
||||
const bool neg_dp0 = dp0 < 0; \
|
||||
const bool neg_dp1 = dp1 < 0; \
|
||||
\
|
||||
if (neg_dp0 && neg_dp1) \
|
||||
return; \
|
||||
\
|
||||
if (neg_dp1) \
|
||||
{ \
|
||||
float t = dp1 / (dp1 - dp0); \
|
||||
if (t > t1) \
|
||||
t1 = t; \
|
||||
} \
|
||||
else if (neg_dp0) \
|
||||
{ \
|
||||
float t = dp0 / (dp0 - dp1); \
|
||||
if (t > t0) \
|
||||
t0 = t; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
static void ClipTriangle(int* indices, int* numIndices)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
mask |= CalcClipMask(Vertices[0]);
|
||||
mask |= CalcClipMask(Vertices[1]);
|
||||
mask |= CalcClipMask(Vertices[2]);
|
||||
|
||||
if (mask != 0)
|
||||
{
|
||||
for (int i = 0; i < 3; i += 3)
|
||||
{
|
||||
int vlist[2][2 * 6 + 1];
|
||||
int *inlist = vlist[0], *outlist = vlist[1];
|
||||
int n = 3;
|
||||
int numVertices = 3;
|
||||
|
||||
inlist[0] = 0;
|
||||
inlist[1] = 1;
|
||||
inlist[2] = 2;
|
||||
|
||||
// mark this triangle as unused in case it should be completely
|
||||
// clipped
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
indices[2] = SKIP_FLAG;
|
||||
|
||||
POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
INCSTAT(stats.thisFrame.numTrianglesClipped);
|
||||
|
||||
// transform the poly in inlist into triangles
|
||||
indices[0] = inlist[0];
|
||||
indices[1] = inlist[1];
|
||||
indices[2] = inlist[2];
|
||||
for (int j = 3; j < n; ++j)
|
||||
{
|
||||
indices[(*numIndices)++] = inlist[0];
|
||||
indices[(*numIndices)++] = inlist[j - 1];
|
||||
indices[(*numIndices)++] = inlist[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ClipLine(int* indices)
|
||||
{
|
||||
int mask = 0;
|
||||
int clip_mask[2] = {0, 0};
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
clip_mask[i] = CalcClipMask(Vertices[i]);
|
||||
mask |= clip_mask[i];
|
||||
}
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
float t0 = 0;
|
||||
float t1 = 0;
|
||||
|
||||
// Mark unused in case of early termination
|
||||
// of the macros below. (When fully clipped)
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
|
||||
LINE_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Z_BIT, 0, 0, -1, 1);
|
||||
LINE_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
// Restore the old values as this line
|
||||
// was not fully clipped.
|
||||
indices[0] = 0;
|
||||
indices[1] = 1;
|
||||
|
||||
int numVertices = 2;
|
||||
|
||||
if (clip_mask[0])
|
||||
{
|
||||
indices[0] = numVertices;
|
||||
AddInterpolatedVertex(t0, 0, 1, &numVertices);
|
||||
}
|
||||
|
||||
if (clip_mask[1])
|
||||
{
|
||||
indices[1] = numVertices;
|
||||
AddInterpolatedVertex(t1, 1, 0, &numVertices);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesIn)
|
||||
|
||||
bool backface;
|
||||
|
||||
if (!CullTest(v0, v1, v2, backface))
|
||||
return;
|
||||
|
||||
int indices[NUM_INDICES] = {0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG};
|
||||
int numIndices = 3;
|
||||
|
||||
if (backface)
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v2;
|
||||
Vertices[2] = v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v1;
|
||||
Vertices[2] = v2;
|
||||
}
|
||||
|
||||
ClipTriangle(indices, &numIndices);
|
||||
|
||||
for (int i = 0; i + 3 <= numIndices; i += 3)
|
||||
{
|
||||
_assert_(i < NUM_INDICES);
|
||||
if (indices[i] != SKIP_FLAG)
|
||||
{
|
||||
PerspectiveDivide(Vertices[indices[i]]);
|
||||
PerspectiveDivide(Vertices[indices[i + 1]]);
|
||||
PerspectiveDivide(Vertices[indices[i + 2]]);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i + 1]],
|
||||
Vertices[indices[i + 2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CopyVertex(OutputVertexData* dst, OutputVertexData* src, float dx, float dy,
|
||||
unsigned int sOffset)
|
||||
{
|
||||
dst->screenPosition.x = src->screenPosition.x + dx;
|
||||
dst->screenPosition.y = src->screenPosition.y + dy;
|
||||
dst->screenPosition.z = src->screenPosition.z;
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
dst->normal[i] = src->normal[i];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
dst->color[0][i] = src->color[0][i];
|
||||
|
||||
// todo - s offset
|
||||
for (int i = 0; i < 8; ++i)
|
||||
dst->texCoords[i] = src->texCoords[i];
|
||||
}
|
||||
|
||||
void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1)
|
||||
{
|
||||
int indices[4] = {0, 1, SKIP_FLAG, SKIP_FLAG};
|
||||
|
||||
Vertices[0] = lineV0;
|
||||
Vertices[1] = lineV1;
|
||||
|
||||
// point to a valid vertex to store to when clipping
|
||||
Vertices[2] = &ClippedVertices[17];
|
||||
|
||||
ClipLine(indices);
|
||||
|
||||
if (indices[0] != SKIP_FLAG)
|
||||
{
|
||||
OutputVertexData* v0 = Vertices[indices[0]];
|
||||
OutputVertexData* v1 = Vertices[indices[1]];
|
||||
|
||||
PerspectiveDivide(v0);
|
||||
PerspectiveDivide(v1);
|
||||
|
||||
float dx = v1->screenPosition.x - v0->screenPosition.x;
|
||||
float dy = v1->screenPosition.y - v0->screenPosition.y;
|
||||
|
||||
float screenDx = 0;
|
||||
float screenDy = 0;
|
||||
|
||||
if (fabsf(dx) > fabsf(dy))
|
||||
{
|
||||
if (dx > 0)
|
||||
screenDy = bpmem.lineptwidth.linesize / -12.0f;
|
||||
else
|
||||
screenDy = bpmem.lineptwidth.linesize / 12.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dy > 0)
|
||||
screenDx = bpmem.lineptwidth.linesize / 12.0f;
|
||||
else
|
||||
screenDx = bpmem.lineptwidth.linesize / -12.0f;
|
||||
}
|
||||
|
||||
OutputVertexData triangle[3];
|
||||
|
||||
CopyVertex(&triangle[0], v0, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[1], v1, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
// ccw winding
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]);
|
||||
|
||||
CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool CullTest(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2, bool& backface)
|
||||
{
|
||||
int mask = CalcClipMask(v0);
|
||||
mask &= CalcClipMask(v1);
|
||||
mask &= CalcClipMask(v2);
|
||||
|
||||
if (mask)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesRejected)
|
||||
return false;
|
||||
}
|
||||
|
||||
float x0 = v0->projectedPosition.x;
|
||||
float x1 = v1->projectedPosition.x;
|
||||
float x2 = v2->projectedPosition.x;
|
||||
float y1 = v1->projectedPosition.y;
|
||||
float y0 = v0->projectedPosition.y;
|
||||
float y2 = v2->projectedPosition.y;
|
||||
float w0 = v0->projectedPosition.w;
|
||||
float w1 = v1->projectedPosition.w;
|
||||
float w2 = v2->projectedPosition.w;
|
||||
|
||||
float normalZDir = (x0 * w2 - x2 * w0) * y1 + (x2 * y0 - x0 * y2) * w1 + (y2 * w0 - y0 * w2) * x1;
|
||||
|
||||
backface = normalZDir <= 0.0f;
|
||||
|
||||
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerspectiveDivide(OutputVertexData* vertex)
|
||||
{
|
||||
Vec4& projected = vertex->projectedPosition;
|
||||
Vec3& screen = vertex->screenPosition;
|
||||
|
||||
float wInverse = 1.0f / projected.w;
|
||||
screen.x = projected.x * wInverse * xfmem.viewport.wd + xfmem.viewport.xOrig - 342;
|
||||
screen.y = projected.y * wInverse * xfmem.viewport.ht + xfmem.viewport.yOrig - 342;
|
||||
screen.z = projected.z * wInverse * xfmem.viewport.zRange + xfmem.viewport.farZ;
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ struct OutputVertexData;
|
||||
|
||||
namespace Clipper
|
||||
{
|
||||
void Init();
|
||||
void Init();
|
||||
|
||||
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2);
|
||||
|
||||
void ProcessLine(OutputVertexData *v0, OutputVertexData *v1);
|
||||
void ProcessLine(OutputVertexData* v0, OutputVertexData* v1);
|
||||
|
||||
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
|
||||
bool CullTest(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2, bool& backface);
|
||||
|
||||
void PerspectiveDivide(OutputVertexData *vertex);
|
||||
void PerspectiveDivide(OutputVertexData* vertex);
|
||||
}
|
||||
|
@ -21,10 +21,9 @@
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
|
||||
static const int NUM_OBJECT_BUFFERS = 40;
|
||||
|
||||
static u32 *ObjectBuffer[NUM_OBJECT_BUFFERS];
|
||||
static u32* ObjectBuffer[NUM_OBJECT_BUFFERS];
|
||||
static u32 TempBuffer[NUM_OBJECT_BUFFERS];
|
||||
|
||||
static bool DrawnToBuffer[NUM_OBJECT_BUFFERS];
|
||||
@ -33,197 +32,199 @@ static int BufferBase[NUM_OBJECT_BUFFERS];
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
ObjectBuffer[i] = new u32[EFB_WIDTH*EFB_HEIGHT]();
|
||||
DrawnToBuffer[i] = false;
|
||||
ObjectBufferName[i] = nullptr;
|
||||
BufferBase[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
ObjectBuffer[i] = new u32[EFB_WIDTH * EFB_HEIGHT]();
|
||||
DrawnToBuffer[i] = false;
|
||||
ObjectBufferName[i] = nullptr;
|
||||
BufferBase[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
delete[] ObjectBuffer[i];
|
||||
}
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
delete[] ObjectBuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveTexture(const std::string& filename, u32 texmap, s32 mip)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
|
||||
u32 width = ti0.width + 1;
|
||||
u32 height = ti0.height + 1;
|
||||
u32 width = ti0.width + 1;
|
||||
u32 height = ti0.height + 1;
|
||||
|
||||
u8 *data = new u8[width * height * 4];
|
||||
u8* data = new u8[width * height * 4];
|
||||
|
||||
GetTextureRGBA(data, texmap, mip, width, height);
|
||||
|
||||
TextureToPng(data, width*4, filename, width, height, true);
|
||||
delete[] data;
|
||||
GetTextureRGBA(data, texmap, mip, width, height);
|
||||
|
||||
TextureToPng(data, width * 4, filename, width, height, true);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void GetTextureRGBA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height)
|
||||
void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height)
|
||||
{
|
||||
for (u32 y = 0; y < height; y++)
|
||||
{
|
||||
for (u32 x = 0; x < width; x++)
|
||||
{
|
||||
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, dst);
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
for (u32 y = 0; y < height; y++)
|
||||
{
|
||||
for (u32 x = 0; x < width; x++)
|
||||
{
|
||||
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, dst);
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static s32 GetMaxTextureLod(u32 texmap)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
u8 maxLod = texUnit.texMode1[subTexmap].max_lod;
|
||||
u8 mip = maxLod >> 4;
|
||||
u8 fract = maxLod & 0xf;
|
||||
u8 maxLod = texUnit.texMode1[subTexmap].max_lod;
|
||||
u8 mip = maxLod >> 4;
|
||||
u8 fract = maxLod & 0xf;
|
||||
|
||||
if (fract)
|
||||
++mip;
|
||||
if (fract)
|
||||
++mip;
|
||||
|
||||
return (s32)mip;
|
||||
return (s32)mip;
|
||||
}
|
||||
|
||||
void DumpActiveTextures()
|
||||
{
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
|
||||
}
|
||||
}
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip),
|
||||
texmap, mip);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
TwoTevStageOrders &order = bpmem.tevorders[stageNum2];
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum & 1;
|
||||
TwoTevStageOrders& order = bpmem.tevorders[stageNum2];
|
||||
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip);
|
||||
}
|
||||
}
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, stageNum, texmap, mip),
|
||||
texmap, mip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpEfb(const std::string& filename)
|
||||
{
|
||||
u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
|
||||
u8 *writePtr = data;
|
||||
u8 sample[4];
|
||||
u8* data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
|
||||
u8* writePtr = data;
|
||||
u8 sample[4];
|
||||
|
||||
for (int y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (int x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
EfbInterface::GetColor(x, y, sample);
|
||||
// ABGR to RGBA
|
||||
*(writePtr++) = sample[3];
|
||||
*(writePtr++) = sample[2];
|
||||
*(writePtr++) = sample[1];
|
||||
*(writePtr++) = sample[0];
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (int x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
EfbInterface::GetColor(x, y, sample);
|
||||
// ABGR to RGBA
|
||||
*(writePtr++) = sample[3];
|
||||
*(writePtr++) = sample[2];
|
||||
*(writePtr++) = sample[1];
|
||||
*(writePtr++) = sample[0];
|
||||
}
|
||||
}
|
||||
|
||||
TextureToPng(data, EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
|
||||
delete[] data;
|
||||
TextureToPng(data, EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name)
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8* color, int bufferBase, int subBuffer, const char* name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH) * 4;
|
||||
u8 *dst = (u8*)&ObjectBuffer[buffer][offset];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
u32 offset = (x + y * EFB_WIDTH) * 4;
|
||||
u8* dst = (u8*)&ObjectBuffer[buffer][offset];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void DrawTempBuffer(u8 *color, int buffer)
|
||||
void DrawTempBuffer(u8* color, int buffer)
|
||||
{
|
||||
u8 *dst = (u8*)&TempBuffer[buffer];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
u8* dst = (u8*)&TempBuffer[buffer];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
}
|
||||
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name)
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH);
|
||||
ObjectBuffer[buffer][offset] = TempBuffer[buffer];
|
||||
u32 offset = (x + y * EFB_WIDTH);
|
||||
ObjectBuffer[buffer][offset] = TempBuffer[buffer];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void OnObjectBegin()
|
||||
{
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (g_ActiveConfig.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
|
||||
DumpActiveTextures();
|
||||
}
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (g_ActiveConfig.bDumpTextures &&
|
||||
stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart &&
|
||||
stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
|
||||
DumpActiveTextures();
|
||||
}
|
||||
}
|
||||
|
||||
void OnObjectEnd()
|
||||
{
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (g_ActiveConfig.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
|
||||
DumpEfb(StringFromFormat("%sobject%i.png",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects));
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (g_ActiveConfig.bDumpObjects &&
|
||||
stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart &&
|
||||
stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd)
|
||||
DumpEfb(StringFromFormat("%sobject%i.png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects));
|
||||
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
if (DrawnToBuffer[i])
|
||||
{
|
||||
DrawnToBuffer[i] = false;
|
||||
std::string filename = StringFromFormat("%sobject%i_%s(%i).png",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]);
|
||||
for (int i = 0; i < NUM_OBJECT_BUFFERS; i++)
|
||||
{
|
||||
if (DrawnToBuffer[i])
|
||||
{
|
||||
DrawnToBuffer[i] = false;
|
||||
std::string filename = StringFromFormat(
|
||||
"%sobject%i_%s(%i).png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]);
|
||||
|
||||
TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
|
||||
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
|
||||
TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true);
|
||||
memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
stats.thisFrame.numDrawnObjects++;
|
||||
}
|
||||
stats.thisFrame.numDrawnObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,18 +8,18 @@
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void GetTextureRGBA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height);
|
||||
void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height);
|
||||
|
||||
void DumpActiveTextures();
|
||||
void DumpActiveTextures();
|
||||
|
||||
void OnObjectBegin();
|
||||
void OnObjectEnd();
|
||||
void OnObjectBegin();
|
||||
void OnObjectEnd();
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name);
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8* color, int bufferBase, int subBuffer, const char* name);
|
||||
|
||||
void DrawTempBuffer(u8 *color, int buffer);
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name);
|
||||
void DrawTempBuffer(u8* color, int buffer);
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name);
|
||||
}
|
||||
|
@ -2,104 +2,99 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/Software/EfbCopy.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "VideoBackends/Software/EfbCopy.h"
|
||||
#include "VideoBackends/Software/EfbInterface.h"
|
||||
#include "VideoBackends/Software/TextureEncoder.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
|
||||
static const float s_gammaLUT[] =
|
||||
{
|
||||
1.0f,
|
||||
1.7f,
|
||||
2.2f,
|
||||
1.0f
|
||||
};
|
||||
static const float s_gammaLUT[] = {1.0f, 1.7f, 2.2f, 1.0f};
|
||||
|
||||
namespace EfbCopy
|
||||
{
|
||||
static void CopyToXfb(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)
|
||||
{
|
||||
INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f",
|
||||
xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma);
|
||||
static void CopyToXfb(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,
|
||||
float Gamma)
|
||||
{
|
||||
INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f",
|
||||
xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right,
|
||||
Gamma);
|
||||
|
||||
EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
|
||||
EfbInterface::yuv422_packed* xfb_in_ram =
|
||||
(EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr);
|
||||
|
||||
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
|
||||
}
|
||||
|
||||
static void CopyToRam()
|
||||
{
|
||||
u8 *dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5);
|
||||
|
||||
TextureEncoder::Encode(dest_ptr);
|
||||
}
|
||||
|
||||
void ClearEfb()
|
||||
{
|
||||
u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
|
||||
int left = bpmem.copyTexSrcXY.x;
|
||||
int top = bpmem.copyTexSrcXY.y;
|
||||
int right = left + bpmem.copyTexSrcWH.x;
|
||||
int bottom = top + bpmem.copyTexSrcWH.y;
|
||||
|
||||
for (u16 y = top; y <= bottom; y++)
|
||||
{
|
||||
for (u16 x = left; x <= right; x++)
|
||||
{
|
||||
EfbInterface::SetColor(x, y, (u8*)(&clearColor));
|
||||
EfbInterface::SetDepth(x, y, bpmem.clearZValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyEfb()
|
||||
{
|
||||
EFBRectangle rc;
|
||||
rc.left = (int)bpmem.copyTexSrcXY.x;
|
||||
rc.top = (int)bpmem.copyTexSrcXY.y;
|
||||
|
||||
// flipper represents the widths internally as last pixel minus starting pixel, so
|
||||
// these are zero indexed.
|
||||
rc.right = rc.left + (int)bpmem.copyTexSrcWH.x + 1;
|
||||
rc.bottom = rc.top + (int)bpmem.copyTexSrcWH.y + 1;
|
||||
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (bpmem.triggerEFBCopy.copy_to_xfb)
|
||||
{
|
||||
float yScale;
|
||||
if (bpmem.triggerEFBCopy.scale_invert)
|
||||
yScale = 256.0f / (float)bpmem.dispcopyyscale;
|
||||
else
|
||||
yScale = (float)bpmem.dispcopyyscale / 256.0f;
|
||||
|
||||
float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
|
||||
|
||||
if (yScale != 1.0)
|
||||
WARN_LOG(VIDEO, "yScale of %f is currently unsupported", yScale);
|
||||
|
||||
if ((u32)xfbLines > MAX_XFB_HEIGHT)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines (%f)", xfbLines);
|
||||
xfbLines = MAX_XFB_HEIGHT;
|
||||
}
|
||||
|
||||
CopyToXfb(bpmem.copyTexDest << 5,
|
||||
bpmem.copyMipMapStrideChannels << 4,
|
||||
(u32)xfbLines,
|
||||
rc,
|
||||
s_gammaLUT[bpmem.triggerEFBCopy.gamma]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyToRam(); // FIXME: should use the rectangle we have already created above
|
||||
}
|
||||
}
|
||||
}
|
||||
EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma);
|
||||
}
|
||||
|
||||
static void CopyToRam()
|
||||
{
|
||||
u8* dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5);
|
||||
|
||||
TextureEncoder::Encode(dest_ptr);
|
||||
}
|
||||
|
||||
void ClearEfb()
|
||||
{
|
||||
u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 |
|
||||
(bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
|
||||
int left = bpmem.copyTexSrcXY.x;
|
||||
int top = bpmem.copyTexSrcXY.y;
|
||||
int right = left + bpmem.copyTexSrcWH.x;
|
||||
int bottom = top + bpmem.copyTexSrcWH.y;
|
||||
|
||||
for (u16 y = top; y <= bottom; y++)
|
||||
{
|
||||
for (u16 x = left; x <= right; x++)
|
||||
{
|
||||
EfbInterface::SetColor(x, y, (u8*)(&clearColor));
|
||||
EfbInterface::SetDepth(x, y, bpmem.clearZValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyEfb()
|
||||
{
|
||||
EFBRectangle rc;
|
||||
rc.left = (int)bpmem.copyTexSrcXY.x;
|
||||
rc.top = (int)bpmem.copyTexSrcXY.y;
|
||||
|
||||
// flipper represents the widths internally as last pixel minus starting pixel, so
|
||||
// these are zero indexed.
|
||||
rc.right = rc.left + (int)bpmem.copyTexSrcWH.x + 1;
|
||||
rc.bottom = rc.top + (int)bpmem.copyTexSrcWH.y + 1;
|
||||
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (bpmem.triggerEFBCopy.copy_to_xfb)
|
||||
{
|
||||
float yScale;
|
||||
if (bpmem.triggerEFBCopy.scale_invert)
|
||||
yScale = 256.0f / (float)bpmem.dispcopyyscale;
|
||||
else
|
||||
yScale = (float)bpmem.dispcopyyscale / 256.0f;
|
||||
|
||||
float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale);
|
||||
|
||||
if (yScale != 1.0)
|
||||
WARN_LOG(VIDEO, "yScale of %f is currently unsupported", yScale);
|
||||
|
||||
if ((u32)xfbLines > MAX_XFB_HEIGHT)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines (%f)", xfbLines);
|
||||
xfbLines = MAX_XFB_HEIGHT;
|
||||
}
|
||||
|
||||
CopyToXfb(bpmem.copyTexDest << 5, bpmem.copyMipMapStrideChannels << 4, (u32)xfbLines, rc,
|
||||
s_gammaLUT[bpmem.triggerEFBCopy.gamma]);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyToRam(); // FIXME: should use the rectangle we have already created above
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
namespace EfbCopy
|
||||
{
|
||||
// Copy the EFB to RAM as a texture format or XFB
|
||||
void CopyEfb();
|
||||
// Copy the EFB to RAM as a texture format or XFB
|
||||
void CopyEfb();
|
||||
|
||||
void ClearEfb();
|
||||
void ClearEfb();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,67 +10,68 @@
|
||||
|
||||
namespace EfbInterface
|
||||
{
|
||||
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
|
||||
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
|
||||
|
||||
// xfb color format - packed so the compiler doesn't mess with alignment
|
||||
#pragma pack(push,1)
|
||||
struct yuv422_packed
|
||||
{
|
||||
u8 Y;
|
||||
u8 UV;
|
||||
};
|
||||
// xfb color format - packed so the compiler doesn't mess with alignment
|
||||
#pragma pack(push, 1)
|
||||
struct yuv422_packed
|
||||
{
|
||||
u8 Y;
|
||||
u8 UV;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// But this struct is only used internally, so we could optimise alignment
|
||||
struct yuv444
|
||||
{
|
||||
u8 Y;
|
||||
s8 U;
|
||||
s8 V;
|
||||
};
|
||||
// But this struct is only used internally, so we could optimise alignment
|
||||
struct yuv444
|
||||
{
|
||||
u8 Y;
|
||||
s8 U;
|
||||
s8 V;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ALP_C,
|
||||
BLU_C,
|
||||
GRN_C,
|
||||
RED_C
|
||||
};
|
||||
enum
|
||||
{
|
||||
ALP_C,
|
||||
BLU_C,
|
||||
GRN_C,
|
||||
RED_C
|
||||
};
|
||||
|
||||
// color order is ABGR in order to emulate RGBA on little-endian hardware
|
||||
// color order is ABGR in order to emulate RGBA on little-endian hardware
|
||||
|
||||
// does full blending of an incoming pixel
|
||||
void BlendTev(u16 x, u16 y, u8 *color);
|
||||
// does full blending of an incoming pixel
|
||||
void BlendTev(u16 x, u16 y, u8* color);
|
||||
|
||||
// compare z at location x,y
|
||||
// writes it if it passes
|
||||
// returns result of compare.
|
||||
bool ZCompare(u16 x, u16 y, u32 z);
|
||||
// compare z at location x,y
|
||||
// writes it if it passes
|
||||
// returns result of compare.
|
||||
bool ZCompare(u16 x, u16 y, u32 z);
|
||||
|
||||
// sets the color and alpha
|
||||
void SetColor(u16 x, u16 y, u8 *color);
|
||||
void SetDepth(u16 x, u16 y, u32 depth);
|
||||
// sets the color and alpha
|
||||
void SetColor(u16 x, u16 y, u8* color);
|
||||
void SetDepth(u16 x, u16 y, u32 depth);
|
||||
|
||||
void GetColor(u16 x, u16 y, u8 *color);
|
||||
void GetColorYUV(u16 x, u16 y, yuv444 *color);
|
||||
u32 GetDepth(u16 x, u16 y);
|
||||
void GetColor(u16 x, u16 y, u8* color);
|
||||
void GetColorYUV(u16 x, u16 y, yuv444* color);
|
||||
u32 GetDepth(u16 x, u16 y);
|
||||
|
||||
u8* GetPixelPointer(u16 x, u16 y, bool depth);
|
||||
u8* GetPixelPointer(u16 x, u16 y, bool depth);
|
||||
|
||||
void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
|
||||
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
|
||||
void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,
|
||||
float Gamma);
|
||||
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma);
|
||||
|
||||
extern u32 perf_values[PQ_NUM_MEMBERS];
|
||||
inline void IncPerfCounterQuadCount(PerfQueryType type)
|
||||
{
|
||||
// NOTE: hardware doesn't process individual pixels but quads instead.
|
||||
// Current software renderer architecture works on pixels though, so
|
||||
// we have this "quad" hack here to only increment the registers on
|
||||
// every fourth rendered pixel
|
||||
static u32 quad[PQ_NUM_MEMBERS];
|
||||
if (++quad[type] != 3)
|
||||
return;
|
||||
quad[type] = 0;
|
||||
++perf_values[type];
|
||||
}
|
||||
extern u32 perf_values[PQ_NUM_MEMBERS];
|
||||
inline void IncPerfCounterQuadCount(PerfQueryType type)
|
||||
{
|
||||
// NOTE: hardware doesn't process individual pixels but quads instead.
|
||||
// Current software renderer architecture works on pixels though, so
|
||||
// we have this "quad" hack here to only increment the registers on
|
||||
// every fourth rendered pixel
|
||||
static u32 quad[PQ_NUM_MEMBERS];
|
||||
if (++quad[type] != 3)
|
||||
return;
|
||||
quad[type] = 0;
|
||||
++perf_values[type];
|
||||
}
|
||||
}
|
||||
|
@ -9,72 +9,72 @@
|
||||
|
||||
struct Vec4
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
|
||||
struct InputVertexData
|
||||
{
|
||||
u8 posMtx;
|
||||
u8 texMtx[8];
|
||||
u8 posMtx;
|
||||
u8 texMtx[8];
|
||||
|
||||
Vec3 position;
|
||||
Vec3 normal[3];
|
||||
u8 color[2][4];
|
||||
float texCoords[8][2];
|
||||
Vec3 position;
|
||||
Vec3 normal[3];
|
||||
u8 color[2][4];
|
||||
float texCoords[8][2];
|
||||
};
|
||||
|
||||
struct OutputVertexData
|
||||
{
|
||||
// components in color channels
|
||||
enum
|
||||
{
|
||||
RED_C,
|
||||
GRN_C,
|
||||
BLU_C,
|
||||
ALP_C
|
||||
};
|
||||
// components in color channels
|
||||
enum
|
||||
{
|
||||
RED_C,
|
||||
GRN_C,
|
||||
BLU_C,
|
||||
ALP_C
|
||||
};
|
||||
|
||||
Vec3 mvPosition = {};
|
||||
Vec4 projectedPosition = {};
|
||||
Vec3 screenPosition = {};
|
||||
Vec3 normal[3] = {};
|
||||
u8 color[2][4] = {};
|
||||
Vec3 texCoords[8] = {};
|
||||
Vec3 mvPosition = {};
|
||||
Vec4 projectedPosition = {};
|
||||
Vec3 screenPosition = {};
|
||||
Vec3 normal[3] = {};
|
||||
u8 color[2][4] = {};
|
||||
Vec3 texCoords[8] = {};
|
||||
|
||||
void Lerp(float t, OutputVertexData *a, OutputVertexData *b)
|
||||
{
|
||||
#define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T)
|
||||
void Lerp(float t, OutputVertexData* a, OutputVertexData* b)
|
||||
{
|
||||
#define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T)
|
||||
|
||||
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
|
||||
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
|
||||
|
||||
mvPosition = LINTERP(t, a->mvPosition, b->mvPosition);
|
||||
mvPosition = LINTERP(t, a->mvPosition, b->mvPosition);
|
||||
|
||||
projectedPosition.x = LINTERP(t, a->projectedPosition.x, b->projectedPosition.x);
|
||||
projectedPosition.y = LINTERP(t, a->projectedPosition.y, b->projectedPosition.y);
|
||||
projectedPosition.z = LINTERP(t, a->projectedPosition.z, b->projectedPosition.z);
|
||||
projectedPosition.w = LINTERP(t, a->projectedPosition.w, b->projectedPosition.w);
|
||||
projectedPosition.x = LINTERP(t, a->projectedPosition.x, b->projectedPosition.x);
|
||||
projectedPosition.y = LINTERP(t, a->projectedPosition.y, b->projectedPosition.y);
|
||||
projectedPosition.z = LINTERP(t, a->projectedPosition.z, b->projectedPosition.z);
|
||||
projectedPosition.w = LINTERP(t, a->projectedPosition.w, b->projectedPosition.w);
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
normal[i] = LINTERP(t, a->normal[i], b->normal[i]);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
normal[i] = LINTERP(t, a->normal[i], b->normal[i]);
|
||||
}
|
||||
|
||||
u16 t_int = (u16)(t * 256);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]);
|
||||
color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]);
|
||||
}
|
||||
u16 t_int = (u16)(t * 256);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]);
|
||||
color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]);
|
||||
}
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]);
|
||||
}
|
||||
|
||||
#undef LINTERP
|
||||
#undef LINTERP_INT
|
||||
}
|
||||
#undef LINTERP
|
||||
#undef LINTERP_INT
|
||||
}
|
||||
};
|
||||
|
@ -34,427 +34,436 @@ static RasterBlock rasterBlock;
|
||||
|
||||
void Init()
|
||||
{
|
||||
tev.Init();
|
||||
tev.Init();
|
||||
|
||||
// Set initial z reference plane in the unlikely case that zfreeze is enabled when drawing the first primitive.
|
||||
// TODO: This is just a guess!
|
||||
ZSlope.dfdx = ZSlope.dfdy = 0.f;
|
||||
ZSlope.f0 = 1.f;
|
||||
// Set initial z reference plane in the unlikely case that zfreeze is enabled when drawing the
|
||||
// first primitive.
|
||||
// TODO: This is just a guess!
|
||||
ZSlope.dfdx = ZSlope.dfdy = 0.f;
|
||||
ZSlope.f0 = 1.f;
|
||||
}
|
||||
|
||||
// Returns approximation of log2(f) in s28.4
|
||||
// results are close enough to use for LOD
|
||||
static s32 FixedLog2(float f)
|
||||
{
|
||||
u32 x;
|
||||
std::memcpy(&x, &f, sizeof(u32));
|
||||
u32 x;
|
||||
std::memcpy(&x, &f, sizeof(u32));
|
||||
|
||||
s32 logInt = ((x & 0x7F800000) >> 19) - 2032; // integer part
|
||||
s32 logFract = (x & 0x007fffff) >> 19; // approximate fractional part
|
||||
s32 logInt = ((x & 0x7F800000) >> 19) - 2032; // integer part
|
||||
s32 logFract = (x & 0x007fffff) >> 19; // approximate fractional part
|
||||
|
||||
return logInt + logFract;
|
||||
return logInt + logFract;
|
||||
}
|
||||
|
||||
static inline int iround(float x)
|
||||
{
|
||||
int t = (int)x;
|
||||
if ((x - t) >= 0.5)
|
||||
return t + 1;
|
||||
int t = (int)x;
|
||||
if ((x - t) >= 0.5)
|
||||
return t + 1;
|
||||
|
||||
return t;
|
||||
return t;
|
||||
}
|
||||
|
||||
void SetTevReg(int reg, int comp, s16 color)
|
||||
{
|
||||
tev.SetRegColor(reg, comp, color);
|
||||
tev.SetRegColor(reg, comp, color);
|
||||
}
|
||||
|
||||
static void Draw(s32 x, s32 y, s32 xi, s32 yi)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.rasterizedPixels);
|
||||
INCSTAT(stats.thisFrame.rasterizedPixels);
|
||||
|
||||
float dx = vertexOffsetX + (float)(x - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(y - vertex0Y);
|
||||
float dx = vertexOffsetX + (float)(x - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(y - vertex0Y);
|
||||
|
||||
s32 z = (s32)MathUtil::Clamp<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f);
|
||||
s32 z = (s32)MathUtil::Clamp<float>(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f);
|
||||
|
||||
if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc)
|
||||
{
|
||||
// TODO: Test if perf regs are incremented even if test is disabled
|
||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
||||
if (bpmem.zmode.testenable)
|
||||
{
|
||||
// early z
|
||||
if (!EfbInterface::ZCompare(x, y, z))
|
||||
return;
|
||||
}
|
||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT_ZCOMPLOC);
|
||||
}
|
||||
if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc)
|
||||
{
|
||||
// TODO: Test if perf regs are incremented even if test is disabled
|
||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
||||
if (bpmem.zmode.testenable)
|
||||
{
|
||||
// early z
|
||||
if (!EfbInterface::ZCompare(x, y, z))
|
||||
return;
|
||||
}
|
||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT_ZCOMPLOC);
|
||||
}
|
||||
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
|
||||
tev.Position[0] = x;
|
||||
tev.Position[1] = y;
|
||||
tev.Position[2] = z;
|
||||
tev.Position[0] = x;
|
||||
tev.Position[1] = y;
|
||||
tev.Position[2] = z;
|
||||
|
||||
// colors
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
u16 color = (u16)ColorSlopes[i][comp].GetValue(dx, dy);
|
||||
// colors
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
u16 color = (u16)ColorSlopes[i][comp].GetValue(dx, dy);
|
||||
|
||||
// clamp color value to 0
|
||||
u16 mask = ~(color >> 8);
|
||||
// clamp color value to 0
|
||||
u16 mask = ~(color >> 8);
|
||||
|
||||
tev.Color[i][comp] = color & mask;
|
||||
}
|
||||
}
|
||||
tev.Color[i][comp] = color & mask;
|
||||
}
|
||||
}
|
||||
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
// multiply by 128 because TEV stores UVs as s17.7
|
||||
tev.Uv[i].s = (s32)(pixel.Uv[i][0] * 128);
|
||||
tev.Uv[i].t = (s32)(pixel.Uv[i][1] * 128);
|
||||
}
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
// multiply by 128 because TEV stores UVs as s17.7
|
||||
tev.Uv[i].s = (s32)(pixel.Uv[i][0] * 128);
|
||||
tev.Uv[i].t = (s32)(pixel.Uv[i][1] * 128);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
tev.IndirectLod[i] = rasterBlock.IndirectLod[i];
|
||||
tev.IndirectLinear[i] = rasterBlock.IndirectLinear[i];
|
||||
}
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
tev.IndirectLod[i] = rasterBlock.IndirectLod[i];
|
||||
tev.IndirectLinear[i] = rasterBlock.IndirectLinear[i];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
tev.TextureLod[i] = rasterBlock.TextureLod[i];
|
||||
tev.TextureLinear[i] = rasterBlock.TextureLinear[i];
|
||||
}
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
tev.TextureLod[i] = rasterBlock.TextureLod[i];
|
||||
tev.TextureLinear[i] = rasterBlock.TextureLinear[i];
|
||||
}
|
||||
|
||||
tev.Draw();
|
||||
tev.Draw();
|
||||
}
|
||||
|
||||
static void InitTriangle(float X1, float Y1, s32 xi, s32 yi)
|
||||
{
|
||||
vertex0X = xi;
|
||||
vertex0Y = yi;
|
||||
vertex0X = xi;
|
||||
vertex0Y = yi;
|
||||
|
||||
// adjust a little less than 0.5
|
||||
const float adjust = 0.495f;
|
||||
// adjust a little less than 0.5
|
||||
const float adjust = 0.495f;
|
||||
|
||||
vertexOffsetX = ((float)xi - X1) + adjust;
|
||||
vertexOffsetY = ((float)yi - Y1) + adjust;
|
||||
vertexOffsetX = ((float)xi - X1) + adjust;
|
||||
vertexOffsetY = ((float)yi - Y1) + adjust;
|
||||
}
|
||||
|
||||
static void InitSlope(Slope *slope, float f1, float f2, float f3, float DX31, float DX12, float DY12, float DY31)
|
||||
static void InitSlope(Slope* slope, float f1, float f2, float f3, float DX31, float DX12,
|
||||
float DY12, float DY31)
|
||||
{
|
||||
float DF31 = f3 - f1;
|
||||
float DF21 = f2 - f1;
|
||||
float a = DF31 * -DY12 - DF21 * DY31;
|
||||
float b = DX31 * DF21 + DX12 * DF31;
|
||||
float c = -DX12 * DY31 - DX31 * -DY12;
|
||||
slope->dfdx = -a / c;
|
||||
slope->dfdy = -b / c;
|
||||
slope->f0 = f1;
|
||||
float DF31 = f3 - f1;
|
||||
float DF21 = f2 - f1;
|
||||
float a = DF31 * -DY12 - DF21 * DY31;
|
||||
float b = DX31 * DF21 + DX12 * DF31;
|
||||
float c = -DX12 * DY31 - DX31 * -DY12;
|
||||
slope->dfdx = -a / c;
|
||||
slope->dfdy = -b / c;
|
||||
slope->f0 = f1;
|
||||
}
|
||||
|
||||
static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoord)
|
||||
{
|
||||
const FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
const u8 subTexmap = texmap & 3;
|
||||
const FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
const u8 subTexmap = texmap & 3;
|
||||
|
||||
// LOD calculation requires data from the texture mode for bias, etc.
|
||||
// it does not seem to use the actual texture size
|
||||
const TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
const TexMode1& tm1 = texUnit.texMode1[subTexmap];
|
||||
// LOD calculation requires data from the texture mode for bias, etc.
|
||||
// it does not seem to use the actual texture size
|
||||
const TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
const TexMode1& tm1 = texUnit.texMode1[subTexmap];
|
||||
|
||||
float sDelta, tDelta;
|
||||
if (tm0.diag_lod)
|
||||
{
|
||||
float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float *uv1 = rasterBlock.Pixel[1][1].Uv[texcoord];
|
||||
float sDelta, tDelta;
|
||||
if (tm0.diag_lod)
|
||||
{
|
||||
float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord];
|
||||
|
||||
sDelta = fabsf(uv0[0] - uv1[0]);
|
||||
tDelta = fabsf(uv0[1] - uv1[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float *uv1 = rasterBlock.Pixel[1][0].Uv[texcoord];
|
||||
float *uv2 = rasterBlock.Pixel[0][1].Uv[texcoord];
|
||||
sDelta = fabsf(uv0[0] - uv1[0]);
|
||||
tDelta = fabsf(uv0[1] - uv1[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float* uv1 = rasterBlock.Pixel[1][0].Uv[texcoord];
|
||||
float* uv2 = rasterBlock.Pixel[0][1].Uv[texcoord];
|
||||
|
||||
sDelta = std::max(fabsf(uv0[0] - uv1[0]), fabsf(uv0[0] - uv2[0]));
|
||||
tDelta = std::max(fabsf(uv0[1] - uv1[1]), fabsf(uv0[1] - uv2[1]));
|
||||
}
|
||||
sDelta = std::max(fabsf(uv0[0] - uv1[0]), fabsf(uv0[0] - uv2[0]));
|
||||
tDelta = std::max(fabsf(uv0[1] - uv1[1]), fabsf(uv0[1] - uv2[1]));
|
||||
}
|
||||
|
||||
// get LOD in s28.4
|
||||
s32 lod = FixedLog2(std::max(sDelta, tDelta));
|
||||
// get LOD in s28.4
|
||||
s32 lod = FixedLog2(std::max(sDelta, tDelta));
|
||||
|
||||
// bias is s2.5
|
||||
int bias = tm0.lod_bias;
|
||||
bias >>= 1;
|
||||
lod += bias;
|
||||
// bias is s2.5
|
||||
int bias = tm0.lod_bias;
|
||||
bias >>= 1;
|
||||
lod += bias;
|
||||
|
||||
*linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter));
|
||||
*linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter));
|
||||
|
||||
// NOTE: The order of comparisons for this clamp check matters.
|
||||
if (lod > static_cast<s32>(tm1.max_lod))
|
||||
lod = static_cast<s32>(tm1.max_lod);
|
||||
else if (lod < static_cast<s32>(tm1.min_lod))
|
||||
lod = static_cast<s32>(tm1.min_lod);
|
||||
// NOTE: The order of comparisons for this clamp check matters.
|
||||
if (lod > static_cast<s32>(tm1.max_lod))
|
||||
lod = static_cast<s32>(tm1.max_lod);
|
||||
else if (lod < static_cast<s32>(tm1.min_lod))
|
||||
lod = static_cast<s32>(tm1.min_lod);
|
||||
|
||||
*lodp = lod;
|
||||
*lodp = lod;
|
||||
}
|
||||
|
||||
static void BuildBlock(s32 blockX, s32 blockY)
|
||||
{
|
||||
for (s32 yi = 0; yi < BLOCK_SIZE; yi++)
|
||||
{
|
||||
for (s32 xi = 0; xi < BLOCK_SIZE; xi++)
|
||||
{
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
for (s32 yi = 0; yi < BLOCK_SIZE; yi++)
|
||||
{
|
||||
for (s32 xi = 0; xi < BLOCK_SIZE; xi++)
|
||||
{
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
|
||||
float dx = vertexOffsetX + (float)(xi + blockX - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(yi + blockY - vertex0Y);
|
||||
float dx = vertexOffsetX + (float)(xi + blockX - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(yi + blockY - vertex0Y);
|
||||
|
||||
float invW = 1.0f / WSlope.GetValue(dx, dy);
|
||||
pixel.InvW = invW;
|
||||
float invW = 1.0f / WSlope.GetValue(dx, dy);
|
||||
pixel.InvW = invW;
|
||||
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
float projection = invW;
|
||||
if (xfmem.texMtxInfo[i].projection)
|
||||
{
|
||||
float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
|
||||
if (q != 0.0f)
|
||||
projection = invW / q;
|
||||
}
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
float projection = invW;
|
||||
if (xfmem.texMtxInfo[i].projection)
|
||||
{
|
||||
float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
|
||||
if (q != 0.0f)
|
||||
projection = invW / q;
|
||||
}
|
||||
|
||||
pixel.Uv[i][0] = TexSlopes[i][0].GetValue(dx, dy) * projection;
|
||||
pixel.Uv[i][1] = TexSlopes[i][1].GetValue(dx, dy) * projection;
|
||||
}
|
||||
}
|
||||
}
|
||||
pixel.Uv[i][0] = TexSlopes[i][0].GetValue(dx, dy) * projection;
|
||||
pixel.Uv[i][1] = TexSlopes[i][1].GetValue(dx, dy) * projection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 indref = bpmem.tevindref.hex;
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
u32 texmap = indref & 3;
|
||||
indref >>= 3;
|
||||
u32 texcoord = indref & 3;
|
||||
indref >>= 3;
|
||||
u32 indref = bpmem.tevindref.hex;
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
u32 texmap = indref & 3;
|
||||
indref >>= 3;
|
||||
u32 texcoord = indref & 3;
|
||||
indref >>= 3;
|
||||
|
||||
CalculateLOD(&rasterBlock.IndirectLod[i], &rasterBlock.IndirectLinear[i], texmap, texcoord);
|
||||
}
|
||||
CalculateLOD(&rasterBlock.IndirectLod[i], &rasterBlock.IndirectLinear[i], texmap, texcoord);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
int stageOdd = i&1;
|
||||
const TwoTevStageOrders& order = bpmem.tevorders[i >> 1];
|
||||
if (order.getEnable(stageOdd))
|
||||
{
|
||||
u32 texmap = order.getTexMap(stageOdd);
|
||||
u32 texcoord = order.getTexCoord(stageOdd);
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
int stageOdd = i & 1;
|
||||
const TwoTevStageOrders& order = bpmem.tevorders[i >> 1];
|
||||
if (order.getEnable(stageOdd))
|
||||
{
|
||||
u32 texmap = order.getTexMap(stageOdd);
|
||||
u32 texcoord = order.getTexCoord(stageOdd);
|
||||
|
||||
CalculateLOD(&rasterBlock.TextureLod[i], &rasterBlock.TextureLinear[i], texmap, texcoord);
|
||||
}
|
||||
}
|
||||
CalculateLOD(&rasterBlock.TextureLod[i], &rasterBlock.TextureLinear[i], texmap, texcoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
void DrawTriangleFrontFace(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.numTrianglesDrawn);
|
||||
INCSTAT(stats.thisFrame.numTrianglesDrawn);
|
||||
|
||||
// adapted from http://devmaster.net/posts/6145/advanced-rasterization
|
||||
// adapted from http://devmaster.net/posts/6145/advanced-rasterization
|
||||
|
||||
// 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output
|
||||
// could also take floor and adjust -8
|
||||
const s32 Y1 = iround(16.0f * v0->screenPosition[1]) - 9;
|
||||
const s32 Y2 = iround(16.0f * v1->screenPosition[1]) - 9;
|
||||
const s32 Y3 = iround(16.0f * v2->screenPosition[1]) - 9;
|
||||
// 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output
|
||||
// could also take floor and adjust -8
|
||||
const s32 Y1 = iround(16.0f * v0->screenPosition[1]) - 9;
|
||||
const s32 Y2 = iround(16.0f * v1->screenPosition[1]) - 9;
|
||||
const s32 Y3 = iround(16.0f * v2->screenPosition[1]) - 9;
|
||||
|
||||
const s32 X1 = iround(16.0f * v0->screenPosition[0]) - 9;
|
||||
const s32 X2 = iround(16.0f * v1->screenPosition[0]) - 9;
|
||||
const s32 X3 = iround(16.0f * v2->screenPosition[0]) - 9;
|
||||
const s32 X1 = iround(16.0f * v0->screenPosition[0]) - 9;
|
||||
const s32 X2 = iround(16.0f * v1->screenPosition[0]) - 9;
|
||||
const s32 X3 = iround(16.0f * v2->screenPosition[0]) - 9;
|
||||
|
||||
// Deltas
|
||||
const s32 DX12 = X1 - X2;
|
||||
const s32 DX23 = X2 - X3;
|
||||
const s32 DX31 = X3 - X1;
|
||||
// Deltas
|
||||
const s32 DX12 = X1 - X2;
|
||||
const s32 DX23 = X2 - X3;
|
||||
const s32 DX31 = X3 - X1;
|
||||
|
||||
const s32 DY12 = Y1 - Y2;
|
||||
const s32 DY23 = Y2 - Y3;
|
||||
const s32 DY31 = Y3 - Y1;
|
||||
const s32 DY12 = Y1 - Y2;
|
||||
const s32 DY23 = Y2 - Y3;
|
||||
const s32 DY31 = Y3 - Y1;
|
||||
|
||||
// Fixed-pos32 deltas
|
||||
const s32 FDX12 = DX12 * 16;
|
||||
const s32 FDX23 = DX23 * 16;
|
||||
const s32 FDX31 = DX31 * 16;
|
||||
// Fixed-pos32 deltas
|
||||
const s32 FDX12 = DX12 * 16;
|
||||
const s32 FDX23 = DX23 * 16;
|
||||
const s32 FDX31 = DX31 * 16;
|
||||
|
||||
const s32 FDY12 = DY12 * 16;
|
||||
const s32 FDY23 = DY23 * 16;
|
||||
const s32 FDY31 = DY31 * 16;
|
||||
const s32 FDY12 = DY12 * 16;
|
||||
const s32 FDY23 = DY23 * 16;
|
||||
const s32 FDY31 = DY31 * 16;
|
||||
|
||||
// Bounding rectangle
|
||||
s32 minx = (std::min(std::min(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 maxx = (std::max(std::max(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 miny = (std::min(std::min(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
s32 maxy = (std::max(std::max(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
// Bounding rectangle
|
||||
s32 minx = (std::min(std::min(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 maxx = (std::max(std::max(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 miny = (std::min(std::min(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
s32 maxy = (std::max(std::max(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
|
||||
// scissor
|
||||
int xoff = bpmem.scissorOffset.x * 2 - 342;
|
||||
int yoff = bpmem.scissorOffset.y * 2 - 342;
|
||||
// scissor
|
||||
int xoff = bpmem.scissorOffset.x * 2 - 342;
|
||||
int yoff = bpmem.scissorOffset.y * 2 - 342;
|
||||
|
||||
s32 scissorLeft = bpmem.scissorTL.x - xoff - 342;
|
||||
if (scissorLeft < 0)
|
||||
scissorLeft = 0;
|
||||
s32 scissorLeft = bpmem.scissorTL.x - xoff - 342;
|
||||
if (scissorLeft < 0)
|
||||
scissorLeft = 0;
|
||||
|
||||
s32 scissorTop = bpmem.scissorTL.y - yoff - 342;
|
||||
if (scissorTop < 0)
|
||||
scissorTop = 0;
|
||||
s32 scissorTop = bpmem.scissorTL.y - yoff - 342;
|
||||
if (scissorTop < 0)
|
||||
scissorTop = 0;
|
||||
|
||||
s32 scissorRight = bpmem.scissorBR.x - xoff - 341;
|
||||
if (scissorRight > EFB_WIDTH)
|
||||
scissorRight = EFB_WIDTH;
|
||||
s32 scissorRight = bpmem.scissorBR.x - xoff - 341;
|
||||
if (scissorRight > EFB_WIDTH)
|
||||
scissorRight = EFB_WIDTH;
|
||||
|
||||
s32 scissorBottom = bpmem.scissorBR.y - yoff - 341;
|
||||
if (scissorBottom > EFB_HEIGHT)
|
||||
scissorBottom = EFB_HEIGHT;
|
||||
s32 scissorBottom = bpmem.scissorBR.y - yoff - 341;
|
||||
if (scissorBottom > EFB_HEIGHT)
|
||||
scissorBottom = EFB_HEIGHT;
|
||||
|
||||
minx = std::max(minx, scissorLeft);
|
||||
maxx = std::min(maxx, scissorRight);
|
||||
miny = std::max(miny, scissorTop);
|
||||
maxy = std::min(maxy, scissorBottom);
|
||||
minx = std::max(minx, scissorLeft);
|
||||
maxx = std::min(maxx, scissorRight);
|
||||
miny = std::max(miny, scissorTop);
|
||||
maxy = std::min(maxy, scissorBottom);
|
||||
|
||||
if (minx >= maxx || miny >= maxy)
|
||||
return;
|
||||
if (minx >= maxx || miny >= maxy)
|
||||
return;
|
||||
|
||||
// Setup slopes
|
||||
float fltx1 = v0->screenPosition.x;
|
||||
float flty1 = v0->screenPosition.y;
|
||||
float fltdx31 = v2->screenPosition.x - fltx1;
|
||||
float fltdx12 = fltx1 - v1->screenPosition.x;
|
||||
float fltdy12 = flty1 - v1->screenPosition.y;
|
||||
float fltdy31 = v2->screenPosition.y - flty1;
|
||||
// Setup slopes
|
||||
float fltx1 = v0->screenPosition.x;
|
||||
float flty1 = v0->screenPosition.y;
|
||||
float fltdx31 = v2->screenPosition.x - fltx1;
|
||||
float fltdx12 = fltx1 - v1->screenPosition.x;
|
||||
float fltdy12 = flty1 - v1->screenPosition.y;
|
||||
float fltdy31 = v2->screenPosition.y - flty1;
|
||||
|
||||
InitTriangle(fltx1, flty1, (X1 + 0xF) >> 4, (Y1 + 0xF) >> 4);
|
||||
InitTriangle(fltx1, flty1, (X1 + 0xF) >> 4, (Y1 + 0xF) >> 4);
|
||||
|
||||
float w[3] = { 1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w, 1.0f / v2->projectedPosition.w };
|
||||
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
float w[3] = {1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w,
|
||||
1.0f / v2->projectedPosition.w};
|
||||
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
|
||||
// TODO: The zfreeze emulation is not quite correct, yet!
|
||||
// Many things might prevent us from reaching this line (culling, clipping, scissoring).
|
||||
// However, the zslope is always guaranteed to be calculated unless all vertices are trivially rejected during clipping!
|
||||
// We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring tests fail.
|
||||
if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze)
|
||||
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
// TODO: The zfreeze emulation is not quite correct, yet!
|
||||
// Many things might prevent us from reaching this line (culling, clipping, scissoring).
|
||||
// However, the zslope is always guaranteed to be calculated unless all vertices are trivially
|
||||
// rejected during clipping!
|
||||
// We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring
|
||||
// tests fail.
|
||||
if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze)
|
||||
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31,
|
||||
fltdx12, fltdy12, fltdy31);
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp],
|
||||
fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 3; comp++)
|
||||
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
for (int comp = 0; comp < 3; comp++)
|
||||
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1],
|
||||
v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
|
||||
// Half-edge constants
|
||||
s32 C1 = DY12 * X1 - DX12 * Y1;
|
||||
s32 C2 = DY23 * X2 - DX23 * Y2;
|
||||
s32 C3 = DY31 * X3 - DX31 * Y3;
|
||||
// Half-edge constants
|
||||
s32 C1 = DY12 * X1 - DX12 * Y1;
|
||||
s32 C2 = DY23 * X2 - DX23 * Y2;
|
||||
s32 C3 = DY31 * X3 - DX31 * Y3;
|
||||
|
||||
// Correct for fill convention
|
||||
if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
|
||||
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
|
||||
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
||||
// Correct for fill convention
|
||||
if (DY12 < 0 || (DY12 == 0 && DX12 > 0))
|
||||
C1++;
|
||||
if (DY23 < 0 || (DY23 == 0 && DX23 > 0))
|
||||
C2++;
|
||||
if (DY31 < 0 || (DY31 == 0 && DX31 > 0))
|
||||
C3++;
|
||||
|
||||
// Start in corner of 8x8 block
|
||||
minx &= ~(BLOCK_SIZE - 1);
|
||||
miny &= ~(BLOCK_SIZE - 1);
|
||||
// Start in corner of 8x8 block
|
||||
minx &= ~(BLOCK_SIZE - 1);
|
||||
miny &= ~(BLOCK_SIZE - 1);
|
||||
|
||||
// Loop through blocks
|
||||
for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
|
||||
{
|
||||
for (s32 x = minx; x < maxx; x += BLOCK_SIZE)
|
||||
{
|
||||
// Corners of block
|
||||
s32 x0 = x << 4;
|
||||
s32 x1 = (x + BLOCK_SIZE - 1) << 4;
|
||||
s32 y0 = y << 4;
|
||||
s32 y1 = (y + BLOCK_SIZE - 1) << 4;
|
||||
// Loop through blocks
|
||||
for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
|
||||
{
|
||||
for (s32 x = minx; x < maxx; x += BLOCK_SIZE)
|
||||
{
|
||||
// Corners of block
|
||||
s32 x0 = x << 4;
|
||||
s32 x1 = (x + BLOCK_SIZE - 1) << 4;
|
||||
s32 y0 = y << 4;
|
||||
s32 y1 = (y + BLOCK_SIZE - 1) << 4;
|
||||
|
||||
// Evaluate half-space functions
|
||||
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
|
||||
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
|
||||
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
|
||||
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
|
||||
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
|
||||
// Evaluate half-space functions
|
||||
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
|
||||
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
|
||||
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
|
||||
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
|
||||
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
|
||||
|
||||
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
|
||||
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
|
||||
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
|
||||
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
|
||||
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
|
||||
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
|
||||
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
|
||||
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
|
||||
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
|
||||
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
|
||||
|
||||
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
|
||||
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
|
||||
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
|
||||
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
|
||||
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
|
||||
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
|
||||
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
|
||||
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
|
||||
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
|
||||
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
|
||||
|
||||
// Skip block when outside an edge
|
||||
if (a == 0x0 || b == 0x0 || c == 0x0)
|
||||
continue;
|
||||
// Skip block when outside an edge
|
||||
if (a == 0x0 || b == 0x0 || c == 0x0)
|
||||
continue;
|
||||
|
||||
BuildBlock(x, y);
|
||||
BuildBlock(x, y);
|
||||
|
||||
// Accept whole block when totally covered
|
||||
if (a == 0xF && b == 0xF && c == 0xF)
|
||||
{
|
||||
for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Partially covered block
|
||||
{
|
||||
s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
|
||||
s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
|
||||
s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
|
||||
// Accept whole block when totally covered
|
||||
if (a == 0xF && b == 0xF && c == 0xF)
|
||||
{
|
||||
for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Partially covered block
|
||||
{
|
||||
s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
|
||||
s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
|
||||
s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
|
||||
|
||||
for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
s32 CX1 = CY1;
|
||||
s32 CX2 = CY2;
|
||||
s32 CX3 = CY3;
|
||||
for (s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
s32 CX1 = CY1;
|
||||
s32 CX2 = CY2;
|
||||
s32 CX3 = CY3;
|
||||
|
||||
for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
if (CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
for (s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
if (CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
|
||||
CX1 -= FDY12;
|
||||
CX2 -= FDY23;
|
||||
CX3 -= FDY31;
|
||||
}
|
||||
CX1 -= FDY12;
|
||||
CX2 -= FDY23;
|
||||
CX3 -= FDY31;
|
||||
}
|
||||
|
||||
CY1 += FDX12;
|
||||
CY2 += FDX23;
|
||||
CY3 += FDX31;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CY1 += FDX12;
|
||||
CY2 += FDX23;
|
||||
CY3 += FDX31;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -10,33 +10,33 @@ struct OutputVertexData;
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
void Init();
|
||||
void Init();
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
void DrawTriangleFrontFace(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2);
|
||||
|
||||
void SetTevReg(int reg, int comp, s16 color);
|
||||
void SetTevReg(int reg, int comp, s16 color);
|
||||
|
||||
struct Slope
|
||||
{
|
||||
float dfdx;
|
||||
float dfdy;
|
||||
float f0;
|
||||
struct Slope
|
||||
{
|
||||
float dfdx;
|
||||
float dfdy;
|
||||
float f0;
|
||||
|
||||
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
|
||||
};
|
||||
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
|
||||
};
|
||||
|
||||
struct RasterBlockPixel
|
||||
{
|
||||
float InvW;
|
||||
float Uv[8][2];
|
||||
};
|
||||
struct RasterBlockPixel
|
||||
{
|
||||
float InvW;
|
||||
float Uv[8][2];
|
||||
};
|
||||
|
||||
struct RasterBlock
|
||||
{
|
||||
RasterBlockPixel Pixel[2][2];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
};
|
||||
struct RasterBlock
|
||||
{
|
||||
RasterBlockPixel Pixel[2][2];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
};
|
||||
}
|
||||
|
@ -12,120 +12,118 @@
|
||||
|
||||
std::unique_ptr<SWOGLWindow> SWOGLWindow::s_instance;
|
||||
|
||||
void SWOGLWindow::Init(void *window_handle)
|
||||
void SWOGLWindow::Init(void* window_handle)
|
||||
{
|
||||
InitInterface();
|
||||
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
|
||||
if (!GLInterface->Create(window_handle))
|
||||
{
|
||||
INFO_LOG(VIDEO, "GLInterface::Create failed.");
|
||||
}
|
||||
InitInterface();
|
||||
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
|
||||
if (!GLInterface->Create(window_handle))
|
||||
{
|
||||
INFO_LOG(VIDEO, "GLInterface::Create failed.");
|
||||
}
|
||||
|
||||
s_instance.reset(new SWOGLWindow());
|
||||
s_instance.reset(new SWOGLWindow());
|
||||
}
|
||||
|
||||
void SWOGLWindow::Shutdown()
|
||||
{
|
||||
GLInterface->Shutdown();
|
||||
GLInterface.reset();
|
||||
GLInterface->Shutdown();
|
||||
GLInterface.reset();
|
||||
|
||||
s_instance.reset();
|
||||
s_instance.reset();
|
||||
}
|
||||
|
||||
void SWOGLWindow::Prepare()
|
||||
{
|
||||
if (m_init) return;
|
||||
m_init = true;
|
||||
if (m_init)
|
||||
return;
|
||||
m_init = true;
|
||||
|
||||
// Init extension support.
|
||||
if (!GLExtensions::Init())
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?");
|
||||
return;
|
||||
}
|
||||
else if (GLExtensions::Version() < 310)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.", GLExtensions::Version());
|
||||
return;
|
||||
}
|
||||
// Init extension support.
|
||||
if (!GLExtensions::Init())
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?");
|
||||
return;
|
||||
}
|
||||
else if (GLExtensions::Version() < 310)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.",
|
||||
GLExtensions::Version());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string frag_shader =
|
||||
"in vec2 TexCoord;\n"
|
||||
"out vec4 ColorOut;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"void main() {\n"
|
||||
" ColorOut = texture2D(Texture, TexCoord);\n"
|
||||
"}\n";
|
||||
std::string frag_shader = "in vec2 TexCoord;\n"
|
||||
"out vec4 ColorOut;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"void main() {\n"
|
||||
" ColorOut = texture2D(Texture, TexCoord);\n"
|
||||
"}\n";
|
||||
|
||||
std::string vertex_shader =
|
||||
"out vec2 TexCoord;\n"
|
||||
"void main() {\n"
|
||||
" vec2 rawpos = vec2(gl_VertexID & 1, (gl_VertexID & 2) >> 1);\n"
|
||||
" gl_Position = vec4(rawpos * 2.0 - 1.0, 0.0, 1.0);\n"
|
||||
" TexCoord = vec2(rawpos.x, -rawpos.y);\n"
|
||||
"}\n";
|
||||
std::string vertex_shader = "out vec2 TexCoord;\n"
|
||||
"void main() {\n"
|
||||
" vec2 rawpos = vec2(gl_VertexID & 1, (gl_VertexID & 2) >> 1);\n"
|
||||
" gl_Position = vec4(rawpos * 2.0 - 1.0, 0.0, 1.0);\n"
|
||||
" TexCoord = vec2(rawpos.x, -rawpos.y);\n"
|
||||
"}\n";
|
||||
|
||||
std::string header =
|
||||
GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ?
|
||||
"#version 140\n"
|
||||
:
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n";
|
||||
std::string header = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ?
|
||||
"#version 140\n" :
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n";
|
||||
|
||||
m_image_program = OpenGL_CompileProgram(header + vertex_shader, header + frag_shader);
|
||||
m_image_program = OpenGL_CompileProgram(header + vertex_shader, header + frag_shader);
|
||||
|
||||
glUseProgram(m_image_program);
|
||||
glUseProgram(m_image_program);
|
||||
|
||||
glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0);
|
||||
glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0);
|
||||
|
||||
glGenTextures(1, &m_image_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glGenTextures(1, &m_image_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenVertexArrays(1, &m_image_vao);
|
||||
glGenVertexArrays(1, &m_image_vao);
|
||||
}
|
||||
|
||||
void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
|
||||
{
|
||||
TextData data{text, x, y, color};
|
||||
m_text.emplace_back(data);
|
||||
TextData data{text, x, y, color};
|
||||
m_text.emplace_back(data);
|
||||
}
|
||||
|
||||
void SWOGLWindow::ShowImage(u8* data, int stride, int width, int height, float aspect)
|
||||
{
|
||||
GLInterface->MakeCurrent();
|
||||
GLInterface->Update();
|
||||
Prepare();
|
||||
GLInterface->MakeCurrent();
|
||||
GLInterface->Update();
|
||||
Prepare();
|
||||
|
||||
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
|
||||
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
|
||||
|
||||
glViewport(0, 0, glWidth, glHeight);
|
||||
glViewport(0, 0, glWidth, glHeight);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
|
||||
glUseProgram(m_image_program);
|
||||
glUseProgram(m_image_program);
|
||||
|
||||
glBindVertexArray(m_image_vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(m_image_vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
// TODO: implement OSD
|
||||
// for (TextData& text : m_text)
|
||||
// {
|
||||
// }
|
||||
m_text.clear();
|
||||
// TODO: implement OSD
|
||||
// for (TextData& text : m_text)
|
||||
// {
|
||||
// }
|
||||
m_text.clear();
|
||||
|
||||
GLInterface->Swap();
|
||||
GLInterface->ClearCurrent();
|
||||
GLInterface->Swap();
|
||||
GLInterface->ClearCurrent();
|
||||
}
|
||||
|
||||
int SWOGLWindow::PeekMessages()
|
||||
{
|
||||
return GLInterface->PeekMessages();
|
||||
return GLInterface->PeekMessages();
|
||||
}
|
||||
|
||||
|
@ -13,33 +13,32 @@
|
||||
class SWOGLWindow
|
||||
{
|
||||
public:
|
||||
static void Init(void* window_handle);
|
||||
static void Shutdown();
|
||||
static void Init(void* window_handle);
|
||||
static void Shutdown();
|
||||
|
||||
// Will be printed on the *next* image
|
||||
void PrintText(const std::string& text, int x, int y, u32 color);
|
||||
// Will be printed on the *next* image
|
||||
void PrintText(const std::string& text, int x, int y, u32 color);
|
||||
|
||||
// Image to show, will be swapped immediately
|
||||
void ShowImage(u8* data, int stride, int width, int height, float aspect);
|
||||
// Image to show, will be swapped immediately
|
||||
void ShowImage(u8* data, int stride, int width, int height, float aspect);
|
||||
|
||||
int PeekMessages();
|
||||
int PeekMessages();
|
||||
|
||||
static std::unique_ptr<SWOGLWindow> s_instance;
|
||||
static std::unique_ptr<SWOGLWindow> s_instance;
|
||||
|
||||
private:
|
||||
SWOGLWindow() {}
|
||||
SWOGLWindow() {}
|
||||
void Prepare();
|
||||
|
||||
void Prepare();
|
||||
struct TextData
|
||||
{
|
||||
std::string text;
|
||||
int x, y;
|
||||
u32 color;
|
||||
};
|
||||
std::vector<TextData> m_text;
|
||||
|
||||
struct TextData
|
||||
{
|
||||
std::string text;
|
||||
int x, y;
|
||||
u32 color;
|
||||
};
|
||||
std::vector<TextData> m_text;
|
||||
bool m_init{false};
|
||||
|
||||
bool m_init {false};
|
||||
|
||||
u32 m_image_program, m_image_texture, m_image_vao;
|
||||
u32 m_image_program, m_image_texture, m_image_vao;
|
||||
};
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
@ -25,187 +25,193 @@
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static u8 *s_xfbColorTexture[2];
|
||||
static u8* s_xfbColorTexture[2];
|
||||
static int s_currentColorTexture = 0;
|
||||
|
||||
SWRenderer::~SWRenderer()
|
||||
{
|
||||
delete[] s_xfbColorTexture[0];
|
||||
delete[] s_xfbColorTexture[1];
|
||||
delete[] s_xfbColorTexture[0];
|
||||
delete[] s_xfbColorTexture[1];
|
||||
}
|
||||
|
||||
void SWRenderer::Init()
|
||||
{
|
||||
s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
|
||||
s_currentColorTexture = 0;
|
||||
s_currentColorTexture = 0;
|
||||
}
|
||||
|
||||
void SWRenderer::Shutdown()
|
||||
{
|
||||
g_Config.bRunning = false;
|
||||
UpdateActiveConfig();
|
||||
g_Config.bRunning = false;
|
||||
UpdateActiveConfig();
|
||||
}
|
||||
|
||||
void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
|
||||
{
|
||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||
}
|
||||
|
||||
u8* SWRenderer::GetNextColorTexture()
|
||||
{
|
||||
return s_xfbColorTexture[!s_currentColorTexture];
|
||||
return s_xfbColorTexture[!s_currentColorTexture];
|
||||
}
|
||||
|
||||
u8* SWRenderer::GetCurrentColorTexture()
|
||||
{
|
||||
return s_xfbColorTexture[s_currentColorTexture];
|
||||
return s_xfbColorTexture[s_currentColorTexture];
|
||||
}
|
||||
|
||||
void SWRenderer::SwapColorTexture()
|
||||
{
|
||||
s_currentColorTexture = !s_currentColorTexture;
|
||||
s_currentColorTexture = !s_currentColorTexture;
|
||||
}
|
||||
|
||||
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight)
|
||||
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
|
||||
return;
|
||||
}
|
||||
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 offset = 0;
|
||||
u8 *TexturePointer = GetNextColorTexture();
|
||||
u32 offset = 0;
|
||||
u8* TexturePointer = GetNextColorTexture();
|
||||
|
||||
for (u16 y = 0; y < fbHeight; y++)
|
||||
{
|
||||
for (u16 x = 0; x < fbWidth; x+=2)
|
||||
{
|
||||
// We do this one color sample (aka 2 RGB pixles) at a time
|
||||
int Y1 = xfb[x].Y - 16;
|
||||
int Y2 = xfb[x + 1].Y - 16;
|
||||
int U = int(xfb[x].UV) - 128;
|
||||
int V = int(xfb[x + 1].UV) - 128;
|
||||
for (u16 y = 0; y < fbHeight; y++)
|
||||
{
|
||||
for (u16 x = 0; x < fbWidth; x += 2)
|
||||
{
|
||||
// We do this one color sample (aka 2 RGB pixles) at a time
|
||||
int Y1 = xfb[x].Y - 16;
|
||||
int Y2 = xfb[x + 1].Y - 16;
|
||||
int U = int(xfb[x].UV) - 128;
|
||||
int V = int(xfb[x + 1].UV) - 128;
|
||||
|
||||
// We do the inverse BT.601 conversion for YCbCr to RGB
|
||||
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U ), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
// We do the inverse BT.601 conversion for YCbCr to RGB
|
||||
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] =
|
||||
MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U ), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
}
|
||||
xfb += fbWidth;
|
||||
}
|
||||
SwapColorTexture();
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] =
|
||||
MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
}
|
||||
xfb += fbWidth;
|
||||
}
|
||||
SwapColorTexture();
|
||||
}
|
||||
|
||||
// Called on the GPU thread
|
||||
void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma)
|
||||
void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||
const EFBRectangle& rc, float Gamma)
|
||||
{
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (!Fifo::WillSkipCurrentFrame())
|
||||
{
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr);
|
||||
UpdateColorTexture(xfb, fbWidth, fbHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma);
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr);
|
||||
UpdateColorTexture(xfb, fbWidth, fbHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma);
|
||||
}
|
||||
// Save screenshot
|
||||
if (s_bScreenshot)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
||||
|
||||
// Save screenshot
|
||||
if (s_bScreenshot)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
||||
if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight,
|
||||
false))
|
||||
OSD::AddMessage("Screenshot saved to " + s_sScreenshotName);
|
||||
|
||||
if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, false))
|
||||
OSD::AddMessage("Screenshot saved to " + s_sScreenshotName);
|
||||
// Reset settings
|
||||
s_sScreenshotName.clear();
|
||||
s_bScreenshot = false;
|
||||
s_screenshotCompleted.Set();
|
||||
}
|
||||
|
||||
// Reset settings
|
||||
s_sScreenshotName.clear();
|
||||
s_bScreenshot = false;
|
||||
s_screenshotCompleted.Set();
|
||||
}
|
||||
if (SConfig::GetInstance().m_DumpFrames)
|
||||
{
|
||||
static int frame_index = 0;
|
||||
TextureToPng(GetCurrentColorTexture(), fbWidth * 4,
|
||||
StringFromFormat("%sframe%i_color.png",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index),
|
||||
fbWidth, fbHeight, true);
|
||||
frame_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().m_DumpFrames)
|
||||
{
|
||||
static int frame_index = 0;
|
||||
TextureToPng(GetCurrentColorTexture(), fbWidth * 4, StringFromFormat("%sframe%i_color.png",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index), fbWidth, fbHeight, true);
|
||||
frame_index++;
|
||||
}
|
||||
}
|
||||
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
|
||||
|
||||
OSD::DoCallbacks(OSD::CallbackType::OnFrame);
|
||||
DrawDebugText();
|
||||
|
||||
DrawDebugText();
|
||||
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
|
||||
|
||||
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
|
||||
UpdateActiveConfig();
|
||||
|
||||
UpdateActiveConfig();
|
||||
|
||||
// virtual XFB is not supported
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
g_ActiveConfig.bUseRealXFB = true;
|
||||
// virtual XFB is not supported
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
g_ActiveConfig.bUseRealXFB = true;
|
||||
}
|
||||
|
||||
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
|
||||
{
|
||||
u32 value = 0;
|
||||
u32 value = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PEEK_Z:
|
||||
{
|
||||
value = EfbInterface::GetDepth(x, y);
|
||||
break;
|
||||
}
|
||||
case PEEK_COLOR:
|
||||
{
|
||||
u32 color = 0;
|
||||
EfbInterface::GetColor(x, y, (u8*)&color);
|
||||
switch (type)
|
||||
{
|
||||
case PEEK_Z:
|
||||
{
|
||||
value = EfbInterface::GetDepth(x, y);
|
||||
break;
|
||||
}
|
||||
case PEEK_COLOR:
|
||||
{
|
||||
u32 color = 0;
|
||||
EfbInterface::GetColor(x, y, (u8*)&color);
|
||||
|
||||
// rgba to argb
|
||||
value = (color >> 8) | (color & 0xff) << 24;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// rgba to argb
|
||||
value = (color >> 8) | (color & 0xff) << 24;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
u16 SWRenderer::BBoxRead(int index)
|
||||
{
|
||||
return BoundingBox::coords[index];
|
||||
return BoundingBox::coords[index];
|
||||
}
|
||||
|
||||
void SWRenderer::BBoxWrite(int index, u16 value)
|
||||
{
|
||||
BoundingBox::coords[index] = value;
|
||||
BoundingBox::coords[index] = value;
|
||||
}
|
||||
|
||||
TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
{
|
||||
TargetRectangle result;
|
||||
result.left = rc.left;
|
||||
result.top = rc.top;
|
||||
result.right = rc.right;
|
||||
result.bottom = rc.bottom;
|
||||
return result;
|
||||
TargetRectangle result;
|
||||
result.left = rc.left;
|
||||
result.top = rc.top;
|
||||
result.right = rc.right;
|
||||
result.bottom = rc.bottom;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
|
||||
void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable,
|
||||
bool zEnable, u32 color, u32 z)
|
||||
{
|
||||
EfbCopy::ClearEfb();
|
||||
EfbCopy::ClearEfb();
|
||||
}
|
||||
|
@ -14,32 +14,35 @@
|
||||
class SWRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
~SWRenderer() override;
|
||||
~SWRenderer() override;
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static u8* GetNextColorTexture();
|
||||
static u8* GetCurrentColorTexture();
|
||||
void SwapColorTexture();
|
||||
void UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight);
|
||||
static u8* GetNextColorTexture();
|
||||
static u8* GetCurrentColorTexture();
|
||||
void SwapColorTexture();
|
||||
void UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {};
|
||||
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override{};
|
||||
|
||||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
|
||||
int GetMaxTextureSize() override { return 16 * 1024; };
|
||||
int GetMaxTextureSize() override { return 16 * 1024; };
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
|
||||
float Gamma) override;
|
||||
|
||||
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override;
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override;
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override {}
|
||||
|
||||
bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override { return true; };
|
||||
void ReinterpretPixelData(unsigned int convtype) override {}
|
||||
bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override
|
||||
{
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/NativeVertexFormat.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
#include "VideoBackends/Software/SetupUnit.h"
|
||||
#include "VideoBackends/Software/SWVertexLoader.h"
|
||||
#include "VideoBackends/Software/SetupUnit.h"
|
||||
#include "VideoBackends/Software/Tev.h"
|
||||
#include "VideoBackends/Software/TransformUnit.h"
|
||||
|
||||
@ -29,217 +29,220 @@
|
||||
class NullNativeVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
public:
|
||||
NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; }
|
||||
void SetupVertexPointers() override {}
|
||||
NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; }
|
||||
void SetupVertexPointers() override {}
|
||||
};
|
||||
|
||||
NativeVertexFormat* SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
NativeVertexFormat*
|
||||
SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
{
|
||||
return new NullNativeVertexFormat(vtx_decl);
|
||||
return new NullNativeVertexFormat(vtx_decl);
|
||||
}
|
||||
|
||||
SWVertexLoader::SWVertexLoader()
|
||||
{
|
||||
LocalVBuffer.resize(MAXVBUFFERSIZE);
|
||||
LocalIBuffer.resize(MAXIBUFFERSIZE);
|
||||
m_SetupUnit = new SetupUnit;
|
||||
LocalVBuffer.resize(MAXVBUFFERSIZE);
|
||||
LocalIBuffer.resize(MAXIBUFFERSIZE);
|
||||
m_SetupUnit = new SetupUnit;
|
||||
}
|
||||
|
||||
SWVertexLoader::~SWVertexLoader()
|
||||
{
|
||||
delete m_SetupUnit;
|
||||
m_SetupUnit = nullptr;
|
||||
delete m_SetupUnit;
|
||||
m_SetupUnit = nullptr;
|
||||
}
|
||||
|
||||
void SWVertexLoader::ResetBuffer(u32 stride)
|
||||
{
|
||||
s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer.data();
|
||||
s_pEndBufferPointer = s_pCurBufferPointer + LocalVBuffer.size();
|
||||
IndexGenerator::Start(GetIndexBuffer());
|
||||
s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer.data();
|
||||
s_pEndBufferPointer = s_pCurBufferPointer + LocalVBuffer.size();
|
||||
IndexGenerator::Start(GetIndexBuffer());
|
||||
}
|
||||
|
||||
void SWVertexLoader::vFlush(bool useDstAlpha)
|
||||
{
|
||||
DebugUtil::OnObjectBegin();
|
||||
DebugUtil::OnObjectBegin();
|
||||
|
||||
u8 primitiveType = 0;
|
||||
switch (current_primitive_type)
|
||||
{
|
||||
case PRIMITIVE_POINTS:
|
||||
primitiveType = GX_DRAW_POINTS;
|
||||
break;
|
||||
case PRIMITIVE_LINES:
|
||||
primitiveType = GX_DRAW_LINES;
|
||||
break;
|
||||
case PRIMITIVE_TRIANGLES:
|
||||
primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GX_DRAW_TRIANGLE_STRIP : GX_DRAW_TRIANGLES;
|
||||
break;
|
||||
}
|
||||
u8 primitiveType = 0;
|
||||
switch (current_primitive_type)
|
||||
{
|
||||
case PRIMITIVE_POINTS:
|
||||
primitiveType = GX_DRAW_POINTS;
|
||||
break;
|
||||
case PRIMITIVE_LINES:
|
||||
primitiveType = GX_DRAW_LINES;
|
||||
break;
|
||||
case PRIMITIVE_TRIANGLES:
|
||||
primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GX_DRAW_TRIANGLE_STRIP :
|
||||
GX_DRAW_TRIANGLES;
|
||||
break;
|
||||
}
|
||||
|
||||
m_SetupUnit->Init(primitiveType);
|
||||
m_SetupUnit->Init(primitiveType);
|
||||
|
||||
// set all states with are stored within video sw
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Rasterizer::SetTevReg(i, Tev::RED_C, PixelShaderManager::constants.kcolors[i][0]);
|
||||
Rasterizer::SetTevReg(i, Tev::GRN_C, PixelShaderManager::constants.kcolors[i][1]);
|
||||
Rasterizer::SetTevReg(i, Tev::BLU_C, PixelShaderManager::constants.kcolors[i][2]);
|
||||
Rasterizer::SetTevReg(i, Tev::ALP_C, PixelShaderManager::constants.kcolors[i][3]);
|
||||
}
|
||||
// set all states with are stored within video sw
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Rasterizer::SetTevReg(i, Tev::RED_C, PixelShaderManager::constants.kcolors[i][0]);
|
||||
Rasterizer::SetTevReg(i, Tev::GRN_C, PixelShaderManager::constants.kcolors[i][1]);
|
||||
Rasterizer::SetTevReg(i, Tev::BLU_C, PixelShaderManager::constants.kcolors[i][2]);
|
||||
Rasterizer::SetTevReg(i, Tev::ALP_C, PixelShaderManager::constants.kcolors[i][3]);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
|
||||
{
|
||||
u16 index = LocalIBuffer[i];
|
||||
for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++)
|
||||
{
|
||||
u16 index = LocalIBuffer[i];
|
||||
|
||||
if (index == 0xffff)
|
||||
{
|
||||
// primitive restart
|
||||
m_SetupUnit->Init(primitiveType);
|
||||
continue;
|
||||
}
|
||||
memset(&m_Vertex, 0, sizeof(m_Vertex));
|
||||
if (index == 0xffff)
|
||||
{
|
||||
// primitive restart
|
||||
m_SetupUnit->Init(primitiveType);
|
||||
continue;
|
||||
}
|
||||
memset(&m_Vertex, 0, sizeof(m_Vertex));
|
||||
|
||||
// Super Mario Sunshine requires those to be zero for those debug boxes.
|
||||
memset(&m_Vertex.color, 0, sizeof(m_Vertex.color));
|
||||
// Super Mario Sunshine requires those to be zero for those debug boxes.
|
||||
memset(&m_Vertex.color, 0, sizeof(m_Vertex.color));
|
||||
|
||||
// parse the videocommon format to our own struct format (m_Vertex)
|
||||
SetFormat(g_main_cp_state.last_id, primitiveType);
|
||||
ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index);
|
||||
// parse the videocommon format to our own struct format (m_Vertex)
|
||||
SetFormat(g_main_cp_state.last_id, primitiveType);
|
||||
ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index);
|
||||
|
||||
// transform this vertex so that it can be used for rasterization (outVertex)
|
||||
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
|
||||
TransformUnit::TransformPosition(&m_Vertex, outVertex);
|
||||
memset(&outVertex->normal, 0, sizeof(outVertex->normal));
|
||||
if (VertexLoaderManager::g_current_components & VB_HAS_NRM0)
|
||||
{
|
||||
TransformUnit::TransformNormal(&m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex);
|
||||
}
|
||||
TransformUnit::TransformColor(&m_Vertex, outVertex);
|
||||
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
|
||||
// transform this vertex so that it can be used for rasterization (outVertex)
|
||||
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
|
||||
TransformUnit::TransformPosition(&m_Vertex, outVertex);
|
||||
memset(&outVertex->normal, 0, sizeof(outVertex->normal));
|
||||
if (VertexLoaderManager::g_current_components & VB_HAS_NRM0)
|
||||
{
|
||||
TransformUnit::TransformNormal(
|
||||
&m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex);
|
||||
}
|
||||
TransformUnit::TransformColor(&m_Vertex, outVertex);
|
||||
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
|
||||
|
||||
// assemble and rasterize the primitive
|
||||
m_SetupUnit->SetupVertex();
|
||||
// assemble and rasterize the primitive
|
||||
m_SetupUnit->SetupVertex();
|
||||
|
||||
INCSTAT(stats.thisFrame.numVerticesLoaded)
|
||||
}
|
||||
INCSTAT(stats.thisFrame.numVerticesLoaded)
|
||||
}
|
||||
|
||||
DebugUtil::OnObjectEnd();
|
||||
DebugUtil::OnObjectEnd();
|
||||
}
|
||||
|
||||
void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
|
||||
{
|
||||
// matrix index from xf regs or cp memory?
|
||||
if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex1MtxIdx != g_main_cp_state.matrix_index_a.Tex1MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex2MtxIdx != g_main_cp_state.matrix_index_a.Tex2MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex3MtxIdx != g_main_cp_state.matrix_index_a.Tex3MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex4MtxIdx != g_main_cp_state.matrix_index_b.Tex4MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex5MtxIdx != g_main_cp_state.matrix_index_b.Tex5MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex6MtxIdx != g_main_cp_state.matrix_index_b.Tex6MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex7MtxIdx != g_main_cp_state.matrix_index_b.Tex7MtxIdx)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Matrix indices don't match");
|
||||
}
|
||||
// matrix index from xf regs or cp memory?
|
||||
if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex1MtxIdx != g_main_cp_state.matrix_index_a.Tex1MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex2MtxIdx != g_main_cp_state.matrix_index_a.Tex2MtxIdx ||
|
||||
xfmem.MatrixIndexA.Tex3MtxIdx != g_main_cp_state.matrix_index_a.Tex3MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex4MtxIdx != g_main_cp_state.matrix_index_b.Tex4MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex5MtxIdx != g_main_cp_state.matrix_index_b.Tex5MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex6MtxIdx != g_main_cp_state.matrix_index_b.Tex6MtxIdx ||
|
||||
xfmem.MatrixIndexB.Tex7MtxIdx != g_main_cp_state.matrix_index_b.Tex7MtxIdx)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Matrix indices don't match");
|
||||
}
|
||||
|
||||
m_Vertex.posMtx = xfmem.MatrixIndexA.PosNormalMtxIdx;
|
||||
m_Vertex.texMtx[0] = xfmem.MatrixIndexA.Tex0MtxIdx;
|
||||
m_Vertex.texMtx[1] = xfmem.MatrixIndexA.Tex1MtxIdx;
|
||||
m_Vertex.texMtx[2] = xfmem.MatrixIndexA.Tex2MtxIdx;
|
||||
m_Vertex.texMtx[3] = xfmem.MatrixIndexA.Tex3MtxIdx;
|
||||
m_Vertex.texMtx[4] = xfmem.MatrixIndexB.Tex4MtxIdx;
|
||||
m_Vertex.texMtx[5] = xfmem.MatrixIndexB.Tex5MtxIdx;
|
||||
m_Vertex.texMtx[6] = xfmem.MatrixIndexB.Tex6MtxIdx;
|
||||
m_Vertex.texMtx[7] = xfmem.MatrixIndexB.Tex7MtxIdx;
|
||||
m_Vertex.posMtx = xfmem.MatrixIndexA.PosNormalMtxIdx;
|
||||
m_Vertex.texMtx[0] = xfmem.MatrixIndexA.Tex0MtxIdx;
|
||||
m_Vertex.texMtx[1] = xfmem.MatrixIndexA.Tex1MtxIdx;
|
||||
m_Vertex.texMtx[2] = xfmem.MatrixIndexA.Tex2MtxIdx;
|
||||
m_Vertex.texMtx[3] = xfmem.MatrixIndexA.Tex3MtxIdx;
|
||||
m_Vertex.texMtx[4] = xfmem.MatrixIndexB.Tex4MtxIdx;
|
||||
m_Vertex.texMtx[5] = xfmem.MatrixIndexB.Tex5MtxIdx;
|
||||
m_Vertex.texMtx[6] = xfmem.MatrixIndexB.Tex6MtxIdx;
|
||||
m_Vertex.texMtx[7] = xfmem.MatrixIndexB.Tex7MtxIdx;
|
||||
|
||||
|
||||
// special case if only pos and tex coord 0 and tex coord input is AB11
|
||||
// http://libogc.devkitpro.org/gx_8h.html#a55a426a3ff796db584302bddd829f002
|
||||
m_TexGenSpecialCase =
|
||||
VertexLoaderManager::g_current_components == VB_HAS_UV0 &&
|
||||
xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST;
|
||||
// special case if only pos and tex coord 0 and tex coord input is AB11
|
||||
// http://libogc.devkitpro.org/gx_8h.html#a55a426a3ff796db584302bddd829f002
|
||||
m_TexGenSpecialCase = VertexLoaderManager::g_current_components == VB_HAS_UV0 &&
|
||||
xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST;
|
||||
}
|
||||
|
||||
template <typename T, typename I>
|
||||
static T ReadNormalized(I value)
|
||||
{
|
||||
T casted = (T) value;
|
||||
if (!std::numeric_limits<T>::is_integer && std::numeric_limits<I>::is_integer)
|
||||
{
|
||||
// normalize if non-float is converted to a float
|
||||
casted *= (T) (1.0 / std::numeric_limits<I>::max());
|
||||
}
|
||||
return casted;
|
||||
T casted = (T)value;
|
||||
if (!std::numeric_limits<T>::is_integer && std::numeric_limits<I>::is_integer)
|
||||
{
|
||||
// normalize if non-float is converted to a float
|
||||
casted *= (T)(1.0 / std::numeric_limits<I>::max());
|
||||
}
|
||||
return casted;
|
||||
}
|
||||
|
||||
template <typename T, bool swap = false>
|
||||
static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& format, int base_component, int components, bool reverse)
|
||||
static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& format,
|
||||
int base_component, int components, bool reverse)
|
||||
{
|
||||
if (format.enable)
|
||||
{
|
||||
src.Skip(format.offset);
|
||||
src.Skip(base_component * (1<<(format.type>>1)));
|
||||
if (format.enable)
|
||||
{
|
||||
src.Skip(format.offset);
|
||||
src.Skip(base_component * (1 << (format.type >> 1)));
|
||||
|
||||
int i;
|
||||
for (i = 0; i < std::min(format.components - base_component, components); i++)
|
||||
{
|
||||
int i_dst = reverse ? components - i - 1 : i;
|
||||
switch (format.type)
|
||||
{
|
||||
case VAR_UNSIGNED_BYTE:
|
||||
dst[i_dst] = ReadNormalized<T, u8>(src.Read<u8, swap>());
|
||||
break;
|
||||
case VAR_BYTE:
|
||||
dst[i_dst] = ReadNormalized<T, s8>(src.Read<s8, swap>());
|
||||
break;
|
||||
case VAR_UNSIGNED_SHORT:
|
||||
dst[i_dst] = ReadNormalized<T, u16>(src.Read<u16, swap>());
|
||||
break;
|
||||
case VAR_SHORT:
|
||||
dst[i_dst] = ReadNormalized<T, s16>(src.Read<s16, swap>());
|
||||
break;
|
||||
case VAR_FLOAT:
|
||||
dst[i_dst] = ReadNormalized<T, float>(src.Read<float, swap>());
|
||||
break;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < std::min(format.components - base_component, components); i++)
|
||||
{
|
||||
int i_dst = reverse ? components - i - 1 : i;
|
||||
switch (format.type)
|
||||
{
|
||||
case VAR_UNSIGNED_BYTE:
|
||||
dst[i_dst] = ReadNormalized<T, u8>(src.Read<u8, swap>());
|
||||
break;
|
||||
case VAR_BYTE:
|
||||
dst[i_dst] = ReadNormalized<T, s8>(src.Read<s8, swap>());
|
||||
break;
|
||||
case VAR_UNSIGNED_SHORT:
|
||||
dst[i_dst] = ReadNormalized<T, u16>(src.Read<u16, swap>());
|
||||
break;
|
||||
case VAR_SHORT:
|
||||
dst[i_dst] = ReadNormalized<T, s16>(src.Read<s16, swap>());
|
||||
break;
|
||||
case VAR_FLOAT:
|
||||
dst[i_dst] = ReadNormalized<T, float>(src.Read<float, swap>());
|
||||
break;
|
||||
}
|
||||
|
||||
_assert_msg_(VIDEO, !format.integer || format.type != VAR_FLOAT, "only non-float values are allowed to be streamed as integer");
|
||||
}
|
||||
for (; i < components; i++)
|
||||
{
|
||||
int i_dst = reverse ? components - i - 1 : i;
|
||||
dst[i_dst] = i == 3;
|
||||
}
|
||||
}
|
||||
_assert_msg_(VIDEO, !format.integer || format.type != VAR_FLOAT,
|
||||
"only non-float values are allowed to be streamed as integer");
|
||||
}
|
||||
for (; i < components; i++)
|
||||
{
|
||||
int i_dst = reverse ? components - i - 1 : i;
|
||||
dst[i_dst] = i == 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index)
|
||||
{
|
||||
DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size());
|
||||
src.Skip(index * vdec.stride);
|
||||
DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size());
|
||||
src.Skip(index * vdec.stride);
|
||||
|
||||
ReadVertexAttribute<float>(&m_Vertex.position[0], src, vdec.position, 0, 3, false);
|
||||
ReadVertexAttribute<float>(&m_Vertex.position[0], src, vdec.position, 0, 3, false);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
ReadVertexAttribute<float>(&m_Vertex.normal[i][0], src, vdec.normals[i], 0, 3, false);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
ReadVertexAttribute<float>(&m_Vertex.normal[i][0], src, vdec.normals[i], 0, 3, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ReadVertexAttribute<u8>(m_Vertex.color[i], src, vdec.colors[i], 0, 4, true);
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ReadVertexAttribute<u8>(m_Vertex.color[i], src, vdec.colors[i], 0, 4, true);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ReadVertexAttribute<float>(m_Vertex.texCoords[i], src, vdec.texcoords[i], 0, 2, false);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
ReadVertexAttribute<float>(m_Vertex.texCoords[i], src, vdec.texcoords[i], 0, 2, false);
|
||||
|
||||
// the texmtr is stored as third component of the texCoord
|
||||
if (vdec.texcoords[i].components >= 3)
|
||||
{
|
||||
ReadVertexAttribute<u8>(&m_Vertex.texMtx[i], src, vdec.texcoords[i], 2, 1, false);
|
||||
}
|
||||
}
|
||||
// the texmtr is stored as third component of the texCoord
|
||||
if (vdec.texcoords[i].components >= 3)
|
||||
{
|
||||
ReadVertexAttribute<u8>(&m_Vertex.texMtx[i], src, vdec.texcoords[i], 2, 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
ReadVertexAttribute<u8>(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false);
|
||||
ReadVertexAttribute<u8>(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false);
|
||||
}
|
||||
|
@ -20,28 +20,27 @@ class SetupUnit;
|
||||
class SWVertexLoader : public VertexManagerBase
|
||||
{
|
||||
public:
|
||||
SWVertexLoader();
|
||||
~SWVertexLoader();
|
||||
SWVertexLoader();
|
||||
~SWVertexLoader();
|
||||
|
||||
NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override;
|
||||
NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override;
|
||||
|
||||
protected:
|
||||
void ResetBuffer(u32 stride) override;
|
||||
u16* GetIndexBuffer() { return &LocalIBuffer[0]; }
|
||||
void ResetBuffer(u32 stride) override;
|
||||
u16* GetIndexBuffer() { return &LocalIBuffer[0]; }
|
||||
private:
|
||||
void vFlush(bool useDstAlpha) override;
|
||||
std::vector<u8> LocalVBuffer;
|
||||
std::vector<u16> LocalIBuffer;
|
||||
void vFlush(bool useDstAlpha) override;
|
||||
std::vector<u8> LocalVBuffer;
|
||||
std::vector<u16> LocalIBuffer;
|
||||
|
||||
InputVertexData m_Vertex;
|
||||
InputVertexData m_Vertex;
|
||||
|
||||
void ParseVertex(const PortableVertexDeclaration& vdec, int index);
|
||||
void ParseVertex(const PortableVertexDeclaration& vdec, int index);
|
||||
|
||||
SetupUnit *m_SetupUnit;
|
||||
SetupUnit* m_SetupUnit;
|
||||
|
||||
bool m_TexGenSpecialCase;
|
||||
bool m_TexGenSpecialCase;
|
||||
|
||||
public:
|
||||
|
||||
void SetFormat(u8 attributeIndex, u8 primitiveType);
|
||||
void SetFormat(u8 attributeIndex, u8 primitiveType);
|
||||
};
|
||||
|
@ -40,206 +40,208 @@
|
||||
|
||||
namespace SW
|
||||
{
|
||||
|
||||
class PerfQuery : public PerfQueryBase
|
||||
{
|
||||
public:
|
||||
PerfQuery() {}
|
||||
~PerfQuery() {}
|
||||
|
||||
void EnableQuery(PerfQueryGroup type) override {}
|
||||
void DisableQuery(PerfQueryGroup type) override {}
|
||||
void ResetQuery() override
|
||||
{
|
||||
memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
|
||||
}
|
||||
u32 GetQueryResult(PerfQueryType type) override
|
||||
{
|
||||
return EfbInterface::perf_values[type];
|
||||
};
|
||||
void FlushResults() override {}
|
||||
bool IsFlushed() const override { return true; };
|
||||
PerfQuery() {}
|
||||
~PerfQuery() {}
|
||||
void EnableQuery(PerfQueryGroup type) override {}
|
||||
void DisableQuery(PerfQueryGroup type) override {}
|
||||
void ResetQuery() override
|
||||
{
|
||||
memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values));
|
||||
}
|
||||
u32 GetQueryResult(PerfQueryType type) override { return EfbInterface::perf_values[type]; };
|
||||
void FlushResults() override {}
|
||||
bool IsFlushed() const override { return true; };
|
||||
};
|
||||
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
void CompileShaders() override {};
|
||||
void DeleteShaders() override {};
|
||||
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override {};
|
||||
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
void CompileShaders() override{};
|
||||
void DeleteShaders() override{};
|
||||
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette,
|
||||
TlutFormat format) override{};
|
||||
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
|
||||
u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
|
||||
private:
|
||||
struct TCacheEntry : TCacheEntryBase
|
||||
{
|
||||
TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) {}
|
||||
~TCacheEntry() {}
|
||||
struct TCacheEntry : TCacheEntryBase
|
||||
{
|
||||
TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) {}
|
||||
~TCacheEntry() {}
|
||||
void Load(unsigned int width, unsigned int height, unsigned int expanded_width,
|
||||
unsigned int level) override
|
||||
{
|
||||
}
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level) override {}
|
||||
void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
|
||||
bool scaleByHalf, unsigned int cbufid, const float* colmat) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
|
||||
void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
|
||||
bool scaleByHalf, unsigned int cbufid, const float *colmat) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
void CopyRectangleFromTexture(const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override
|
||||
{
|
||||
}
|
||||
|
||||
void CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int>& srcrect,
|
||||
const MathUtil::Rectangle<int>& dstrect) override {}
|
||||
void Bind(unsigned int stage) override {}
|
||||
bool Save(const std::string& filename, unsigned int level) override { return false; }
|
||||
};
|
||||
|
||||
void Bind(unsigned int stage) override {}
|
||||
|
||||
bool Save(const std::string& filename, unsigned int level) override { return false; }
|
||||
};
|
||||
|
||||
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override
|
||||
{
|
||||
return new TCacheEntry(config);
|
||||
}
|
||||
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override
|
||||
{
|
||||
return new TCacheEntry(config);
|
||||
}
|
||||
};
|
||||
|
||||
class XFBSource : public XFBSourceBase
|
||||
{
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {}
|
||||
void CopyEFB(float Gamma) override {}
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {}
|
||||
void CopyEFB(float Gamma) override {}
|
||||
};
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override { return std::make_unique<XFBSource>(); }
|
||||
void GetTargetSize(unsigned int* width, unsigned int* height) override {};
|
||||
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma = 1.0f) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
|
||||
unsigned int target_height,
|
||||
unsigned int layers) override
|
||||
{
|
||||
return std::make_unique<XFBSource>();
|
||||
}
|
||||
void GetTargetSize(unsigned int* width, unsigned int* height) override{};
|
||||
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,
|
||||
float Gamma = 1.0f) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
};
|
||||
|
||||
std::string VideoSoftware::GetName() const
|
||||
{
|
||||
return "Software Renderer";
|
||||
return "Software Renderer";
|
||||
}
|
||||
|
||||
std::string VideoSoftware::GetDisplayName() const
|
||||
{
|
||||
return "Software Renderer";
|
||||
return "Software Renderer";
|
||||
}
|
||||
|
||||
static void InitBackendInfo()
|
||||
{
|
||||
g_Config.backend_info.APIType = API_NONE;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
g_Config.backend_info.bSupportsEarlyZ = true;
|
||||
g_Config.backend_info.bSupportsOversizedViewports = true;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = false;
|
||||
g_Config.backend_info.APIType = API_NONE;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
g_Config.backend_info.bSupportsEarlyZ = true;
|
||||
g_Config.backend_info.bSupportsOversizedViewports = true;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = false;
|
||||
|
||||
// aamodes
|
||||
g_Config.backend_info.AAModes = {1};
|
||||
// aamodes
|
||||
g_Config.backend_info.AAModes = {1};
|
||||
}
|
||||
|
||||
void VideoSoftware::ShowConfig(void *hParent)
|
||||
void VideoSoftware::ShowConfig(void* hParent)
|
||||
{
|
||||
if (!m_initialized)
|
||||
InitBackendInfo();
|
||||
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software");
|
||||
if (!m_initialized)
|
||||
InitBackendInfo();
|
||||
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software");
|
||||
}
|
||||
|
||||
bool VideoSoftware::Initialize(void *window_handle)
|
||||
bool VideoSoftware::Initialize(void* window_handle)
|
||||
{
|
||||
InitializeShared();
|
||||
InitBackendInfo();
|
||||
InitializeShared();
|
||||
InitBackendInfo();
|
||||
|
||||
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str());
|
||||
g_Config.GameIniLoad();
|
||||
g_Config.UpdateProjectionHack();
|
||||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str());
|
||||
g_Config.GameIniLoad();
|
||||
g_Config.UpdateProjectionHack();
|
||||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
||||
SWOGLWindow::Init(window_handle);
|
||||
SWOGLWindow::Init(window_handle);
|
||||
|
||||
PixelEngine::Init();
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
SWRenderer::Init();
|
||||
DebugUtil::Init();
|
||||
PixelEngine::Init();
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
SWRenderer::Init();
|
||||
DebugUtil::Init();
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::CallbackType::Initialization);
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::CallbackType::Initialization);
|
||||
|
||||
m_initialized = true;
|
||||
m_initialized = true;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoSoftware::Shutdown()
|
||||
{
|
||||
m_initialized = false;
|
||||
m_initialized = false;
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::CallbackType::Shutdown);
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::CallbackType::Shutdown);
|
||||
|
||||
SWOGLWindow::Shutdown();
|
||||
SWOGLWindow::Shutdown();
|
||||
}
|
||||
|
||||
void VideoSoftware::Video_Cleanup()
|
||||
{
|
||||
if (g_renderer)
|
||||
{
|
||||
Fifo::Shutdown();
|
||||
SWRenderer::Shutdown();
|
||||
DebugUtil::Shutdown();
|
||||
// The following calls are NOT Thread Safe
|
||||
// And need to be called from the video thread
|
||||
SWRenderer::Shutdown();
|
||||
VertexLoaderManager::Shutdown();
|
||||
g_framebuffer_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
VertexShaderManager::Shutdown();
|
||||
PixelShaderManager::Shutdown();
|
||||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
OpcodeDecoder::Shutdown();
|
||||
g_renderer.reset();
|
||||
}
|
||||
if (g_renderer)
|
||||
{
|
||||
Fifo::Shutdown();
|
||||
SWRenderer::Shutdown();
|
||||
DebugUtil::Shutdown();
|
||||
// The following calls are NOT Thread Safe
|
||||
// And need to be called from the video thread
|
||||
SWRenderer::Shutdown();
|
||||
VertexLoaderManager::Shutdown();
|
||||
g_framebuffer_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
VertexShaderManager::Shutdown();
|
||||
PixelShaderManager::Shutdown();
|
||||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
OpcodeDecoder::Shutdown();
|
||||
g_renderer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// This is called after Video_Initialize() from the Core
|
||||
void VideoSoftware::Video_Prepare()
|
||||
{
|
||||
g_renderer = std::make_unique<SWRenderer>();
|
||||
g_renderer = std::make_unique<SWRenderer>();
|
||||
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
|
||||
BPInit();
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
Fifo::Init(); // must be done before OpcodeDecoder::Init()
|
||||
OpcodeDecoder::Init();
|
||||
IndexGenerator::Init();
|
||||
VertexShaderManager::Init();
|
||||
PixelShaderManager::Init();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
SWRenderer::Init();
|
||||
VertexLoaderManager::Init();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
BPInit();
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
Fifo::Init(); // must be done before OpcodeDecoder::Init()
|
||||
OpcodeDecoder::Init();
|
||||
IndexGenerator::Init();
|
||||
VertexShaderManager::Init();
|
||||
PixelShaderManager::Init();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
SWRenderer::Init();
|
||||
VertexLoaderManager::Init();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
|
||||
// Notify the core that the video backend is ready
|
||||
Host_Message(WM_USER_CREATE);
|
||||
// Notify the core that the video backend is ready
|
||||
Host_Message(WM_USER_CREATE);
|
||||
|
||||
INFO_LOG(VIDEO, "Video backend initialized.");
|
||||
INFO_LOG(VIDEO, "Video backend initialized.");
|
||||
}
|
||||
|
||||
unsigned int VideoSoftware::PeekMessages()
|
||||
{
|
||||
return SWOGLWindow::s_instance->PeekMessages();
|
||||
return SWOGLWindow::s_instance->PeekMessages();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,166 +2,165 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/Software/SetupUnit.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoBackends/Software/SetupUnit.h"
|
||||
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
|
||||
void SetupUnit::Init(u8 primitiveType)
|
||||
{
|
||||
m_PrimType = primitiveType;
|
||||
m_PrimType = primitiveType;
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertPointer[0] = &m_Vertices[0];
|
||||
m_VertPointer[1] = &m_Vertices[1];
|
||||
m_VertPointer[2] = &m_Vertices[2];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
m_VertexCounter = 0;
|
||||
m_VertPointer[0] = &m_Vertices[0];
|
||||
m_VertPointer[1] = &m_Vertices[1];
|
||||
m_VertPointer[2] = &m_Vertices[2];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
OutputVertexData* SetupUnit::GetVertex()
|
||||
{
|
||||
memset(m_VertWritePointer, 0, sizeof(*m_VertWritePointer));
|
||||
return m_VertWritePointer;
|
||||
memset(m_VertWritePointer, 0, sizeof(*m_VertWritePointer));
|
||||
return m_VertWritePointer;
|
||||
}
|
||||
|
||||
void SetupUnit::SetupVertex()
|
||||
{
|
||||
switch (m_PrimType)
|
||||
{
|
||||
case GX_DRAW_QUADS:
|
||||
SetupQuad();
|
||||
break;
|
||||
case GX_DRAW_QUADS_2:
|
||||
WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2");
|
||||
SetupQuad();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLES:
|
||||
SetupTriangle();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_STRIP:
|
||||
SetupTriStrip();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_FAN:
|
||||
SetupTriFan();
|
||||
break;
|
||||
case GX_DRAW_LINES:
|
||||
SetupLine();
|
||||
break;
|
||||
case GX_DRAW_LINE_STRIP:
|
||||
SetupLineStrip();
|
||||
break;
|
||||
case GX_DRAW_POINTS:
|
||||
SetupPoint();
|
||||
break;
|
||||
}
|
||||
switch (m_PrimType)
|
||||
{
|
||||
case GX_DRAW_QUADS:
|
||||
SetupQuad();
|
||||
break;
|
||||
case GX_DRAW_QUADS_2:
|
||||
WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2");
|
||||
SetupQuad();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLES:
|
||||
SetupTriangle();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_STRIP:
|
||||
SetupTriStrip();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_FAN:
|
||||
SetupTriFan();
|
||||
break;
|
||||
case GX_DRAW_LINES:
|
||||
SetupLine();
|
||||
break;
|
||||
case GX_DRAW_LINE_STRIP:
|
||||
SetupLineStrip();
|
||||
break;
|
||||
case GX_DRAW_POINTS:
|
||||
SetupPoint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetupUnit::SetupQuad()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertexCounter &= 3;
|
||||
m_VertWritePointer = &m_Vertices[m_VertexCounter & 1];
|
||||
OutputVertexData* temp = m_VertPointer[1];
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = temp;
|
||||
m_VertexCounter++;
|
||||
m_VertexCounter &= 3;
|
||||
m_VertWritePointer = &m_Vertices[m_VertexCounter & 1];
|
||||
OutputVertexData* temp = m_VertPointer[1];
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = temp;
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriangle()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriStrip()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
|
||||
m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
|
||||
m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriFan()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)];
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)];
|
||||
|
||||
m_VertWritePointer = m_VertPointer[2];
|
||||
m_VertWritePointer = m_VertPointer[2];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupLine()
|
||||
{
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupLineStrip()
|
||||
{
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertexCounter++;
|
||||
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
|
||||
m_VertPointer[0] = m_VertPointer[1];
|
||||
m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1];
|
||||
m_VertPointer[0] = m_VertPointer[1];
|
||||
m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupPoint()
|
||||
{}
|
||||
|
||||
{
|
||||
}
|
||||
|
@ -9,25 +9,25 @@
|
||||
|
||||
class SetupUnit
|
||||
{
|
||||
u8 m_PrimType;
|
||||
int m_VertexCounter;
|
||||
u8 m_PrimType;
|
||||
int m_VertexCounter;
|
||||
|
||||
OutputVertexData m_Vertices[3];
|
||||
OutputVertexData *m_VertPointer[3];
|
||||
OutputVertexData *m_VertWritePointer;
|
||||
OutputVertexData m_Vertices[3];
|
||||
OutputVertexData* m_VertPointer[3];
|
||||
OutputVertexData* m_VertWritePointer;
|
||||
|
||||
void SetupQuad();
|
||||
void SetupTriangle();
|
||||
void SetupTriStrip();
|
||||
void SetupTriFan();
|
||||
void SetupLine();
|
||||
void SetupLineStrip();
|
||||
void SetupPoint();
|
||||
void SetupQuad();
|
||||
void SetupTriangle();
|
||||
void SetupTriStrip();
|
||||
void SetupTriFan();
|
||||
void SetupLine();
|
||||
void SetupLineStrip();
|
||||
void SetupPoint();
|
||||
|
||||
public:
|
||||
void Init(u8 primitiveType);
|
||||
void Init(u8 primitiveType);
|
||||
|
||||
OutputVertexData* GetVertex();
|
||||
OutputVertexData* GetVertex();
|
||||
|
||||
void SetupVertex();
|
||||
void SetupVertex();
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,84 +8,84 @@
|
||||
|
||||
class Tev
|
||||
{
|
||||
struct InputRegType
|
||||
{
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
};
|
||||
struct InputRegType
|
||||
{
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
};
|
||||
|
||||
struct TextureCoordinateType
|
||||
{
|
||||
signed s : 24;
|
||||
signed t : 24;
|
||||
};
|
||||
struct TextureCoordinateType
|
||||
{
|
||||
signed s : 24;
|
||||
signed t : 24;
|
||||
};
|
||||
|
||||
// color order: ABGR
|
||||
s16 Reg[4][4];
|
||||
s16 KonstantColors[4][4];
|
||||
s16 TexColor[4];
|
||||
s16 RasColor[4];
|
||||
s16 StageKonst[4];
|
||||
s16 Zero16[4];
|
||||
// color order: ABGR
|
||||
s16 Reg[4][4];
|
||||
s16 KonstantColors[4][4];
|
||||
s16 TexColor[4];
|
||||
s16 RasColor[4];
|
||||
s16 StageKonst[4];
|
||||
s16 Zero16[4];
|
||||
|
||||
s16 FixedConstants[9];
|
||||
u8 AlphaBump;
|
||||
u8 IndirectTex[4][4];
|
||||
TextureCoordinateType TexCoord;
|
||||
s16 FixedConstants[9];
|
||||
u8 AlphaBump;
|
||||
u8 IndirectTex[4][4];
|
||||
TextureCoordinateType TexCoord;
|
||||
|
||||
s16 *m_ColorInputLUT[16][3];
|
||||
s16 *m_AlphaInputLUT[8]; // values must point to ABGR color
|
||||
s16 *m_KonstLUT[32][4];
|
||||
s16 m_BiasLUT[4];
|
||||
u8 m_ScaleLShiftLUT[4];
|
||||
u8 m_ScaleRShiftLUT[4];
|
||||
s16* m_ColorInputLUT[16][3];
|
||||
s16* m_AlphaInputLUT[8]; // values must point to ABGR color
|
||||
s16* m_KonstLUT[32][4];
|
||||
s16 m_BiasLUT[4];
|
||||
u8 m_ScaleLShiftLUT[4];
|
||||
u8 m_ScaleRShiftLUT[4];
|
||||
|
||||
// enumeration for color input LUT
|
||||
enum
|
||||
{
|
||||
BLU_INP,
|
||||
GRN_INP,
|
||||
RED_INP
|
||||
};
|
||||
// enumeration for color input LUT
|
||||
enum
|
||||
{
|
||||
BLU_INP,
|
||||
GRN_INP,
|
||||
RED_INP
|
||||
};
|
||||
|
||||
enum BufferBase
|
||||
{
|
||||
DIRECT = 0,
|
||||
DIRECT_TFETCH = 16,
|
||||
INDIRECT = 32
|
||||
};
|
||||
enum BufferBase
|
||||
{
|
||||
DIRECT = 0,
|
||||
DIRECT_TFETCH = 16,
|
||||
INDIRECT = 32
|
||||
};
|
||||
|
||||
void SetRasColor(int colorChan, int swaptable);
|
||||
void SetRasColor(int colorChan, int swaptable);
|
||||
|
||||
void DrawColorRegular(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
|
||||
void DrawColorCompare(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
|
||||
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]);
|
||||
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]);
|
||||
void DrawColorRegular(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
|
||||
void DrawColorCompare(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]);
|
||||
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]);
|
||||
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]);
|
||||
|
||||
void Indirect(unsigned int stageNum, s32 s, s32 t);
|
||||
void Indirect(unsigned int stageNum, s32 s, s32 t);
|
||||
|
||||
public:
|
||||
s32 Position[3];
|
||||
u8 Color[2][4]; // must be RGBA for correct swap table ordering
|
||||
TextureCoordinateType Uv[8];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
s32 Position[3];
|
||||
u8 Color[2][4]; // must be RGBA for correct swap table ordering
|
||||
TextureCoordinateType Uv[8];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
|
||||
enum
|
||||
{
|
||||
ALP_C,
|
||||
BLU_C,
|
||||
GRN_C,
|
||||
RED_C
|
||||
};
|
||||
enum
|
||||
{
|
||||
ALP_C,
|
||||
BLU_C,
|
||||
GRN_C,
|
||||
RED_C
|
||||
};
|
||||
|
||||
void Init();
|
||||
void Init();
|
||||
|
||||
void Draw();
|
||||
void Draw();
|
||||
|
||||
void SetRegColor(int reg, int comp, s16 color);
|
||||
void SetRegColor(int reg, int comp, s16 color);
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,5 +8,5 @@
|
||||
|
||||
namespace TextureEncoder
|
||||
{
|
||||
void Encode(u8 *dest_ptr);
|
||||
void Encode(u8* dest_ptr);
|
||||
}
|
||||
|
@ -17,224 +17,232 @@
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
|
||||
static inline void WrapCoord(int* coordp, int wrapMode, int imageSize)
|
||||
{
|
||||
int coord = *coordp;
|
||||
switch (wrapMode)
|
||||
{
|
||||
case 0: // clamp
|
||||
coord = (coord>imageSize)?imageSize:(coord<0)?0:coord;
|
||||
break;
|
||||
case 1: // wrap
|
||||
coord = coord % (imageSize + 1);
|
||||
coord = (coord<0)?imageSize+coord:coord;
|
||||
break;
|
||||
case 2: // mirror
|
||||
{
|
||||
int sizePlus1 = imageSize + 1;
|
||||
int div = coord / sizePlus1;
|
||||
coord = coord - (div * sizePlus1);
|
||||
coord = (coord<0)?-coord:coord;
|
||||
coord = (div&1)?imageSize - coord:coord;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*coordp = coord;
|
||||
int coord = *coordp;
|
||||
switch (wrapMode)
|
||||
{
|
||||
case 0: // clamp
|
||||
coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord;
|
||||
break;
|
||||
case 1: // wrap
|
||||
coord = coord % (imageSize + 1);
|
||||
coord = (coord < 0) ? imageSize + coord : coord;
|
||||
break;
|
||||
case 2: // mirror
|
||||
{
|
||||
int sizePlus1 = imageSize + 1;
|
||||
int div = coord / sizePlus1;
|
||||
coord = coord - (div * sizePlus1);
|
||||
coord = (coord < 0) ? -coord : coord;
|
||||
coord = (div & 1) ? imageSize - coord : coord;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*coordp = coord;
|
||||
}
|
||||
|
||||
static inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
||||
static inline void SetTexel(u8* inTexel, u32* outTexel, u32 fract)
|
||||
{
|
||||
outTexel[0] = inTexel[0] * fract;
|
||||
outTexel[1] = inTexel[1] * fract;
|
||||
outTexel[2] = inTexel[2] * fract;
|
||||
outTexel[3] = inTexel[3] * fract;
|
||||
outTexel[0] = inTexel[0] * fract;
|
||||
outTexel[1] = inTexel[1] * fract;
|
||||
outTexel[2] = inTexel[2] * fract;
|
||||
outTexel[3] = inTexel[3] * fract;
|
||||
}
|
||||
|
||||
static inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
||||
static inline void AddTexel(u8* inTexel, u32* outTexel, u32 fract)
|
||||
{
|
||||
outTexel[0] += inTexel[0] * fract;
|
||||
outTexel[1] += inTexel[1] * fract;
|
||||
outTexel[2] += inTexel[2] * fract;
|
||||
outTexel[3] += inTexel[3] * fract;
|
||||
outTexel[0] += inTexel[0] * fract;
|
||||
outTexel[1] += inTexel[1] * fract;
|
||||
outTexel[2] += inTexel[2] * fract;
|
||||
outTexel[3] += inTexel[3] * fract;
|
||||
}
|
||||
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample)
|
||||
{
|
||||
int baseMip = 0;
|
||||
bool mipLinear = false;
|
||||
int baseMip = 0;
|
||||
bool mipLinear = false;
|
||||
|
||||
#if (ALLOW_MIPMAP)
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
|
||||
|
||||
s32 lodFract = lod & 0xf;
|
||||
s32 lodFract = lod & 0xf;
|
||||
|
||||
if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0))
|
||||
{
|
||||
// use mipmap
|
||||
baseMip = lod >> 4;
|
||||
mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR);
|
||||
if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0))
|
||||
{
|
||||
// use mipmap
|
||||
baseMip = lod >> 4;
|
||||
mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR);
|
||||
|
||||
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
|
||||
baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT);
|
||||
}
|
||||
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
|
||||
baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT);
|
||||
}
|
||||
|
||||
if (mipLinear)
|
||||
{
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
if (mipLinear)
|
||||
{
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
|
||||
SampleMip(s, t, baseMip, linear, texmap, sampledTex);
|
||||
SetTexel(sampledTex, texel, (16 - lodFract));
|
||||
SampleMip(s, t, baseMip, linear, texmap, sampledTex);
|
||||
SetTexel(sampledTex, texel, (16 - lodFract));
|
||||
|
||||
SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex);
|
||||
AddTexel(sampledTex, texel, lodFract);
|
||||
SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex);
|
||||
AddTexel(sampledTex, texel, lodFract);
|
||||
|
||||
sample[0] = (u8)(texel[0] >> 4);
|
||||
sample[1] = (u8)(texel[1] >> 4);
|
||||
sample[2] = (u8)(texel[2] >> 4);
|
||||
sample[3] = (u8)(texel[3] >> 4);
|
||||
}
|
||||
else
|
||||
sample[0] = (u8)(texel[0] >> 4);
|
||||
sample[1] = (u8)(texel[1] >> 4);
|
||||
sample[2] = (u8)(texel[2] >> 4);
|
||||
sample[3] = (u8)(texel[3] >> 4);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SampleMip(s, t, baseMip, linear, texmap, sample);
|
||||
}
|
||||
{
|
||||
SampleMip(s, t, baseMip, linear, texmap, sample);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample)
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
|
||||
TlutFormat tlutfmt = (TlutFormat) texTlut.tlut_format;
|
||||
TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
|
||||
TlutFormat tlutfmt = (TlutFormat)texTlut.tlut_format;
|
||||
|
||||
u8 *imageSrc, *imageSrcOdd = nullptr;
|
||||
if (texUnit.texImage1[subTexmap].image_type)
|
||||
{
|
||||
imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
|
||||
if (ti0.format == GX_TF_RGBA8)
|
||||
imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
|
||||
imageSrc = Memory::GetPointer(imageBase);
|
||||
}
|
||||
u8 *imageSrc, *imageSrcOdd = nullptr;
|
||||
if (texUnit.texImage1[subTexmap].image_type)
|
||||
{
|
||||
imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
|
||||
if (ti0.format == GX_TF_RGBA8)
|
||||
imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
|
||||
imageSrc = Memory::GetPointer(imageBase);
|
||||
}
|
||||
|
||||
int imageWidth = ti0.width;
|
||||
int imageHeight = ti0.height;
|
||||
int imageWidth = ti0.width;
|
||||
int imageHeight = ti0.height;
|
||||
|
||||
int tlutAddress = texTlut.tmem_offset << 9;
|
||||
const u8* tlut = &texMem[tlutAddress];
|
||||
int tlutAddress = texTlut.tmem_offset << 9;
|
||||
const u8* tlut = &texMem[tlutAddress];
|
||||
|
||||
// reduce sample location and texture size to mip level
|
||||
// move texture pointer to mip location
|
||||
if (mip)
|
||||
{
|
||||
int mipWidth = imageWidth + 1;
|
||||
int mipHeight = imageHeight + 1;
|
||||
// reduce sample location and texture size to mip level
|
||||
// move texture pointer to mip location
|
||||
if (mip)
|
||||
{
|
||||
int mipWidth = imageWidth + 1;
|
||||
int mipHeight = imageHeight + 1;
|
||||
|
||||
int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format);
|
||||
int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format);
|
||||
int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
|
||||
int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format);
|
||||
int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format);
|
||||
int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
|
||||
|
||||
imageWidth >>= mip;
|
||||
imageHeight >>= mip;
|
||||
s >>= mip;
|
||||
t >>= mip;
|
||||
imageWidth >>= mip;
|
||||
imageHeight >>= mip;
|
||||
s >>= mip;
|
||||
t >>= mip;
|
||||
|
||||
while (mip)
|
||||
{
|
||||
mipWidth = std::max(mipWidth, fmtWidth);
|
||||
mipHeight = std::max(mipHeight, fmtHeight);
|
||||
u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
|
||||
while (mip)
|
||||
{
|
||||
mipWidth = std::max(mipWidth, fmtWidth);
|
||||
mipHeight = std::max(mipHeight, fmtHeight);
|
||||
u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
|
||||
|
||||
imageSrc += size;
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
mip--;
|
||||
}
|
||||
}
|
||||
imageSrc += size;
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
mip--;
|
||||
}
|
||||
}
|
||||
|
||||
if (linear)
|
||||
{
|
||||
// offset linear sampling
|
||||
s -= 64;
|
||||
t -= 64;
|
||||
if (linear)
|
||||
{
|
||||
// offset linear sampling
|
||||
s -= 64;
|
||||
t -= 64;
|
||||
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
|
||||
// linear sampling
|
||||
int imageSPlus1 = imageS + 1;
|
||||
int fractS = s & 0x7f;
|
||||
// linear sampling
|
||||
int imageSPlus1 = imageS + 1;
|
||||
int fractS = s & 0x7f;
|
||||
|
||||
int imageTPlus1 = imageT + 1;
|
||||
int fractT = t & 0x7f;
|
||||
int imageTPlus1 = imageT + 1;
|
||||
int fractT = t & 0x7f;
|
||||
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
|
||||
WrapCoord(&imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageT, tm0.wrap_t, imageHeight);
|
||||
WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight);
|
||||
WrapCoord(&imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageT, tm0.wrap_t, imageHeight);
|
||||
WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight);
|
||||
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
{
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, tlutfmt);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
{
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut,
|
||||
tlutfmt);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format,
|
||||
tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format,
|
||||
tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
else
|
||||
{
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT, imageWidth);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format,
|
||||
tlut, tlutfmt);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
else
|
||||
{
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT,
|
||||
imageWidth);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT, imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT,
|
||||
imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1, imageWidth);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1,
|
||||
imageWidth);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageTPlus1, imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1,
|
||||
imageTPlus1, imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
|
||||
sample[0] = (u8)(texel[0] >> 14);
|
||||
sample[1] = (u8)(texel[1] >> 14);
|
||||
sample[2] = (u8)(texel[2] >> 14);
|
||||
sample[3] = (u8)(texel[3] >> 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
sample[0] = (u8)(texel[0] >> 14);
|
||||
sample[1] = (u8)(texel[1] >> 14);
|
||||
sample[2] = (u8)(texel[2] >> 14);
|
||||
sample[3] = (u8)(texel[3] >> 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
|
||||
// nearest neighbor sampling
|
||||
WrapCoord(&imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageT, tm0.wrap_t, imageHeight);
|
||||
// nearest neighbor sampling
|
||||
WrapCoord(&imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(&imageT, tm0.wrap_t, imageHeight);
|
||||
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, tlutfmt);
|
||||
else
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, imageWidth);
|
||||
}
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut,
|
||||
tlutfmt);
|
||||
else
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT,
|
||||
imageWidth);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,15 +8,15 @@
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample);
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample);
|
||||
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample);
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample);
|
||||
|
||||
enum
|
||||
{
|
||||
RED_SMP,
|
||||
GRN_SMP,
|
||||
BLU_SMP,
|
||||
ALP_SMP
|
||||
};
|
||||
enum
|
||||
{
|
||||
RED_SMP,
|
||||
GRN_SMP,
|
||||
BLU_SMP,
|
||||
ALP_SMP
|
||||
};
|
||||
}
|
||||
|
@ -17,419 +17,424 @@
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
|
||||
static void MultiplyVec2Mat24(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
static void MultiplyVec2Mat24(const Vec3& vec, const float* mat, Vec3& result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = 1.0f;
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = 1.0f;
|
||||
}
|
||||
|
||||
static void MultiplyVec2Mat34(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
static void MultiplyVec2Mat34(const Vec3& vec, const float* mat, Vec3& result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11];
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11];
|
||||
}
|
||||
|
||||
static void MultiplyVec3Mat33(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
static void MultiplyVec3Mat33(const Vec3& vec, const float* mat, Vec3& result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z;
|
||||
result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z;
|
||||
result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z;
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z;
|
||||
result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z;
|
||||
result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z;
|
||||
}
|
||||
|
||||
static void MultiplyVec3Mat24(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
static void MultiplyVec3Mat24(const Vec3& vec, const float* mat, Vec3& result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = 1.0f;
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = 1.0f;
|
||||
}
|
||||
|
||||
static void MultiplyVec3Mat34(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
static void MultiplyVec3Mat34(const Vec3& vec, const float* mat, Vec3& result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11];
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11];
|
||||
}
|
||||
|
||||
static void MultipleVec3Perspective(const Vec3 &vec, const float *proj, Vec4 &result)
|
||||
static void MultipleVec3Perspective(const Vec3& vec, const float* proj, Vec4& result)
|
||||
{
|
||||
result.x = proj[0] * vec.x + proj[1] * vec.z;
|
||||
result.y = proj[2] * vec.y + proj[3] * vec.z;
|
||||
//result.z = (proj[4] * vec.z + proj[5]);
|
||||
result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7);
|
||||
result.w = -vec.z;
|
||||
result.x = proj[0] * vec.x + proj[1] * vec.z;
|
||||
result.y = proj[2] * vec.y + proj[3] * vec.z;
|
||||
// result.z = (proj[4] * vec.z + proj[5]);
|
||||
result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7);
|
||||
result.w = -vec.z;
|
||||
}
|
||||
|
||||
static void MultipleVec3Ortho(const Vec3 &vec, const float *proj, Vec4 &result)
|
||||
static void MultipleVec3Ortho(const Vec3& vec, const float* proj, Vec4& result)
|
||||
{
|
||||
result.x = proj[0] * vec.x + proj[1];
|
||||
result.y = proj[2] * vec.y + proj[3];
|
||||
result.z = proj[4] * vec.z + proj[5];
|
||||
result.w = 1;
|
||||
result.x = proj[0] * vec.x + proj[1];
|
||||
result.y = proj[2] * vec.y + proj[3];
|
||||
result.z = proj[4] * vec.z + proj[5];
|
||||
result.w = 1;
|
||||
}
|
||||
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst)
|
||||
void TransformPosition(const InputVertexData* src, OutputVertexData* dst)
|
||||
{
|
||||
const float* mat = &xfmem.posMatrices[src->posMtx * 4];
|
||||
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
|
||||
const float* mat = &xfmem.posMatrices[src->posMtx * 4];
|
||||
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
|
||||
|
||||
if (xfmem.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
MultipleVec3Ortho(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition);
|
||||
}
|
||||
if (xfmem.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection,
|
||||
dst->projectedPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
MultipleVec3Ortho(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst)
|
||||
void TransformNormal(const InputVertexData* src, bool nbt, OutputVertexData* dst)
|
||||
{
|
||||
const float* mat = &xfmem.normalMatrices[(src->posMtx & 31) * 3];
|
||||
const float* mat = &xfmem.normalMatrices[(src->posMtx & 31) * 3];
|
||||
|
||||
if (nbt)
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]);
|
||||
MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]);
|
||||
dst->normal[0].Normalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
dst->normal[0].Normalize();
|
||||
}
|
||||
if (nbt)
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]);
|
||||
MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]);
|
||||
dst->normal[0].Normalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
dst->normal[0].Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
static void TransformTexCoordRegular(const TexMtxInfo &texinfo, int coordNum, bool specialCase, const InputVertexData *srcVertex, OutputVertexData *dstVertex)
|
||||
static void TransformTexCoordRegular(const TexMtxInfo& texinfo, int coordNum, bool specialCase,
|
||||
const InputVertexData* srcVertex, OutputVertexData* dstVertex)
|
||||
{
|
||||
const Vec3 *src;
|
||||
switch (texinfo.sourcerow)
|
||||
{
|
||||
case XF_SRCGEOM_INROW:
|
||||
src = &srcVertex->position;
|
||||
break;
|
||||
case XF_SRCNORMAL_INROW:
|
||||
src = &srcVertex->normal[0];
|
||||
break;
|
||||
case XF_SRCBINORMAL_T_INROW:
|
||||
src = &srcVertex->normal[1];
|
||||
break;
|
||||
case XF_SRCBINORMAL_B_INROW:
|
||||
src = &srcVertex->normal[2];
|
||||
break;
|
||||
default:
|
||||
_assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
|
||||
src = (Vec3*)srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW];
|
||||
break;
|
||||
}
|
||||
const Vec3* src;
|
||||
switch (texinfo.sourcerow)
|
||||
{
|
||||
case XF_SRCGEOM_INROW:
|
||||
src = &srcVertex->position;
|
||||
break;
|
||||
case XF_SRCNORMAL_INROW:
|
||||
src = &srcVertex->normal[0];
|
||||
break;
|
||||
case XF_SRCBINORMAL_T_INROW:
|
||||
src = &srcVertex->normal[1];
|
||||
break;
|
||||
case XF_SRCBINORMAL_B_INROW:
|
||||
src = &srcVertex->normal[2];
|
||||
break;
|
||||
default:
|
||||
_assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
|
||||
src = (Vec3*)srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW];
|
||||
break;
|
||||
}
|
||||
|
||||
const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4];
|
||||
Vec3* dst = &dstVertex->texCoords[coordNum];
|
||||
const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4];
|
||||
Vec3* dst = &dstVertex->texCoords[coordNum];
|
||||
|
||||
if (texinfo.projection == XF_TEXPROJ_ST)
|
||||
{
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase)
|
||||
MultiplyVec2Mat24(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat24(*src, mat, *dst);
|
||||
}
|
||||
else // texinfo.projection == XF_TEXPROJ_STQ
|
||||
{
|
||||
_assert_(!specialCase);
|
||||
if (texinfo.projection == XF_TEXPROJ_ST)
|
||||
{
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase)
|
||||
MultiplyVec2Mat24(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat24(*src, mat, *dst);
|
||||
}
|
||||
else // texinfo.projection == XF_TEXPROJ_STQ
|
||||
{
|
||||
_assert_(!specialCase);
|
||||
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11)
|
||||
MultiplyVec2Mat34(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat34(*src, mat, *dst);
|
||||
}
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11)
|
||||
MultiplyVec2Mat34(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat34(*src, mat, *dst);
|
||||
}
|
||||
|
||||
if (xfmem.dualTexTrans.enabled)
|
||||
{
|
||||
Vec3 tempCoord;
|
||||
if (xfmem.dualTexTrans.enabled)
|
||||
{
|
||||
Vec3 tempCoord;
|
||||
|
||||
// normalize
|
||||
const PostMtxInfo &postInfo = xfmem.postMtxInfo[coordNum];
|
||||
const float* postMat = &xfmem.postMatrices[postInfo.index * 4];
|
||||
// normalize
|
||||
const PostMtxInfo& postInfo = xfmem.postMtxInfo[coordNum];
|
||||
const float* postMat = &xfmem.postMatrices[postInfo.index * 4];
|
||||
|
||||
if (specialCase)
|
||||
{
|
||||
// no normalization
|
||||
// q of input is 1
|
||||
// q of output is unknown
|
||||
tempCoord.x = dst->x;
|
||||
tempCoord.y = dst->y;
|
||||
if (specialCase)
|
||||
{
|
||||
// no normalization
|
||||
// q of input is 1
|
||||
// q of output is unknown
|
||||
tempCoord.x = dst->x;
|
||||
tempCoord.y = dst->y;
|
||||
|
||||
dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3];
|
||||
dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7];
|
||||
dst->z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (postInfo.normalize)
|
||||
tempCoord = dst->Normalized();
|
||||
else
|
||||
tempCoord = *dst;
|
||||
dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3];
|
||||
dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7];
|
||||
dst->z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (postInfo.normalize)
|
||||
tempCoord = dst->Normalized();
|
||||
else
|
||||
tempCoord = *dst;
|
||||
|
||||
MultiplyVec3Mat34(tempCoord, postMat, *dst);
|
||||
}
|
||||
}
|
||||
MultiplyVec3Mat34(tempCoord, postMat, *dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LightPointer
|
||||
{
|
||||
u32 reserved[3];
|
||||
u8 color[4];
|
||||
Vec3 cosatt;
|
||||
Vec3 distatt;
|
||||
Vec3 pos;
|
||||
Vec3 dir;
|
||||
u32 reserved[3];
|
||||
u8 color[4];
|
||||
Vec3 cosatt;
|
||||
Vec3 distatt;
|
||||
Vec3 pos;
|
||||
Vec3 dir;
|
||||
};
|
||||
|
||||
static inline void AddScaledIntegerColor(const u8 *src, float scale, Vec3 &dst)
|
||||
static inline void AddScaledIntegerColor(const u8* src, float scale, Vec3& dst)
|
||||
{
|
||||
dst.x += src[1] * scale;
|
||||
dst.y += src[2] * scale;
|
||||
dst.z += src[3] * scale;
|
||||
dst.x += src[1] * scale;
|
||||
dst.y += src[2] * scale;
|
||||
dst.z += src[3] * scale;
|
||||
}
|
||||
|
||||
static inline float SafeDivide(float n, float d)
|
||||
{
|
||||
return (d==0) ? (n>0?1:0) : n/d;
|
||||
return (d == 0) ? (n > 0 ? 1 : 0) : n / d;
|
||||
}
|
||||
|
||||
static float CalculateLightAttn(const LightPointer *light, Vec3* _ldir, const Vec3 &normal, const LitChannel &chan)
|
||||
static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Vec3& normal,
|
||||
const LitChannel& chan)
|
||||
{
|
||||
float attn = 1.0f;
|
||||
Vec3& ldir = *_ldir;
|
||||
float attn = 1.0f;
|
||||
Vec3& ldir = *_ldir;
|
||||
|
||||
switch (chan.attnfunc)
|
||||
{
|
||||
case LIGHTATTN_NONE:
|
||||
case LIGHTATTN_DIR:
|
||||
{
|
||||
ldir = ldir.Normalized();
|
||||
if (ldir == Vec3(0.0f, 0.0f, 0.0f))
|
||||
ldir = normal;
|
||||
break;
|
||||
}
|
||||
case LIGHTATTN_SPEC:
|
||||
{
|
||||
ldir = ldir.Normalized();
|
||||
attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0;
|
||||
Vec3 attLen = Vec3(1.0, attn, attn*attn);
|
||||
Vec3 cosAttn = light->cosatt;
|
||||
Vec3 distAttn = light->distatt;
|
||||
if (chan.diffusefunc != LIGHTDIF_NONE)
|
||||
distAttn = distAttn.Normalized();
|
||||
switch (chan.attnfunc)
|
||||
{
|
||||
case LIGHTATTN_NONE:
|
||||
case LIGHTATTN_DIR:
|
||||
{
|
||||
ldir = ldir.Normalized();
|
||||
if (ldir == Vec3(0.0f, 0.0f, 0.0f))
|
||||
ldir = normal;
|
||||
break;
|
||||
}
|
||||
case LIGHTATTN_SPEC:
|
||||
{
|
||||
ldir = ldir.Normalized();
|
||||
attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0;
|
||||
Vec3 attLen = Vec3(1.0, attn, attn * attn);
|
||||
Vec3 cosAttn = light->cosatt;
|
||||
Vec3 distAttn = light->distatt;
|
||||
if (chan.diffusefunc != LIGHTDIF_NONE)
|
||||
distAttn = distAttn.Normalized();
|
||||
|
||||
attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn);
|
||||
break;
|
||||
}
|
||||
case LIGHTATTN_SPOT:
|
||||
{
|
||||
float dist2 = ldir.Length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = std::max(0.0f, ldir * light->dir);
|
||||
attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn);
|
||||
break;
|
||||
}
|
||||
case LIGHTATTN_SPOT:
|
||||
{
|
||||
float dist2 = ldir.Length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = std::max(0.0f, ldir * light->dir);
|
||||
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = SafeDivide(std::max(0.0f, cosAtt), distAtt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PanicAlert("LightColor");
|
||||
}
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = SafeDivide(std::max(0.0f, cosAtt), distAtt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PanicAlert("LightColor");
|
||||
}
|
||||
|
||||
return attn;
|
||||
return attn;
|
||||
}
|
||||
|
||||
static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, LitChannel &chan, Vec3 &lightCol)
|
||||
static void LightColor(const Vec3& pos, const Vec3& normal, u8 lightNum, LitChannel& chan,
|
||||
Vec3& lightCol)
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum];
|
||||
const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum];
|
||||
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn = CalculateLightAttn(light, &ldir, normal, chan);
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn = CalculateLightAttn(light, &ldir, normal, chan);
|
||||
|
||||
float difAttn = ldir * normal;
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
AddScaledIntegerColor(light->color, attn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
difAttn = std::max(0.0f, difAttn);
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
float difAttn = ldir * normal;
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
AddScaledIntegerColor(light->color, attn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
difAttn = std::max(0.0f, difAttn);
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
break;
|
||||
default:
|
||||
_assert_(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const LitChannel &chan, float &lightCol)
|
||||
static void LightAlpha(const Vec3& pos, const Vec3& normal, u8 lightNum, const LitChannel& chan,
|
||||
float& lightCol)
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum];
|
||||
const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum];
|
||||
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn = CalculateLightAttn(light, &ldir, normal, chan);
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn = CalculateLightAttn(light, &ldir, normal, chan);
|
||||
|
||||
float difAttn = ldir * normal;
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0] * attn;
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
difAttn = std::max(0.0f, difAttn);
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
float difAttn = ldir * normal;
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0] * attn;
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
difAttn = std::max(0.0f, difAttn);
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
break;
|
||||
default:
|
||||
_assert_(0);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst)
|
||||
void TransformColor(const InputVertexData* src, OutputVertexData* dst)
|
||||
{
|
||||
for (u32 chan = 0; chan < xfmem.numChan.numColorChans; chan++)
|
||||
{
|
||||
// abgr
|
||||
u8 matcolor[4];
|
||||
u8 chancolor[4];
|
||||
for (u32 chan = 0; chan < xfmem.numChan.numColorChans; chan++)
|
||||
{
|
||||
// abgr
|
||||
u8 matcolor[4];
|
||||
u8 chancolor[4];
|
||||
|
||||
// color
|
||||
LitChannel &colorchan = xfmem.color[chan];
|
||||
if (colorchan.matsource)
|
||||
*(u32*)matcolor = *(u32*)src->color[chan]; // vertex
|
||||
else
|
||||
*(u32*)matcolor = xfmem.matColor[chan];
|
||||
// color
|
||||
LitChannel& colorchan = xfmem.color[chan];
|
||||
if (colorchan.matsource)
|
||||
*(u32*)matcolor = *(u32*)src->color[chan]; // vertex
|
||||
else
|
||||
*(u32*)matcolor = xfmem.matColor[chan];
|
||||
|
||||
if (colorchan.enablelighting)
|
||||
{
|
||||
Vec3 lightCol;
|
||||
if (colorchan.ambsource)
|
||||
{
|
||||
// vertex
|
||||
lightCol.x = src->color[chan][1];
|
||||
lightCol.y = src->color[chan][2];
|
||||
lightCol.z = src->color[chan][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *ambColor = (u8*)&xfmem.ambColor[chan];
|
||||
lightCol.x = ambColor[1];
|
||||
lightCol.y = ambColor[2];
|
||||
lightCol.z = ambColor[3];
|
||||
}
|
||||
if (colorchan.enablelighting)
|
||||
{
|
||||
Vec3 lightCol;
|
||||
if (colorchan.ambsource)
|
||||
{
|
||||
// vertex
|
||||
lightCol.x = src->color[chan][1];
|
||||
lightCol.y = src->color[chan][2];
|
||||
lightCol.z = src->color[chan][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
u8* ambColor = (u8*)&xfmem.ambColor[chan];
|
||||
lightCol.x = ambColor[1];
|
||||
lightCol.y = ambColor[2];
|
||||
lightCol.z = ambColor[3];
|
||||
}
|
||||
|
||||
u8 mask = colorchan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask&(1<<i))
|
||||
LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol);
|
||||
}
|
||||
u8 mask = colorchan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol);
|
||||
}
|
||||
|
||||
int light_x = MathUtil::Clamp(static_cast<int>(lightCol.x), 0, 255);
|
||||
int light_y = MathUtil::Clamp(static_cast<int>(lightCol.y), 0, 255);
|
||||
int light_z = MathUtil::Clamp(static_cast<int>(lightCol.z), 0, 255);
|
||||
chancolor[1] = (matcolor[1] * (light_x + (light_x >> 7))) >> 8;
|
||||
chancolor[2] = (matcolor[2] * (light_y + (light_y >> 7))) >> 8;
|
||||
chancolor[3] = (matcolor[3] * (light_z + (light_z >> 7))) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u32*)chancolor = *(u32*)matcolor;
|
||||
}
|
||||
int light_x = MathUtil::Clamp(static_cast<int>(lightCol.x), 0, 255);
|
||||
int light_y = MathUtil::Clamp(static_cast<int>(lightCol.y), 0, 255);
|
||||
int light_z = MathUtil::Clamp(static_cast<int>(lightCol.z), 0, 255);
|
||||
chancolor[1] = (matcolor[1] * (light_x + (light_x >> 7))) >> 8;
|
||||
chancolor[2] = (matcolor[2] * (light_y + (light_y >> 7))) >> 8;
|
||||
chancolor[3] = (matcolor[3] * (light_z + (light_z >> 7))) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u32*)chancolor = *(u32*)matcolor;
|
||||
}
|
||||
|
||||
// alpha
|
||||
LitChannel &alphachan = xfmem.alpha[chan];
|
||||
if (alphachan.matsource)
|
||||
matcolor[0] = src->color[chan][0]; // vertex
|
||||
else
|
||||
matcolor[0] = xfmem.matColor[chan] & 0xff;
|
||||
// alpha
|
||||
LitChannel& alphachan = xfmem.alpha[chan];
|
||||
if (alphachan.matsource)
|
||||
matcolor[0] = src->color[chan][0]; // vertex
|
||||
else
|
||||
matcolor[0] = xfmem.matColor[chan] & 0xff;
|
||||
|
||||
if (xfmem.alpha[chan].enablelighting)
|
||||
{
|
||||
float lightCol;
|
||||
if (alphachan.ambsource)
|
||||
lightCol = src->color[chan][0]; // vertex
|
||||
else
|
||||
lightCol = (float)(xfmem.ambColor[chan] & 0xff);
|
||||
if (xfmem.alpha[chan].enablelighting)
|
||||
{
|
||||
float lightCol;
|
||||
if (alphachan.ambsource)
|
||||
lightCol = src->color[chan][0]; // vertex
|
||||
else
|
||||
lightCol = (float)(xfmem.ambColor[chan] & 0xff);
|
||||
|
||||
u8 mask = alphachan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask&(1<<i))
|
||||
LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol);
|
||||
}
|
||||
u8 mask = alphachan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol);
|
||||
}
|
||||
|
||||
int light_a = MathUtil::Clamp(static_cast<int>(lightCol), 0, 255);
|
||||
chancolor[0] = (matcolor[0] * (light_a + (light_a >> 7))) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
chancolor[0] = matcolor[0];
|
||||
}
|
||||
int light_a = MathUtil::Clamp(static_cast<int>(lightCol), 0, 255);
|
||||
chancolor[0] = (matcolor[0] * (light_a + (light_a >> 7))) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
chancolor[0] = matcolor[0];
|
||||
}
|
||||
|
||||
// abgr -> rgba
|
||||
*(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor);
|
||||
}
|
||||
// abgr -> rgba
|
||||
*(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase)
|
||||
void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst, bool specialCase)
|
||||
{
|
||||
for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++)
|
||||
{
|
||||
const TexMtxInfo &texinfo = xfmem.texMtxInfo[coordNum];
|
||||
for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++)
|
||||
{
|
||||
const TexMtxInfo& texinfo = xfmem.texMtxInfo[coordNum];
|
||||
|
||||
switch (texinfo.texgentype)
|
||||
{
|
||||
case XF_TEXGEN_REGULAR:
|
||||
TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst);
|
||||
break;
|
||||
case XF_TEXGEN_EMBOSS_MAP:
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift];
|
||||
switch (texinfo.texgentype)
|
||||
{
|
||||
case XF_TEXGEN_REGULAR:
|
||||
TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst);
|
||||
break;
|
||||
case XF_TEXGEN_EMBOSS_MAP:
|
||||
{
|
||||
const LightPointer* light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift];
|
||||
|
||||
Vec3 ldir = (light->pos - dst->mvPosition).Normalized();
|
||||
float d1 = ldir * dst->normal[1];
|
||||
float d2 = ldir * dst->normal[2];
|
||||
Vec3 ldir = (light->pos - dst->mvPosition).Normalized();
|
||||
float d1 = ldir * dst->normal[1];
|
||||
float d2 = ldir * dst->normal[2];
|
||||
|
||||
dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1;
|
||||
dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2;
|
||||
dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z;
|
||||
}
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC0:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC1:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype);
|
||||
}
|
||||
}
|
||||
dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1;
|
||||
dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2;
|
||||
dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z;
|
||||
}
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC0:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC1:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++)
|
||||
{
|
||||
dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1);
|
||||
dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1);
|
||||
}
|
||||
for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++)
|
||||
{
|
||||
dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1);
|
||||
dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ struct OutputVertexData;
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst);
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase);
|
||||
void TransformPosition(const InputVertexData* src, OutputVertexData* dst);
|
||||
void TransformNormal(const InputVertexData* src, bool nbt, OutputVertexData* dst);
|
||||
void TransformColor(const InputVertexData* src, OutputVertexData* dst);
|
||||
void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst, bool specialCase);
|
||||
}
|
||||
|
@ -12,151 +12,76 @@
|
||||
class Vec3
|
||||
{
|
||||
public:
|
||||
float x, y, z;
|
||||
float x, y, z;
|
||||
|
||||
Vec3()
|
||||
{
|
||||
}
|
||||
Vec3() {}
|
||||
explicit Vec3(float f) { x = y = z = f; }
|
||||
explicit Vec3(const float* f)
|
||||
{
|
||||
x = f[0];
|
||||
y = f[1];
|
||||
z = f[2];
|
||||
}
|
||||
|
||||
explicit Vec3(float f)
|
||||
{
|
||||
x = y = z = f;
|
||||
}
|
||||
Vec3(const float _x, const float _y, const float _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
explicit Vec3(const float *f)
|
||||
{
|
||||
x = f[0];
|
||||
y = f[1];
|
||||
z = f[2];
|
||||
}
|
||||
void set(const float _x, const float _y, const float _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
Vec3(const float _x, const float _y, const float _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
Vec3 operator+(const Vec3& other) const { return Vec3(x + other.x, y + other.y, z + other.z); }
|
||||
void operator+=(const Vec3& other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
}
|
||||
|
||||
void set(const float _x, const float _y, const float _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
Vec3 operator-(const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
|
||||
void operator-=(const Vec3& other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
}
|
||||
|
||||
Vec3 operator+(const Vec3 &other) const
|
||||
{
|
||||
return Vec3(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
Vec3 operator-() const { return Vec3(-x, -y, -z); }
|
||||
Vec3 operator*(const float f) const { return Vec3(x * f, y * f, z * f); }
|
||||
Vec3 operator/(const float f) const
|
||||
{
|
||||
float invf = (1.0f / f);
|
||||
return Vec3(x * invf, y * invf, z * invf);
|
||||
}
|
||||
|
||||
void operator+=(const Vec3 &other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
}
|
||||
void operator/=(const float f) { *this = *this / f; }
|
||||
float operator*(const Vec3& other) const { return (x * other.x) + (y * other.y) + (z * other.z); }
|
||||
void operator*=(const float f) { *this = *this * f; }
|
||||
Vec3 ScaledBy(const Vec3& other) const { return Vec3(x * other.x, y * other.y, z * other.z); }
|
||||
Vec3 operator%(const Vec3& v) const
|
||||
{
|
||||
return Vec3((y * v.z) - (z * v.y), (z * v.x) - (x * v.z), (x * v.y) - (y * v.x));
|
||||
}
|
||||
|
||||
Vec3 operator-(const Vec3 &v) const
|
||||
{
|
||||
return Vec3(x - v.x, y - v.y, z - v.z);
|
||||
}
|
||||
|
||||
void operator-=(const Vec3 &other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
}
|
||||
|
||||
Vec3 operator-() const
|
||||
{
|
||||
return Vec3(-x, -y, -z);
|
||||
}
|
||||
|
||||
Vec3 operator*(const float f) const
|
||||
{
|
||||
return Vec3(x * f, y * f, z * f);
|
||||
}
|
||||
|
||||
Vec3 operator/(const float f) const
|
||||
{
|
||||
float invf = (1.0f / f);
|
||||
return Vec3(x * invf, y * invf, z * invf);
|
||||
}
|
||||
|
||||
void operator/=(const float f)
|
||||
{
|
||||
*this = *this / f;
|
||||
}
|
||||
|
||||
float operator*(const Vec3 &other) const
|
||||
{
|
||||
return (x * other.x) +
|
||||
(y * other.y) +
|
||||
(z * other.z);
|
||||
}
|
||||
|
||||
void operator*=(const float f)
|
||||
{
|
||||
*this = *this * f;
|
||||
}
|
||||
|
||||
Vec3 ScaledBy(const Vec3 &other) const
|
||||
{
|
||||
return Vec3(x * other.x, y * other.y, z * other.z);
|
||||
}
|
||||
|
||||
Vec3 operator%(const Vec3 &v) const
|
||||
{
|
||||
return Vec3((y * v.z) - (z * v.y),
|
||||
(z * v.x) - (x * v.z),
|
||||
(x * v.y) - (y * v.x));
|
||||
}
|
||||
|
||||
float Length2() const
|
||||
{
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
}
|
||||
|
||||
float Length() const
|
||||
{
|
||||
return sqrtf(Length2());
|
||||
}
|
||||
|
||||
float Distance2To(Vec3 &other)
|
||||
{
|
||||
return (other - (*this)).Length2();
|
||||
}
|
||||
|
||||
Vec3 Normalized() const
|
||||
{
|
||||
return (*this) / Length();
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
(*this) /= Length();
|
||||
}
|
||||
|
||||
float &operator[](int i)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
float operator[](const int i) const
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
bool operator==(const Vec3 &other) const
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
|
||||
void SetZero()
|
||||
{
|
||||
x = 0.0f;
|
||||
y = 0.0f;
|
||||
z = 0.0f;
|
||||
}
|
||||
float Length2() const { return (x * x) + (y * y) + (z * z); }
|
||||
float Length() const { return sqrtf(Length2()); }
|
||||
float Distance2To(Vec3& other) { return (other - (*this)).Length2(); }
|
||||
Vec3 Normalized() const { return (*this) / Length(); }
|
||||
void Normalize() { (*this) /= Length(); }
|
||||
float& operator[](int i) { return *((&x) + i); }
|
||||
float operator[](const int i) const { return *((&x) + i); }
|
||||
bool operator==(const Vec3& other) const { return x == other.x && y == other.y && z == other.z; }
|
||||
void SetZero()
|
||||
{
|
||||
x = 0.0f;
|
||||
y = 0.0f;
|
||||
z = 0.0f;
|
||||
}
|
||||
};
|
||||
|
@ -7,25 +7,26 @@
|
||||
#include <string>
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
namespace MMIO { class Mapping; }
|
||||
namespace MMIO
|
||||
{
|
||||
class Mapping;
|
||||
}
|
||||
|
||||
namespace SW
|
||||
{
|
||||
|
||||
class VideoSoftware : public VideoBackendBase
|
||||
{
|
||||
bool Initialize(void *window_handle) override;
|
||||
void Shutdown() override;
|
||||
bool Initialize(void* window_handle) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
std::string GetDisplayName() const override;
|
||||
std::string GetName() const override;
|
||||
std::string GetDisplayName() const override;
|
||||
|
||||
void Video_Prepare() override;
|
||||
void Video_Cleanup() override;
|
||||
void Video_Prepare() override;
|
||||
void Video_Cleanup() override;
|
||||
|
||||
void ShowConfig(void* parent) override;
|
||||
void ShowConfig(void* parent) override;
|
||||
|
||||
unsigned int PeekMessages() override;
|
||||
unsigned int PeekMessages() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user