123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- // Copyright 2009 Dolphin Emulator Project
- // Licensed under GPLv2+
- // Refer to the license.txt file included.
- /*
- Portions of this file are based off work by Markus Trenkwalder.
- Copyright (c) 2007, 2008 Markus Trenkwalder
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the library's copyright owner nor the names of its
- contributors may be used to endorse or promote products derived from this
- software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- 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/BPMemLoader.h"
- #include "VideoBackends/Software/Clipper.h"
- #include "VideoBackends/Software/NativeVertexFormat.h"
- #include "VideoBackends/Software/Rasterizer.h"
- #include "VideoBackends/Software/SWStatistics.h"
- #include "VideoBackends/Software/XFMemLoader.h"
- namespace Clipper
- {
- enum
- {
- NUM_CLIPPED_VERTICES = 33,
- NUM_INDICES = NUM_CLIPPED_VERTICES + 3
- };
- static float m_ViewOffset[2];
- static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
- static OutputVertexData *Vertices[NUM_INDICES];
- void DoState(PointerWrap &p)
- {
- p.DoArray(m_ViewOffset,2);
- for (auto& ClippedVertice : ClippedVertices)
- ClippedVertice.DoState(p);
- }
- void Init()
- {
- for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
- Vertices[i+3] = &ClippedVertices[i];
- }
- void SetViewOffset()
- {
- m_ViewOffset[0] = xfmem.viewport.xOrig - 342;
- m_ViewOffset[1] = xfmem.viewport.yOrig - 342;
- }
- 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(swstats.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(swstats.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(swstats.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(swstats.thisFrame.numTrianglesCulled)
- return false;
- }
- if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
- {
- INCSTAT(swstats.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 + m_ViewOffset[0];
- screen.y = projected.y * wInverse * xfmem.viewport.ht + m_ViewOffset[1];
- screen.z = projected.z * wInverse * xfmem.viewport.zRange + xfmem.viewport.farZ;
- }
- }
|