enable newline normalization
get revision number via `hg svn info` for svnrev.h
ignore incremental/generated binary files (windows/VS at least)
leave a comment if some files need native eol set in svnprops

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5637 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman
2010-06-09 01:37:08 +00:00
parent dacd557f57
commit 4a0c8fc0c9
200 changed files with 94029 additions and 95353 deletions

View File

@ -1,150 +1,150 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "pluginspecs_video.h"
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "Rasterizer.h"
#include "PixelEngine.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
BPMemory bpmem;
void InitBPMemory()
{
memset(&bpmem, 0, sizeof(bpmem));
bpmem.bpMask = 0xFFFFFF;
}
void BPWritten(int address, int newvalue);
void LoadBPReg(u32 value)
{
//handle the mask register
int address = value >> 24;
int oldval = ((u32*)&bpmem)[address];
int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
((u32*)&bpmem)[address] = newval;
//reset the mask register
if (address != 0xFE)
bpmem.bpMask = 0xFFFFFF;
BPWritten(address, newval);
}
void BPWritten(int address, int newvalue)
{
switch (address)
{
case BPMEM_SCISSORTL:
case BPMEM_SCISSORBR:
case BPMEM_SCISSOROFFSET:
Rasterizer::SetScissor();
break;
case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
switch (bpmem.drawdone & 0xFF)
{
case 0x02:
PixelEngine::SetFinish(); // may generate interrupt
DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
default:
WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
}
break;
case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
break;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), TRUE);
break;
case BPMEM_TRIGGER_EFB_COPY:
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
PixelEngine::pereg.boxRight = newvalue >> 10;
PixelEngine::pereg.boxLeft = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
PixelEngine::pereg.boxBottom = newvalue >> 10;
PixelEngine::pereg.boxTop = newvalue & 0x3ff;
break;
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
break;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
{
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
u8 *ptr = 0;
// TODO - figure out a cleaner way.
if (g_VideoInitialize.bWii)
ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.tlutXferSrc << 5);
else
ptr = g_VideoInitialize.pGetMemoryPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
if (ptr)
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
else
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
break;
}
case BPMEM_TEV_REGISTER_L: // Reg 1
case BPMEM_TEV_REGISTER_L+2: // Reg 2
case BPMEM_TEV_REGISTER_L+4: // Reg 3
case BPMEM_TEV_REGISTER_L+6: // Reg 4
{
int regNum = (address >> 1 ) & 0x3;
ColReg& reg = bpmem.tevregs[regNum].low;
bool konst = reg.type;
Rasterizer::SetTevReg(regNum, 3, konst, reg.b); // A
Rasterizer::SetTevReg(regNum, 0, konst, reg.a); // R
break;
}
case BPMEM_TEV_REGISTER_H: // Reg 1
case BPMEM_TEV_REGISTER_H+2: // Reg 2
case BPMEM_TEV_REGISTER_H+4: // Reg 3
case BPMEM_TEV_REGISTER_H+6: // Reg 4
{
int regNum = (address >> 1 ) & 0x3;
ColReg& reg = bpmem.tevregs[regNum].high;
bool konst = reg.type;
Rasterizer::SetTevReg(regNum, 1, konst, reg.b); // G
Rasterizer::SetTevReg(regNum, 2, konst, reg.a); // B
break;
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "pluginspecs_video.h"
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "Rasterizer.h"
#include "PixelEngine.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
BPMemory bpmem;
void InitBPMemory()
{
memset(&bpmem, 0, sizeof(bpmem));
bpmem.bpMask = 0xFFFFFF;
}
void BPWritten(int address, int newvalue);
void LoadBPReg(u32 value)
{
//handle the mask register
int address = value >> 24;
int oldval = ((u32*)&bpmem)[address];
int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
((u32*)&bpmem)[address] = newval;
//reset the mask register
if (address != 0xFE)
bpmem.bpMask = 0xFFFFFF;
BPWritten(address, newval);
}
void BPWritten(int address, int newvalue)
{
switch (address)
{
case BPMEM_SCISSORTL:
case BPMEM_SCISSORBR:
case BPMEM_SCISSOROFFSET:
Rasterizer::SetScissor();
break;
case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
switch (bpmem.drawdone & 0xFF)
{
case 0x02:
PixelEngine::SetFinish(); // may generate interrupt
DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
default:
WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
break;
}
break;
case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
break;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), TRUE);
break;
case BPMEM_TRIGGER_EFB_COPY:
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
PixelEngine::pereg.boxRight = newvalue >> 10;
PixelEngine::pereg.boxLeft = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
PixelEngine::pereg.boxBottom = newvalue >> 10;
PixelEngine::pereg.boxTop = newvalue & 0x3ff;
break;
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
break;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
{
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
u8 *ptr = 0;
// TODO - figure out a cleaner way.
if (g_VideoInitialize.bWii)
ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.tlutXferSrc << 5);
else
ptr = g_VideoInitialize.pGetMemoryPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
if (ptr)
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
else
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
break;
}
case BPMEM_TEV_REGISTER_L: // Reg 1
case BPMEM_TEV_REGISTER_L+2: // Reg 2
case BPMEM_TEV_REGISTER_L+4: // Reg 3
case BPMEM_TEV_REGISTER_L+6: // Reg 4
{
int regNum = (address >> 1 ) & 0x3;
ColReg& reg = bpmem.tevregs[regNum].low;
bool konst = reg.type;
Rasterizer::SetTevReg(regNum, 3, konst, reg.b); // A
Rasterizer::SetTevReg(regNum, 0, konst, reg.a); // R
break;
}
case BPMEM_TEV_REGISTER_H: // Reg 1
case BPMEM_TEV_REGISTER_H+2: // Reg 2
case BPMEM_TEV_REGISTER_H+4: // Reg 3
case BPMEM_TEV_REGISTER_H+6: // Reg 4
{
int regNum = (address >> 1 ) & 0x3;
ColReg& reg = bpmem.tevregs[regNum].high;
bool konst = reg.type;
Rasterizer::SetTevReg(regNum, 1, konst, reg.b); // G
Rasterizer::SetTevReg(regNum, 2, konst, reg.a); // B
break;
}
}
}

View File

@ -1,82 +1,82 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoCommon.h"
#include "CPMemLoader.h"
// CP state
u8 *cached_arraybases[16];
// STATE_TO_SAVE
u32 arraybases[16];
u32 arraystrides[16];
TMatrixIndexA MatrixIndexA;
TMatrixIndexB MatrixIndexB;
TVtxDesc g_VtxDesc;
VAT g_VtxAttr[8];
void LoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
MatrixIndexA.Hex = value;
break;
case 0x40:
MatrixIndexB.Hex = value;
break;
case 0x50:
g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
g_VtxDesc.Hex |= value;
break;
case 0x60:
g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_VtxDesc.Hex |= (u64)value << 17;
break;
case 0x70:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g0.Hex = value;
break;
case 0x80:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g1.Hex = value;
break;
case 0x90:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g2.Hex = value;
break;
// Pointers to vertex arrays in GC RAM
case 0xA0:
arraybases[sub_cmd & 0xF] = value;
cached_arraybases[sub_cmd & 0xF] = Memory_GetPtr(value);
break;
case 0xB0:
arraystrides[sub_cmd & 0xF] = value & 0xFF;
break;
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoCommon.h"
#include "CPMemLoader.h"
// CP state
u8 *cached_arraybases[16];
// STATE_TO_SAVE
u32 arraybases[16];
u32 arraystrides[16];
TMatrixIndexA MatrixIndexA;
TMatrixIndexB MatrixIndexB;
TVtxDesc g_VtxDesc;
VAT g_VtxAttr[8];
void LoadCPReg(u32 sub_cmd, u32 value)
{
switch (sub_cmd & 0xF0)
{
case 0x30:
MatrixIndexA.Hex = value;
break;
case 0x40:
MatrixIndexB.Hex = value;
break;
case 0x50:
g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
g_VtxDesc.Hex |= value;
break;
case 0x60:
g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_VtxDesc.Hex |= (u64)value << 17;
break;
case 0x70:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g0.Hex = value;
break;
case 0x80:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g1.Hex = value;
break;
case 0x90:
_assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g2.Hex = value;
break;
// Pointers to vertex arrays in GC RAM
case 0xA0:
arraybases[sub_cmd & 0xF] = value;
cached_arraybases[sub_cmd & 0xF] = Memory_GetPtr(value);
break;
case 0xB0:
arraystrides[sub_cmd & 0xF] = value & 0xFF;
break;
}
}

View File

@ -1,443 +1,443 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/*
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 "Clipper.h"
#include "Rasterizer.h"
#include "NativeVertexFormat.h"
#include "XFMemLoader.h"
#include "BPMemLoader.h"
#include "Statistics.h"
#include "VideoConfig.h"
namespace Clipper
{
float m_ViewOffset[3];
OutputVertexData ClippedVertices[18];
OutputVertexData *Vertices[21];
void Init()
{
for (int i = 0; i < 18; ++i)
Vertices[i+3] = &ClippedVertices[i];
}
void SetViewOffset()
{
m_ViewOffset[0] = xfregs.viewport.xOrig - 342;
m_ViewOffset[1] = xfregs.viewport.yOrig - 342;
m_ViewOffset[2] = xfregs.viewport.farZ - xfregs.viewport.farZ;
}
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]);
numVertices++;
}
#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; \
} \
} \
}
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];
}
}
}
}
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)
{
if (stats.thisFrame.numDrawnObjects < g_Config.drawStart || stats.thisFrame.numDrawnObjects >= g_Config.drawEnd )
return;
INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface;
if(!CullTest(v0, v1, v2, backface))
return;
int indices[21] = { 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)
{
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]]);
}
}
}
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(abs(dx) > abs(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 * xfregs.viewport.wd + m_ViewOffset[0];
screen.y = projected.y * wInverse * xfregs.viewport.ht + m_ViewOffset[1];
screen.z = projected.z * wInverse + m_ViewOffset[2];
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/*
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 "Clipper.h"
#include "Rasterizer.h"
#include "NativeVertexFormat.h"
#include "XFMemLoader.h"
#include "BPMemLoader.h"
#include "Statistics.h"
#include "VideoConfig.h"
namespace Clipper
{
float m_ViewOffset[3];
OutputVertexData ClippedVertices[18];
OutputVertexData *Vertices[21];
void Init()
{
for (int i = 0; i < 18; ++i)
Vertices[i+3] = &ClippedVertices[i];
}
void SetViewOffset()
{
m_ViewOffset[0] = xfregs.viewport.xOrig - 342;
m_ViewOffset[1] = xfregs.viewport.yOrig - 342;
m_ViewOffset[2] = xfregs.viewport.farZ - xfregs.viewport.farZ;
}
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]);
numVertices++;
}
#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; \
} \
} \
}
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];
}
}
}
}
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)
{
if (stats.thisFrame.numDrawnObjects < g_Config.drawStart || stats.thisFrame.numDrawnObjects >= g_Config.drawEnd )
return;
INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface;
if(!CullTest(v0, v1, v2, backface))
return;
int indices[21] = { 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)
{
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]]);
}
}
}
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(abs(dx) > abs(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 * xfregs.viewport.wd + m_ViewOffset[0];
screen.y = projected.y * wInverse * xfregs.viewport.ht + m_ViewOffset[1];
screen.z = projected.z * wInverse + m_ViewOffset[2];
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +1,170 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COMMANDPROCESSOR_H_
#define _COMMANDPROCESSOR_H_
#include "Common.h"
#include "pluginspecs_video.h"
class PointerWrap;
extern volatile bool g_bSkipCurrentFrame;
// for compatibility with video common
void Fifo_Init();
void Fifo_Shutdown();
void Fifo_DoState(PointerWrap &p);
void Fifo_EnterLoop(const SVideoInitialize &video_initialize);
void Fifo_ExitLoop();
void Fifo_SetRendering(bool bEnabled);
// Implemented by the Video Plugin
void VideoFifo_CheckSwapRequest();
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
void VideoFifo_CheckEFBAccess();
namespace CommandProcessor
{
// internal hardware addresses
enum
{
STATUS_REGISTER = 0x00,
CTRL_REGISTER = 0x02,
CLEAR_REGISTER = 0x04,
FIFO_TOKEN_REGISTER = 0x0E,
FIFO_BOUNDING_BOX_LEFT = 0x10,
FIFO_BOUNDING_BOX_RIGHT = 0x12,
FIFO_BOUNDING_BOX_TOP = 0x14,
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
FIFO_BASE_LO = 0x20,
FIFO_BASE_HI = 0x22,
FIFO_END_LO = 0x24,
FIFO_END_HI = 0x26,
FIFO_HI_WATERMARK_LO = 0x28,
FIFO_HI_WATERMARK_HI = 0x2a,
FIFO_LO_WATERMARK_LO = 0x2c,
FIFO_LO_WATERMARK_HI = 0x2e,
FIFO_RW_DISTANCE_LO = 0x30,
FIFO_RW_DISTANCE_HI = 0x32,
FIFO_WRITE_POINTER_LO = 0x34,
FIFO_WRITE_POINTER_HI = 0x36,
FIFO_READ_POINTER_LO = 0x38,
FIFO_READ_POINTER_HI = 0x3A,
FIFO_BP_LO = 0x3C,
FIFO_BP_HI = 0x3E
};
// Fifo Status Register
union UCPStatusReg
{
struct
{
unsigned OverflowHiWatermark : 1;
unsigned UnderflowLoWatermark : 1;
unsigned ReadIdle : 1; // done reading
unsigned CommandIdle : 1; // done processing commands
unsigned Breakpoint : 1;
unsigned : 11;
};
u16 Hex;
UCPStatusReg() {Hex = 0; }
UCPStatusReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPCtrlReg
{
struct
{
unsigned GPReadEnable : 1;
unsigned BPEnable : 1;
unsigned FifoOverflowIntEnable : 1;
unsigned FifoUnderflowIntEnable : 1;
unsigned GPLinkEnable : 1;
unsigned BreakPointIntEnable : 1;
unsigned : 10;
};
u16 Hex;
UCPCtrlReg() {Hex = 0; }
UCPCtrlReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPClearReg
{
struct
{
unsigned ClearFifoOverflow : 1;
unsigned ClearFifoUnderflow : 1;
unsigned ClearMetrices : 1;
unsigned : 13;
};
u16 Hex;
UCPClearReg() {Hex = 0; }
UCPClearReg(u16 _hex) {Hex = _hex; }
};
struct CPReg
{
UCPStatusReg status; // 0x00
UCPCtrlReg ctrl; // 0x02
UCPClearReg clear; // 0x04
u32 unk0; // 0x06
u32 unk1; // 0x0a
u16 token; // 0x0e
u16 bboxleft; // 0x10
u16 bboxtop; // 0x12
u16 bboxright; // 0x14
u16 bboxbottom; // 0x16
u16 unk2; // 0x18
u32 fifobase; // 0x20
u32 fifoend; // 0x24
u32 hiwatermark; // 0x28
u32 lowatermark; // 0x2c
u32 rwdistance; // 0x30
u32 writeptr; // 0x34
u32 readptr; // 0x38
u32 breakpt; // 0x3c
};
extern CPReg cpreg;
// Init
void Init();
void Shutdown();
void DoState(PointerWrap &p);
bool RunBuffer();
void RunGpu();
// Read
void Read16(u16& _rReturnValue, const u32 _Address);
void Write16(const u16 _Data, const u32 _Address);
void Read32(u32& _rReturnValue, const u32 _Address);
void Write32(const u32 _Data, const u32 _Address);
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts(u64 userdata);
void UpdateInterruptsFromVideoPlugin(u64 userdata);
} // end of namespace CommandProcessor
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COMMANDPROCESSOR_H_
#define _COMMANDPROCESSOR_H_
#include "Common.h"
#include "pluginspecs_video.h"
class PointerWrap;
extern volatile bool g_bSkipCurrentFrame;
// for compatibility with video common
void Fifo_Init();
void Fifo_Shutdown();
void Fifo_DoState(PointerWrap &p);
void Fifo_EnterLoop(const SVideoInitialize &video_initialize);
void Fifo_ExitLoop();
void Fifo_SetRendering(bool bEnabled);
// Implemented by the Video Plugin
void VideoFifo_CheckSwapRequest();
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
void VideoFifo_CheckEFBAccess();
namespace CommandProcessor
{
// internal hardware addresses
enum
{
STATUS_REGISTER = 0x00,
CTRL_REGISTER = 0x02,
CLEAR_REGISTER = 0x04,
FIFO_TOKEN_REGISTER = 0x0E,
FIFO_BOUNDING_BOX_LEFT = 0x10,
FIFO_BOUNDING_BOX_RIGHT = 0x12,
FIFO_BOUNDING_BOX_TOP = 0x14,
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
FIFO_BASE_LO = 0x20,
FIFO_BASE_HI = 0x22,
FIFO_END_LO = 0x24,
FIFO_END_HI = 0x26,
FIFO_HI_WATERMARK_LO = 0x28,
FIFO_HI_WATERMARK_HI = 0x2a,
FIFO_LO_WATERMARK_LO = 0x2c,
FIFO_LO_WATERMARK_HI = 0x2e,
FIFO_RW_DISTANCE_LO = 0x30,
FIFO_RW_DISTANCE_HI = 0x32,
FIFO_WRITE_POINTER_LO = 0x34,
FIFO_WRITE_POINTER_HI = 0x36,
FIFO_READ_POINTER_LO = 0x38,
FIFO_READ_POINTER_HI = 0x3A,
FIFO_BP_LO = 0x3C,
FIFO_BP_HI = 0x3E
};
// Fifo Status Register
union UCPStatusReg
{
struct
{
unsigned OverflowHiWatermark : 1;
unsigned UnderflowLoWatermark : 1;
unsigned ReadIdle : 1; // done reading
unsigned CommandIdle : 1; // done processing commands
unsigned Breakpoint : 1;
unsigned : 11;
};
u16 Hex;
UCPStatusReg() {Hex = 0; }
UCPStatusReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPCtrlReg
{
struct
{
unsigned GPReadEnable : 1;
unsigned BPEnable : 1;
unsigned FifoOverflowIntEnable : 1;
unsigned FifoUnderflowIntEnable : 1;
unsigned GPLinkEnable : 1;
unsigned BreakPointIntEnable : 1;
unsigned : 10;
};
u16 Hex;
UCPCtrlReg() {Hex = 0; }
UCPCtrlReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPClearReg
{
struct
{
unsigned ClearFifoOverflow : 1;
unsigned ClearFifoUnderflow : 1;
unsigned ClearMetrices : 1;
unsigned : 13;
};
u16 Hex;
UCPClearReg() {Hex = 0; }
UCPClearReg(u16 _hex) {Hex = _hex; }
};
struct CPReg
{
UCPStatusReg status; // 0x00
UCPCtrlReg ctrl; // 0x02
UCPClearReg clear; // 0x04
u32 unk0; // 0x06
u32 unk1; // 0x0a
u16 token; // 0x0e
u16 bboxleft; // 0x10
u16 bboxtop; // 0x12
u16 bboxright; // 0x14
u16 bboxbottom; // 0x16
u16 unk2; // 0x18
u32 fifobase; // 0x20
u32 fifoend; // 0x24
u32 hiwatermark; // 0x28
u32 lowatermark; // 0x2c
u32 rwdistance; // 0x30
u32 writeptr; // 0x34
u32 readptr; // 0x38
u32 breakpt; // 0x3c
};
extern CPReg cpreg;
// Init
void Init();
void Shutdown();
void DoState(PointerWrap &p);
bool RunBuffer();
void RunGpu();
// Read
void Read16(u16& _rReturnValue, const u32 _Address);
void Write16(const u16 _Data, const u32 _Address);
void Read32(u32& _rReturnValue, const u32 _Address);
void Write32(const u32 _Data, const u32 _Address);
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts(u64 userdata);
void UpdateInterruptsFromVideoPlugin(u64 userdata);
} // end of namespace CommandProcessor
#endif

View File

@ -1,233 +1,233 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "main.h"
#include "DebugUtil.h"
#include "BPMemLoader.h"
#include "TextureSampler.h"
#include "VideoConfig.h"
#include "EfbInterface.h"
#include "Statistics.h"
#include "HwRasterizer.h"
#include "StringUtil.h"
#include "CommandProcessor.h"
#include "../../../Core/VideoCommon/Src/ImageWrite.h"
#include "FileUtil.h"
namespace DebugUtil
{
u32 skipFrames = 0;
const int NumObjectBuffers = 32;
u8 ObjectBuffer[NumObjectBuffers][EFB_WIDTH*EFB_HEIGHT*4];
bool DrawnToBuffer[NumObjectBuffers];
const char* ObjectBufferName[NumObjectBuffers];
void Init()
{
for (int i = 0; i < NumObjectBuffers; i++)
{
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
DrawnToBuffer[i] = false;
ObjectBufferName[i] = 0;
}
}
void SaveTexture(const char* filename, u32 texmap, s32 mip)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
u8 subTexmap = texmap & 3;
TexImage0& ti0 = texUnit.texImage0[subTexmap];
int width = ti0.width + 1;
int height = ti0.height + 1;
u8 *data = new u8[width * height * 4];
GetTextureBGRA(data, texmap, mip, width, height);
(void)SaveTGA(filename, width, height, data);
delete []data;
}
void GetTextureBGRA(u8 *dst, u32 texmap, s32 mip, int width, int height)
{
u8 sample[4];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++) {
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, sample);
// rgba to bgra
*(dst++) = sample[2];
*(dst++) = sample[1];
*(dst++) = sample[0];
*(dst++) = sample[3];
}
}
s32 GetMaxTextureLod(u32 texmap)
{
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;
if(fract)
++mip;
return (s32)mip;
}
void DumpActiveTextures()
{
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.tga", File::GetUserPath(D_DUMPTEXTURES_IDX), stats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), 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];
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.tga", File::GetUserPath(D_DUMPTEXTURES_IDX), stats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), texmap, mip);
}
}
}
void DumpEfb(const char* filename)
{
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);
// rgba to bgra
*(writePtr++) = sample[2];
*(writePtr++) = sample[1];
*(writePtr++) = sample[0];
*(writePtr++) = sample[3];
}
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
delete []data;
}
void DumpDepth(const char* filename)
{
u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
u8 *writePtr = data;
for (int y = 0; y < EFB_HEIGHT; y++)
for (int x = 0; x < EFB_WIDTH; x++) {
u32 depth = EfbInterface::GetDepth(x, y);
// depth to bgra
*(writePtr++) = (depth >> 16) & 0xff;
*(writePtr++) = (depth >> 8) & 0xff;
*(writePtr++) = depth & 0xff;
*(writePtr++) = 255;
}
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
delete []data;
}
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int buffer, const char *name)
{
u32 offset = (x + y * EFB_WIDTH) * 4;
u8 *dst = &ObjectBuffer[buffer][offset];
*(dst++) = color[2];
*(dst++) = color[1];
*(dst++) = color[0];
*(dst++) = color[3];
DrawnToBuffer[buffer] = true;
ObjectBufferName[buffer] = name;
}
void OnObjectBegin()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_Config.drawStart && stats.thisFrame.numDrawnObjects < g_Config.drawEnd)
DumpActiveTextures();
if (g_Config.bHwRasterizer)
HwRasterizer::BeginTriangles();
}
}
void OnObjectEnd()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_Config.drawStart && stats.thisFrame.numDrawnObjects < g_Config.drawEnd)
DumpEfb(StringFromFormat("%sobject%i.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.thisFrame.numDrawnObjects).c_str());
if (g_Config.bHwRasterizer)
HwRasterizer::EndTriangles();
for (int i = 0; i < NumObjectBuffers; i++)
{
if (DrawnToBuffer[i])
{
DrawnToBuffer[i] = false;
(void)SaveTGA(StringFromFormat("%sobject%i_%s(%i).tga", File::GetUserPath(D_DUMPFRAMES_IDX),
stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i).c_str(), EFB_WIDTH, EFB_HEIGHT, ObjectBuffer[i]);
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
}
}
stats.thisFrame.numDrawnObjects++;
}
}
void OnFrameEnd()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpFrames)
{
DumpEfb(StringFromFormat("%sframe%i_color.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.frameCount).c_str());
DumpDepth(StringFromFormat("%sframe%i_depth.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.frameCount).c_str());
}
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "main.h"
#include "DebugUtil.h"
#include "BPMemLoader.h"
#include "TextureSampler.h"
#include "VideoConfig.h"
#include "EfbInterface.h"
#include "Statistics.h"
#include "HwRasterizer.h"
#include "StringUtil.h"
#include "CommandProcessor.h"
#include "../../../Core/VideoCommon/Src/ImageWrite.h"
#include "FileUtil.h"
namespace DebugUtil
{
u32 skipFrames = 0;
const int NumObjectBuffers = 32;
u8 ObjectBuffer[NumObjectBuffers][EFB_WIDTH*EFB_HEIGHT*4];
bool DrawnToBuffer[NumObjectBuffers];
const char* ObjectBufferName[NumObjectBuffers];
void Init()
{
for (int i = 0; i < NumObjectBuffers; i++)
{
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
DrawnToBuffer[i] = false;
ObjectBufferName[i] = 0;
}
}
void SaveTexture(const char* filename, u32 texmap, s32 mip)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
u8 subTexmap = texmap & 3;
TexImage0& ti0 = texUnit.texImage0[subTexmap];
int width = ti0.width + 1;
int height = ti0.height + 1;
u8 *data = new u8[width * height * 4];
GetTextureBGRA(data, texmap, mip, width, height);
(void)SaveTGA(filename, width, height, data);
delete []data;
}
void GetTextureBGRA(u8 *dst, u32 texmap, s32 mip, int width, int height)
{
u8 sample[4];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++) {
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, sample);
// rgba to bgra
*(dst++) = sample[2];
*(dst++) = sample[1];
*(dst++) = sample[0];
*(dst++) = sample[3];
}
}
s32 GetMaxTextureLod(u32 texmap)
{
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;
if(fract)
++mip;
return (s32)mip;
}
void DumpActiveTextures()
{
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.tga", File::GetUserPath(D_DUMPTEXTURES_IDX), stats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), 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];
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.tga", File::GetUserPath(D_DUMPTEXTURES_IDX), stats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), texmap, mip);
}
}
}
void DumpEfb(const char* filename)
{
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);
// rgba to bgra
*(writePtr++) = sample[2];
*(writePtr++) = sample[1];
*(writePtr++) = sample[0];
*(writePtr++) = sample[3];
}
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
delete []data;
}
void DumpDepth(const char* filename)
{
u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
u8 *writePtr = data;
for (int y = 0; y < EFB_HEIGHT; y++)
for (int x = 0; x < EFB_WIDTH; x++) {
u32 depth = EfbInterface::GetDepth(x, y);
// depth to bgra
*(writePtr++) = (depth >> 16) & 0xff;
*(writePtr++) = (depth >> 8) & 0xff;
*(writePtr++) = depth & 0xff;
*(writePtr++) = 255;
}
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
delete []data;
}
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int buffer, const char *name)
{
u32 offset = (x + y * EFB_WIDTH) * 4;
u8 *dst = &ObjectBuffer[buffer][offset];
*(dst++) = color[2];
*(dst++) = color[1];
*(dst++) = color[0];
*(dst++) = color[3];
DrawnToBuffer[buffer] = true;
ObjectBufferName[buffer] = name;
}
void OnObjectBegin()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_Config.drawStart && stats.thisFrame.numDrawnObjects < g_Config.drawEnd)
DumpActiveTextures();
if (g_Config.bHwRasterizer)
HwRasterizer::BeginTriangles();
}
}
void OnObjectEnd()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_Config.drawStart && stats.thisFrame.numDrawnObjects < g_Config.drawEnd)
DumpEfb(StringFromFormat("%sobject%i.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.thisFrame.numDrawnObjects).c_str());
if (g_Config.bHwRasterizer)
HwRasterizer::EndTriangles();
for (int i = 0; i < NumObjectBuffers; i++)
{
if (DrawnToBuffer[i])
{
DrawnToBuffer[i] = false;
(void)SaveTGA(StringFromFormat("%sobject%i_%s(%i).tga", File::GetUserPath(D_DUMPFRAMES_IDX),
stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i).c_str(), EFB_WIDTH, EFB_HEIGHT, ObjectBuffer[i]);
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
}
}
stats.thisFrame.numDrawnObjects++;
}
}
void OnFrameEnd()
{
if (!g_bSkipCurrentFrame)
{
if (g_Config.bDumpFrames)
{
DumpEfb(StringFromFormat("%sframe%i_color.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.frameCount).c_str());
DumpDepth(StringFromFormat("%sframe%i_depth.tga", File::GetUserPath(D_DUMPFRAMES_IDX), stats.frameCount).c_str());
}
}
}
}

View File

@ -1,108 +1,108 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "EfbInterface.h"
#include "Renderer.h"
#include "TextureEncoder.h"
#include "Statistics.h"
#include "VideoConfig.h"
#include "DebugUtil.h"
#include "HwRasterizer.h"
#include "CommandProcessor.h"
namespace EfbCopy
{
void CopyToXfb()
{
if (!g_Config.bHwRasterizer)
{
// copy to open gl for rendering
EfbInterface::UpdateColorTexture();
Renderer::DrawTexture(EfbInterface::efbColorTexture, EFB_WIDTH, EFB_HEIGHT);
}
Renderer::SwapBuffer();
}
void CopyToRam()
{
u8 *dest_ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.copyTexDest << 5);
TextureEncoder::Encode(dest_ptr);
}
void ClearEfb()
{
u32 clearColor = (bpmem.clearcolorAR & 0xff) | Common::swap16(bpmem.clearcolorGB) << 8 | (bpmem.clearcolorAR & 0xff00) << 16;
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()
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
DebugUtil::OnFrameEnd();
if (!g_bSkipCurrentFrame)
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
{
CopyToXfb();
g_VideoInitialize.pCopiedToXFB(false);
stats.frameCount++;
}
else
{
CopyToRam();
}
if (bpmem.triggerEFBCopy.clear)
{
if (g_Config.bHwRasterizer)
HwRasterizer::Clear();
else
ClearEfb();
}
}
else
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
{
// no frame rendered but tell that a frame has finished for frame skip counter
g_VideoInitialize.pCopiedToXFB(false);
}
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "EfbInterface.h"
#include "Renderer.h"
#include "TextureEncoder.h"
#include "Statistics.h"
#include "VideoConfig.h"
#include "DebugUtil.h"
#include "HwRasterizer.h"
#include "CommandProcessor.h"
namespace EfbCopy
{
void CopyToXfb()
{
if (!g_Config.bHwRasterizer)
{
// copy to open gl for rendering
EfbInterface::UpdateColorTexture();
Renderer::DrawTexture(EfbInterface::efbColorTexture, EFB_WIDTH, EFB_HEIGHT);
}
Renderer::SwapBuffer();
}
void CopyToRam()
{
u8 *dest_ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.copyTexDest << 5);
TextureEncoder::Encode(dest_ptr);
}
void ClearEfb()
{
u32 clearColor = (bpmem.clearcolorAR & 0xff) | Common::swap16(bpmem.clearcolorGB) << 8 | (bpmem.clearcolorAR & 0xff00) << 16;
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()
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
DebugUtil::OnFrameEnd();
if (!g_bSkipCurrentFrame)
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
{
CopyToXfb();
g_VideoInitialize.pCopiedToXFB(false);
stats.frameCount++;
}
else
{
CopyToRam();
}
if (bpmem.triggerEFBCopy.clear)
{
if (g_Config.bHwRasterizer)
HwRasterizer::Clear();
else
ClearEfb();
}
}
else
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
{
// no frame rendered but tell that a frame has finished for frame skip counter
g_VideoInitialize.pCopiedToXFB(false);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +1,50 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EFB_INTERFACE_H_
#define _EFB_INTERFACE_H_
#include "VideoCommon.h"
namespace EfbInterface
{
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
// color order is RGBA
// 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);
// 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);
u32 GetDepth(u16 x, u16 y);
u8* GetPixelPointer(u16 x, u16 y, bool depth);
void UpdateColorTexture();
extern u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4]; // rgba format
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EFB_INTERFACE_H_
#define _EFB_INTERFACE_H_
#include "VideoCommon.h"
namespace EfbInterface
{
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
// color order is RGBA
// 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);
// 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);
u32 GetDepth(u16 x, u16 y);
u8* GetPixelPointer(u16 x, u16 y, bool depth);
void UpdateColorTexture();
extern u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4]; // rgba format
}
#endif

View File

@ -1,191 +1,191 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemoryUtil.h"
#include <VideoCommon.h>
#include "BPMemLoader.h"
#include "HwRasterizer.h"
#include "GLUtil.h"
#include "NativeVertexFormat.h"
#include "DebugUtil.h"
#define TEMP_SIZE (1024*1024*4)
namespace HwRasterizer
{
float efbHalfWidth;
float efbHalfHeight;
float texWidth;
float texHeight;
bool hasTexture;
u8 *temp;
void Init()
{
efbHalfWidth = EFB_WIDTH / 2.0f;
efbHalfHeight = 480 / 2.0f;
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
}
void LoadTexture()
{
FourTexUnits &texUnit = bpmem.tex[0];
u32 imageAddr = texUnit.texImage3[0].image_base;
TexCacheEntry &cacheEntry = textures[imageAddr];
cacheEntry.Update();
texWidth = (float)(bpmem.texcoords[0].s.scale_minus_1 + 1);
texHeight = (float)(bpmem.texcoords[0].t.scale_minus_1 + 1);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cacheEntry.texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
}
void BeginTriangles()
{
// disabling depth test sometimes allows more things to be visible
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
hasTexture = bpmem.tevorders[0].enable0;
if (hasTexture)
LoadTexture();
}
void EndTriangles()
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
}
void DrawColorVertex(OutputVertexData *v)
{
glColor3ub(v->color[0][0], v->color[0][1], v->color[0][2]);
glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z);
}
void DrawTextureVertex(OutputVertexData *v)
{
glTexCoord2f(v->texCoords[0].x * texWidth, v->texCoords[0].y * texHeight);
glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z);
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
glBegin(GL_TRIANGLES);
if (hasTexture)
{
DrawTextureVertex(v0);
DrawTextureVertex(v1);
DrawTextureVertex(v2);
}
else
{
DrawColorVertex(v0);
DrawColorVertex(v1);
DrawColorVertex(v2);
}
glEnd();
}
void Clear()
{
u8 r = (bpmem.clearcolorAR & 0x00ff);
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
u8 b = (bpmem.clearcolorGB & 0x00ff);
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
glBegin(GL_QUADS);
glColor4ub(r, g, b, a);
glVertex3f(left, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, bottom, depth);
glColor4ub(r, g, b, a);
glVertex3f(left, bottom, depth);
glEnd();
}
TexCacheEntry::TexCacheEntry()
{
Create();
}
void TexCacheEntry::Create()
{
FourTexUnits &texUnit = bpmem.tex[0];
texImage0.hex = texUnit.texImage0[0].hex;
texImage1.hex = texUnit.texImage1[0].hex;
texImage2.hex = texUnit.texImage2[0].hex;
texImage3.hex = texUnit.texImage3[0].hex;
texTlut.hex = texUnit.texTlut[0].hex;
int width = texImage0.width;
int height = texImage0.height;
DebugUtil::GetTextureBGRA(temp, 0, 0, width, height);
glGenTextures(1, (GLuint *)&texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
}
void TexCacheEntry::Destroy()
{
if (texture == 0)
return;
glDeleteTextures(1, &texture);
texture = 0;
}
void TexCacheEntry::Update()
{
FourTexUnits &texUnit = bpmem.tex[0];
// extra checks cause textures to be reloaded much more
if (texUnit.texImage0[0].hex != texImage0.hex ||
//texUnit.texImage1[0].hex != texImage1.hex ||
//texUnit.texImage2[0].hex != texImage2.hex ||
texUnit.texImage3[0].hex != texImage3.hex ||
texUnit.texTlut[0].hex != texTlut.hex)
{
Destroy();
Create();
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemoryUtil.h"
#include <VideoCommon.h>
#include "BPMemLoader.h"
#include "HwRasterizer.h"
#include "GLUtil.h"
#include "NativeVertexFormat.h"
#include "DebugUtil.h"
#define TEMP_SIZE (1024*1024*4)
namespace HwRasterizer
{
float efbHalfWidth;
float efbHalfHeight;
float texWidth;
float texHeight;
bool hasTexture;
u8 *temp;
void Init()
{
efbHalfWidth = EFB_WIDTH / 2.0f;
efbHalfHeight = 480 / 2.0f;
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
}
void LoadTexture()
{
FourTexUnits &texUnit = bpmem.tex[0];
u32 imageAddr = texUnit.texImage3[0].image_base;
TexCacheEntry &cacheEntry = textures[imageAddr];
cacheEntry.Update();
texWidth = (float)(bpmem.texcoords[0].s.scale_minus_1 + 1);
texHeight = (float)(bpmem.texcoords[0].t.scale_minus_1 + 1);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cacheEntry.texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
}
void BeginTriangles()
{
// disabling depth test sometimes allows more things to be visible
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
hasTexture = bpmem.tevorders[0].enable0;
if (hasTexture)
LoadTexture();
}
void EndTriangles()
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
}
void DrawColorVertex(OutputVertexData *v)
{
glColor3ub(v->color[0][0], v->color[0][1], v->color[0][2]);
glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z);
}
void DrawTextureVertex(OutputVertexData *v)
{
glTexCoord2f(v->texCoords[0].x * texWidth, v->texCoords[0].y * texHeight);
glVertex3f(v->screenPosition.x / efbHalfWidth - 1.0f, 1.0f - v->screenPosition.y / efbHalfHeight, v->screenPosition.z);
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
glBegin(GL_TRIANGLES);
if (hasTexture)
{
DrawTextureVertex(v0);
DrawTextureVertex(v1);
DrawTextureVertex(v2);
}
else
{
DrawColorVertex(v0);
DrawColorVertex(v1);
DrawColorVertex(v2);
}
glEnd();
}
void Clear()
{
u8 r = (bpmem.clearcolorAR & 0x00ff);
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
u8 b = (bpmem.clearcolorGB & 0x00ff);
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
glBegin(GL_QUADS);
glColor4ub(r, g, b, a);
glVertex3f(left, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, bottom, depth);
glColor4ub(r, g, b, a);
glVertex3f(left, bottom, depth);
glEnd();
}
TexCacheEntry::TexCacheEntry()
{
Create();
}
void TexCacheEntry::Create()
{
FourTexUnits &texUnit = bpmem.tex[0];
texImage0.hex = texUnit.texImage0[0].hex;
texImage1.hex = texUnit.texImage1[0].hex;
texImage2.hex = texUnit.texImage2[0].hex;
texImage3.hex = texUnit.texImage3[0].hex;
texTlut.hex = texUnit.texTlut[0].hex;
int width = texImage0.width;
int height = texImage0.height;
DebugUtil::GetTextureBGRA(temp, 0, 0, width, height);
glGenTextures(1, (GLuint *)&texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
}
void TexCacheEntry::Destroy()
{
if (texture == 0)
return;
glDeleteTextures(1, &texture);
texture = 0;
}
void TexCacheEntry::Update()
{
FourTexUnits &texUnit = bpmem.tex[0];
// extra checks cause textures to be reloaded much more
if (texUnit.texImage0[0].hex != texImage0.hex ||
//texUnit.texImage1[0].hex != texImage1.hex ||
//texUnit.texImage2[0].hex != texImage2.hex ||
texUnit.texImage3[0].hex != texImage3.hex ||
texUnit.texTlut[0].hex != texTlut.hex)
{
Destroy();
Create();
}
}
}

View File

@ -1,60 +1,60 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HW_RASTERIZER_H
#define _HW_RASTERIZER_H
#include <map>
#include "BPMemLoader.h"
#include "GLUtil.h"
struct OutputVertexData;
namespace HwRasterizer
{
void Init();
void BeginTriangles();
void EndTriangles();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void Clear();
struct TexCacheEntry
{
TexImage0 texImage0;
TexImage1 texImage1;
TexImage2 texImage2;
TexImage3 texImage3;
TexTLUT texTlut;
GLuint texture;
TexCacheEntry();
void Create();
void Destroy();
void Update();
};
typedef std::map<u32, TexCacheEntry> TextureCache;
static TextureCache textures;
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HW_RASTERIZER_H
#define _HW_RASTERIZER_H
#include <map>
#include "BPMemLoader.h"
#include "GLUtil.h"
struct OutputVertexData;
namespace HwRasterizer
{
void Init();
void BeginTriangles();
void EndTriangles();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void Clear();
struct TexCacheEntry
{
TexImage0 texImage0;
TexImage1 texImage1;
TexImage2 texImage2;
TexImage3 texImage3;
TexTLUT texTlut;
GLuint texture;
TexCacheEntry();
void Create();
void Destroy();
void Update();
};
typedef std::map<u32, TexCacheEntry> TextureCache;
static TextureCache textures;
}
#endif

View File

@ -1,94 +1,94 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVEVERTEXFORMAT_H
#define _NATIVEVERTEXFORMAT_H
#include "../../Plugin_VideoDX9/Src/Vec3.h"
#ifdef WIN32
#define LOADERDECL __cdecl
#else
#define LOADERDECL
#endif
typedef void (LOADERDECL *TPipelineFunction)();
struct Vec4
{
float x;
float y;
float z;
float w;
};
struct InputVertexData
{
u8 posMtx;
u8 texMtx[8];
Vec3 position;
Vec3 normal[3];
u8 color[2][4];
float texCoords[8][2];
};
struct OutputVertexData
{
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)
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
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);
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]);
}
for (int i = 0; i < 8; ++i)
{
texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]);
}
#undef LINTERP
#undef LINTERP_INT
}
};
#endif
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVEVERTEXFORMAT_H
#define _NATIVEVERTEXFORMAT_H
#include "../../Plugin_VideoDX9/Src/Vec3.h"
#ifdef WIN32
#define LOADERDECL __cdecl
#else
#define LOADERDECL
#endif
typedef void (LOADERDECL *TPipelineFunction)();
struct Vec4
{
float x;
float y;
float z;
float w;
};
struct InputVertexData
{
u8 posMtx;
u8 texMtx[8];
Vec3 position;
Vec3 normal[3];
u8 color[2][4];
float texCoords[8][2];
};
struct OutputVertexData
{
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)
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
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);
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]);
}
for (int i = 0; i < 8; ++i)
{
texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]);
}
#undef LINTERP
#undef LINTERP_INT
}
};
#endif

View File

@ -1,30 +1,30 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVE_VERTEX_WRITER
#define _NATIVE_VERTEX_WRITER
// TODO: rename
namespace VertexManager
{
// TODO: move, rename.
extern u8* s_pCurBufferPointer;
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVE_VERTEX_WRITER
#define _NATIVE_VERTEX_WRITER
// TODO: rename
namespace VertexManager
{
// TODO: move, rename.
extern u8* s_pCurBufferPointer;
}
#endif

View File

@ -1,297 +1,297 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
#include "main.h"
#include "OpcodeDecoder.h"
#include "BPMemLoader.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "VertexLoader.h"
#include "Statistics.h"
#include "DebugUtil.h"
#include "CommandProcessor.h"
typedef void (*DecodingFunction)(u32);
DecodingFunction currentFunction = NULL;
u32 minCommandSize;
u16 streamSize;
u16 streamAddress;
bool readOpcode;
VertexLoader vertexLoader;
bool inObjectStream;
u8 lastPrimCmd;
namespace OpcodeDecoder
{
void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
if(g_bSkipCurrentFrame)
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
g_pVideoData += vertexSize;
iBufferSize -= vertexSize;
streamSize--;
}
}
else
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
vertexLoader.LoadVertex();
iBufferSize -= vertexSize;
streamSize--;
}
}
if (streamSize == 0)
{
// return to normal command processing
ResetDecoding();
}
}
void ReadXFData(u32 iBufferSize)
{
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
u32 pData[16];
for (int i = 0; i < streamSize; i++)
pData[i] = DataReadU32();
LoadXFReg(streamSize, streamAddress, pData);
// return to normal command processing
ResetDecoding();
}
void ExecuteDisplayList(u32 addr, u32 count)
{
u8 *videoDataSave = g_pVideoData;
u8 *dlStart = g_VideoInitialize.pGetMemoryPointer(addr);
g_pVideoData = dlStart;
while (OpcodeDecoder::CommandRunnable(count))
{
OpcodeDecoder::Run(count);
// if data was read by the opcode decoder then the video data pointer changed
u32 readCount = g_pVideoData - dlStart;
dlStart = g_pVideoData;
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
count -= readCount;
}
g_pVideoData = videoDataSave;
}
void DecodeStandard(u32 bufferSize)
{
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
int Cmd = DataReadU8();
if (Cmd == GX_NOP)
return;
// check if switching in or out of an object
// only used for debuggging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
{
inObjectStream = false;
DebugUtil::OnObjectEnd();
}
if (Cmd & 0x80 && !inObjectStream)
{
inObjectStream = true;
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
switch(Cmd)
{
case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
{
u32 SubCmd = DataReadU8();
u32 Value = DataReadU32();
LoadCPReg(SubCmd, Value);
}
break;
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataReadU32();
streamSize = ((Cmd2 >> 16) & 15) + 1;
streamAddress = Cmd2 & 0xFFFF;
currentFunction = ReadXFData;
minCommandSize = streamSize * 4;
readOpcode = false;
}
break;
case GX_LOAD_INDX_A: //used for position matrices
LoadIndexedXF(DataReadU32(), 0xC);
break;
case GX_LOAD_INDX_B: //used for normal matrices
LoadIndexedXF(DataReadU32(), 0xD);
break;
case GX_LOAD_INDX_C: //used for postmatrices
LoadIndexedXF(DataReadU32(), 0xE);
break;
case GX_LOAD_INDX_D: //used for lights
LoadIndexedXF(DataReadU32(), 0xF);
break;
case GX_CMD_CALL_DL:
{
u32 dwAddr = DataReadU32();
u32 dwCount = DataReadU32();
ExecuteDisplayList(dwAddr, dwCount);
}
break;
case 0x44:
// zelda 4 swords calls it and checks the metrics registers after that
break;
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
break;
case GX_LOAD_BP_REG: //0x61
{
u32 cmd = DataReadU32();
LoadBPReg(cmd);
}
break;
// draw primitives
default:
if (Cmd & 0x80)
{
u8 vatIndex = Cmd & GX_VAT_MASK;
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
vertexLoader.SetFormat(vatIndex, primitiveType);
// switch to primitive processing
streamSize = DataReadU16();
currentFunction = DecodePrimitiveStream;
minCommandSize = vertexLoader.GetVertexSize();
readOpcode = false;
INCSTAT(stats.thisFrame.numPrimatives);
DEBUG_LOG(VIDEO, "Draw begin");
}
else
{
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
break;
}
break;
}
}
void Init()
{
inObjectStream = false;
lastPrimCmd = 0;
ResetDecoding();
}
void ResetDecoding()
{
currentFunction = DecodeStandard;
minCommandSize = 1;
readOpcode = true;
}
bool CommandRunnable(u32 iBufferSize)
{
if (iBufferSize < minCommandSize)
return false;
if (readOpcode)
{
u8 Cmd = DataPeek8(0);
u32 minSize = 1;
switch(Cmd)
{
case GX_LOAD_CP_REG: //0x08
minSize = 6;
break;
case GX_LOAD_XF_REG:
minSize = 5;
break;
case GX_LOAD_INDX_A: //used for position matrices
minSize = 5;
break;
case GX_LOAD_INDX_B: //used for normal matrices
minSize = 5;
break;
case GX_LOAD_INDX_C: //used for postmatrices
minSize = 5;
break;
case GX_LOAD_INDX_D: //used for lights
minSize = 5;
break;
case GX_CMD_CALL_DL:
minSize = 9;
break;
case GX_LOAD_BP_REG: //0x61
minSize = 5;
break;
// draw primitives
default:
if (Cmd & 0x80)
minSize = 3;
break;
}
return (iBufferSize >= minSize);
}
return true;
}
void Run(u32 iBufferSize)
{
currentFunction(iBufferSize);
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
#include "main.h"
#include "OpcodeDecoder.h"
#include "BPMemLoader.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "VertexLoader.h"
#include "Statistics.h"
#include "DebugUtil.h"
#include "CommandProcessor.h"
typedef void (*DecodingFunction)(u32);
DecodingFunction currentFunction = NULL;
u32 minCommandSize;
u16 streamSize;
u16 streamAddress;
bool readOpcode;
VertexLoader vertexLoader;
bool inObjectStream;
u8 lastPrimCmd;
namespace OpcodeDecoder
{
void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
if(g_bSkipCurrentFrame)
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
g_pVideoData += vertexSize;
iBufferSize -= vertexSize;
streamSize--;
}
}
else
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
vertexLoader.LoadVertex();
iBufferSize -= vertexSize;
streamSize--;
}
}
if (streamSize == 0)
{
// return to normal command processing
ResetDecoding();
}
}
void ReadXFData(u32 iBufferSize)
{
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
u32 pData[16];
for (int i = 0; i < streamSize; i++)
pData[i] = DataReadU32();
LoadXFReg(streamSize, streamAddress, pData);
// return to normal command processing
ResetDecoding();
}
void ExecuteDisplayList(u32 addr, u32 count)
{
u8 *videoDataSave = g_pVideoData;
u8 *dlStart = g_VideoInitialize.pGetMemoryPointer(addr);
g_pVideoData = dlStart;
while (OpcodeDecoder::CommandRunnable(count))
{
OpcodeDecoder::Run(count);
// if data was read by the opcode decoder then the video data pointer changed
u32 readCount = g_pVideoData - dlStart;
dlStart = g_pVideoData;
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
count -= readCount;
}
g_pVideoData = videoDataSave;
}
void DecodeStandard(u32 bufferSize)
{
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
int Cmd = DataReadU8();
if (Cmd == GX_NOP)
return;
// check if switching in or out of an object
// only used for debuggging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
{
inObjectStream = false;
DebugUtil::OnObjectEnd();
}
if (Cmd & 0x80 && !inObjectStream)
{
inObjectStream = true;
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
switch(Cmd)
{
case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
{
u32 SubCmd = DataReadU8();
u32 Value = DataReadU32();
LoadCPReg(SubCmd, Value);
}
break;
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataReadU32();
streamSize = ((Cmd2 >> 16) & 15) + 1;
streamAddress = Cmd2 & 0xFFFF;
currentFunction = ReadXFData;
minCommandSize = streamSize * 4;
readOpcode = false;
}
break;
case GX_LOAD_INDX_A: //used for position matrices
LoadIndexedXF(DataReadU32(), 0xC);
break;
case GX_LOAD_INDX_B: //used for normal matrices
LoadIndexedXF(DataReadU32(), 0xD);
break;
case GX_LOAD_INDX_C: //used for postmatrices
LoadIndexedXF(DataReadU32(), 0xE);
break;
case GX_LOAD_INDX_D: //used for lights
LoadIndexedXF(DataReadU32(), 0xF);
break;
case GX_CMD_CALL_DL:
{
u32 dwAddr = DataReadU32();
u32 dwCount = DataReadU32();
ExecuteDisplayList(dwAddr, dwCount);
}
break;
case 0x44:
// zelda 4 swords calls it and checks the metrics registers after that
break;
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
break;
case GX_LOAD_BP_REG: //0x61
{
u32 cmd = DataReadU32();
LoadBPReg(cmd);
}
break;
// draw primitives
default:
if (Cmd & 0x80)
{
u8 vatIndex = Cmd & GX_VAT_MASK;
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
vertexLoader.SetFormat(vatIndex, primitiveType);
// switch to primitive processing
streamSize = DataReadU16();
currentFunction = DecodePrimitiveStream;
minCommandSize = vertexLoader.GetVertexSize();
readOpcode = false;
INCSTAT(stats.thisFrame.numPrimatives);
DEBUG_LOG(VIDEO, "Draw begin");
}
else
{
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
break;
}
break;
}
}
void Init()
{
inObjectStream = false;
lastPrimCmd = 0;
ResetDecoding();
}
void ResetDecoding()
{
currentFunction = DecodeStandard;
minCommandSize = 1;
readOpcode = true;
}
bool CommandRunnable(u32 iBufferSize)
{
if (iBufferSize < minCommandSize)
return false;
if (readOpcode)
{
u8 Cmd = DataPeek8(0);
u32 minSize = 1;
switch(Cmd)
{
case GX_LOAD_CP_REG: //0x08
minSize = 6;
break;
case GX_LOAD_XF_REG:
minSize = 5;
break;
case GX_LOAD_INDX_A: //used for position matrices
minSize = 5;
break;
case GX_LOAD_INDX_B: //used for normal matrices
minSize = 5;
break;
case GX_LOAD_INDX_C: //used for postmatrices
minSize = 5;
break;
case GX_LOAD_INDX_D: //used for lights
minSize = 5;
break;
case GX_CMD_CALL_DL:
minSize = 9;
break;
case GX_LOAD_BP_REG: //0x61
minSize = 5;
break;
// draw primitives
default:
if (Cmd & 0x80)
minSize = 3;
break;
}
return (iBufferSize >= minSize);
}
return true;
}
void Run(u32 iBufferSize)
{
currentFunction(iBufferSize);
}
}

View File

@ -1,62 +1,62 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _OPCODEDECODER_H_
#define _OPCODEDECODER_H_
#include "pluginspecs_video.h"
namespace OpcodeDecoder
{
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x78
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
//these are defined 1/8th of their real values and without their top bit
#define GX_DRAW_QUADS 0x0 //0x80
#define GX_DRAW_TRIANGLES 0x2 //0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
#define GX_DRAW_LINES 0x5 //0xA8
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
#define GX_DRAW_POINTS 0x7 //0xB8
void Init();
void ResetDecoding();
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _OPCODEDECODER_H_
#define _OPCODEDECODER_H_
#include "pluginspecs_video.h"
namespace OpcodeDecoder
{
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x78
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
//these are defined 1/8th of their real values and without their top bit
#define GX_DRAW_QUADS 0x0 //0x80
#define GX_DRAW_TRIANGLES 0x2 //0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
#define GX_DRAW_LINES 0x5 //0xA8
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
#define GX_DRAW_POINTS 0x7 //0xB8
void Init();
void ResetDecoding();
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
}
#endif

View File

@ -1,171 +1,171 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// http://developer.nvidia.com/object/General_FAQ.html#t6 !!!!!
#include "Common.h"
#include "ChunkFile.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
namespace PixelEngine
{
enum
{
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
INT_CAUSE_PE_FINISH = 0x400, // GP Finished
};
// STATE_TO_SAVE
PEReg pereg;
static bool g_bSignalTokenInterrupt;
static bool g_bSignalFinishInterrupt;
static int et_SetTokenOnMainThread;
static int et_SetFinishOnMainThread;
void DoState(PointerWrap &p)
{
p.Do(pereg);
p.Do(g_bSignalTokenInterrupt);
p.Do(g_bSignalFinishInterrupt);
}
void UpdateInterrupts();
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
void Init()
{
memset(&pereg, 0, sizeof(pereg));
et_SetTokenOnMainThread = false;
g_bSignalFinishInterrupt = false;
et_SetTokenOnMainThread = g_VideoInitialize.pRegisterEvent("SetToken", SetToken_OnMainThread);
et_SetFinishOnMainThread = g_VideoInitialize.pRegisterEvent("SetFinish", SetFinish_OnMainThread);
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
DEBUG_LOG(PIXELENGINE, "(r16): 0x%08x", _iAddress);
u16 address = _iAddress & 0xFFF;
if (address <= 0x16)
_uReturnValue = ((u16*)&pereg)[address >> 1];
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
WARN_LOG(PIXELENGINE, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
u16 address = _iAddress & 0xFFF;
switch (address)
{
case PE_CTRL_REGISTER:
{
UPECtrlReg tmpCtrl(_iValue);
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
pereg.ctrl.PETokenEnable = tmpCtrl.PETokenEnable;
pereg.ctrl.PEFinishEnable = tmpCtrl.PEFinishEnable;
pereg.ctrl.PEToken = 0; // this flag is write only
pereg.ctrl.PEFinish = 0; // this flag is write only
DEBUG_LOG(PIXELENGINE, "(w16): PE_CTRL_REGISTER: 0x%04x", _iValue);
UpdateInterrupts();
}
break;
default:
if (address <= 0x16)
((u16*)&pereg)[address >> 1] = _iValue;
break;
}
}
bool AllowIdleSkipping()
{
return !g_VideoInitialize.bOnThread || (!pereg.ctrl.PETokenEnable && !pereg.ctrl.PEFinishEnable);
}
void UpdateInterrupts()
{
// check if there is a token-interrupt
if (g_bSignalTokenInterrupt & pereg.ctrl.PETokenEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, false);
// check if there is a finish-interrupt
if (g_bSignalFinishInterrupt & pereg.ctrl.PEFinishEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, false);
}
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalTokenInterrupt = true;
INFO_LOG(PIXELENGINE, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", pereg.token);
UpdateInterrupts();
}
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalFinishInterrupt = true;
UpdateInterrupts();
}
// SetToken
// THIS IS EXECUTED FROM VIDEO THREAD
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
{
pereg.token = _token;
if (_bSetTokenAcknowledge) // set token INT
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
}
}
// SetFinish
// THIS IS EXECUTED FROM VIDEO THREAD
void SetFinish()
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetFinishOnMainThread, 0);
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
}
} // end of namespace PixelEngine
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// http://developer.nvidia.com/object/General_FAQ.html#t6 !!!!!
#include "Common.h"
#include "ChunkFile.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
namespace PixelEngine
{
enum
{
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
INT_CAUSE_PE_FINISH = 0x400, // GP Finished
};
// STATE_TO_SAVE
PEReg pereg;
static bool g_bSignalTokenInterrupt;
static bool g_bSignalFinishInterrupt;
static int et_SetTokenOnMainThread;
static int et_SetFinishOnMainThread;
void DoState(PointerWrap &p)
{
p.Do(pereg);
p.Do(g_bSignalTokenInterrupt);
p.Do(g_bSignalFinishInterrupt);
}
void UpdateInterrupts();
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
void Init()
{
memset(&pereg, 0, sizeof(pereg));
et_SetTokenOnMainThread = false;
g_bSignalFinishInterrupt = false;
et_SetTokenOnMainThread = g_VideoInitialize.pRegisterEvent("SetToken", SetToken_OnMainThread);
et_SetFinishOnMainThread = g_VideoInitialize.pRegisterEvent("SetFinish", SetFinish_OnMainThread);
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
DEBUG_LOG(PIXELENGINE, "(r16): 0x%08x", _iAddress);
u16 address = _iAddress & 0xFFF;
if (address <= 0x16)
_uReturnValue = ((u16*)&pereg)[address >> 1];
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
WARN_LOG(PIXELENGINE, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
u16 address = _iAddress & 0xFFF;
switch (address)
{
case PE_CTRL_REGISTER:
{
UPECtrlReg tmpCtrl(_iValue);
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
pereg.ctrl.PETokenEnable = tmpCtrl.PETokenEnable;
pereg.ctrl.PEFinishEnable = tmpCtrl.PEFinishEnable;
pereg.ctrl.PEToken = 0; // this flag is write only
pereg.ctrl.PEFinish = 0; // this flag is write only
DEBUG_LOG(PIXELENGINE, "(w16): PE_CTRL_REGISTER: 0x%04x", _iValue);
UpdateInterrupts();
}
break;
default:
if (address <= 0x16)
((u16*)&pereg)[address >> 1] = _iValue;
break;
}
}
bool AllowIdleSkipping()
{
return !g_VideoInitialize.bOnThread || (!pereg.ctrl.PETokenEnable && !pereg.ctrl.PEFinishEnable);
}
void UpdateInterrupts()
{
// check if there is a token-interrupt
if (g_bSignalTokenInterrupt & pereg.ctrl.PETokenEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, false);
// check if there is a finish-interrupt
if (g_bSignalFinishInterrupt & pereg.ctrl.PEFinishEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, false);
}
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalTokenInterrupt = true;
INFO_LOG(PIXELENGINE, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", pereg.token);
UpdateInterrupts();
}
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalFinishInterrupt = true;
UpdateInterrupts();
}
// SetToken
// THIS IS EXECUTED FROM VIDEO THREAD
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
{
pereg.token = _token;
if (_bSetTokenAcknowledge) // set token INT
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
}
}
// SetFinish
// THIS IS EXECUTED FROM VIDEO THREAD
void SetFinish()
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetFinishOnMainThread, 0);
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
}
} // end of namespace PixelEngine

View File

@ -1,155 +1,155 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELENGINE_H
#define _PIXELENGINE_H
#include "Common.h"
#include "pluginspecs_video.h"
#include "VideoCommon.h"
class PointerWrap;
namespace PixelEngine
{
// internal hardware addresses
enum
{
PE_ZCONF = 0x000, // Z Config
PE_ALPHACONF = 0x002, // Alpha Config
PE_DSTALPHACONF = 0x004, // Destination Alpha Config
PE_ALPHAMODE = 0x006, // Alpha Mode Config
PE_ALPHAREAD = 0x008, // Alpha Read
PE_CTRL_REGISTER = 0x00a, // Control
PE_TOKEN_REG = 0x00e, // Token
PE_BBOX_LEFT = 0x010, // Flip Left
PE_BBOX_RIGHT = 0x012, // Flip Right
PE_BBOX_TOP = 0x014, // Flip Top
PE_BBOX_BOTTOM = 0x016, // Flip Bottom
};
union UPEZConfReg
{
u16 Hex;
struct
{
u16 ZCompEnable : 1; // Z Comparator Enable
u16 Function : 3;
u16 ZUpdEnable : 1;
u16 : 11;
};
};
union UPEAlphaConfReg
{
u16 Hex;
struct
{
u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT
u16 BMLogic : 1; // GX_BM_LOGIC
u16 Dither : 1;
u16 ColorUpdEnable : 1;
u16 AlphaUpdEnable : 1;
u16 DstFactor : 3;
u16 SrcFactor : 3;
u16 Substract : 1; // Additive mode by default
u16 BlendOperator : 4;
};
};
union UPEDstAlphaConfReg
{
u16 Hex;
struct
{
u16 DstAlpha : 8;
u16 Enable : 1;
u16 : 7;
};
};
union UPEAlphaModeConfReg
{
u16 Hex;
struct
{
u16 Threshold : 8;
u16 CompareMode : 8;
};
};
union UPEAlphaReadReg
{
u16 Hex;
struct
{
u16 ReadMode : 3;
u16 : 13;
};
};
union UPECtrlReg
{
struct
{
u16 PETokenEnable : 1;
u16 PEFinishEnable : 1;
u16 PEToken : 1; // write only
u16 PEFinish : 1; // write only
u16 : 12;
};
u16 Hex;
UPECtrlReg() {Hex = 0; }
UPECtrlReg(u16 _hex) {Hex = _hex; }
};
struct PEReg
{
UPEZConfReg zconf;
UPEAlphaConfReg alphaConf;
UPEDstAlphaConfReg dstAlpha;
UPEAlphaModeConfReg alphaMode;
UPEAlphaReadReg alphaRead;
UPECtrlReg ctrl;
u16 unk0;
u16 token;
u16 boxLeft;
u16 boxRight;
u16 boxTop;
u16 boxBottom;
};
extern PEReg pereg;
void Init();
void DoState(PointerWrap &p);
// Read
void Read16(u16& _uReturnValue, const u32 _iAddress);
// Write
void Write16(const u16 _iValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
// gfx plugin support
void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
bool AllowIdleSkipping();
} // end of namespace PixelEngine
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELENGINE_H
#define _PIXELENGINE_H
#include "Common.h"
#include "pluginspecs_video.h"
#include "VideoCommon.h"
class PointerWrap;
namespace PixelEngine
{
// internal hardware addresses
enum
{
PE_ZCONF = 0x000, // Z Config
PE_ALPHACONF = 0x002, // Alpha Config
PE_DSTALPHACONF = 0x004, // Destination Alpha Config
PE_ALPHAMODE = 0x006, // Alpha Mode Config
PE_ALPHAREAD = 0x008, // Alpha Read
PE_CTRL_REGISTER = 0x00a, // Control
PE_TOKEN_REG = 0x00e, // Token
PE_BBOX_LEFT = 0x010, // Flip Left
PE_BBOX_RIGHT = 0x012, // Flip Right
PE_BBOX_TOP = 0x014, // Flip Top
PE_BBOX_BOTTOM = 0x016, // Flip Bottom
};
union UPEZConfReg
{
u16 Hex;
struct
{
u16 ZCompEnable : 1; // Z Comparator Enable
u16 Function : 3;
u16 ZUpdEnable : 1;
u16 : 11;
};
};
union UPEAlphaConfReg
{
u16 Hex;
struct
{
u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT
u16 BMLogic : 1; // GX_BM_LOGIC
u16 Dither : 1;
u16 ColorUpdEnable : 1;
u16 AlphaUpdEnable : 1;
u16 DstFactor : 3;
u16 SrcFactor : 3;
u16 Substract : 1; // Additive mode by default
u16 BlendOperator : 4;
};
};
union UPEDstAlphaConfReg
{
u16 Hex;
struct
{
u16 DstAlpha : 8;
u16 Enable : 1;
u16 : 7;
};
};
union UPEAlphaModeConfReg
{
u16 Hex;
struct
{
u16 Threshold : 8;
u16 CompareMode : 8;
};
};
union UPEAlphaReadReg
{
u16 Hex;
struct
{
u16 ReadMode : 3;
u16 : 13;
};
};
union UPECtrlReg
{
struct
{
u16 PETokenEnable : 1;
u16 PEFinishEnable : 1;
u16 PEToken : 1; // write only
u16 PEFinish : 1; // write only
u16 : 12;
};
u16 Hex;
UPECtrlReg() {Hex = 0; }
UPECtrlReg(u16 _hex) {Hex = _hex; }
};
struct PEReg
{
UPEZConfReg zconf;
UPEAlphaConfReg alphaConf;
UPEDstAlphaConfReg dstAlpha;
UPEAlphaModeConfReg alphaMode;
UPEAlphaReadReg alphaRead;
UPECtrlReg ctrl;
u16 unk0;
u16 token;
u16 boxLeft;
u16 boxRight;
u16 boxTop;
u16 boxBottom;
};
extern PEReg pereg;
void Init();
void DoState(PointerWrap &p);
// Read
void Read16(u16& _uReturnValue, const u32 _iAddress);
// Write
void Write16(const u16 _iValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
// gfx plugin support
void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
bool AllowIdleSkipping();
} // end of namespace PixelEngine
#endif

View File

@ -1,473 +1,473 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Rasterizer.h"
#include "HwRasterizer.h"
#include "EfbInterface.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Tev.h"
#include "Statistics.h"
#include "VideoConfig.h"
#define BLOCK_SIZE 2
#define CLAMP(x, a, b) (x>b)?b:(x<a)?a:x
// returns approximation of log2(f) in s28.4
// results are close enough to use for LOD
static inline s32 FixedLog2(float f)
{
u32 *x = (u32*)&f;
s32 logInt = ((*x & 0x7F800000) >> 19) - 2032; // integer part
s32 logFract = (*x & 0x007fffff) >> 19; // approximate fractional part
return logInt + logFract;
}
namespace Rasterizer
{
Slope ZSlope;
Slope WSlope;
Slope ColorSlopes[2][4];
Slope TexSlopes[8][3];
s32 vertex0X;
s32 vertex0Y;
float vertexOffsetX;
float vertexOffsetY;
s32 scissorLeft = 0;
s32 scissorTop = 0;
s32 scissorRight = 0;
s32 scissorBottom = 0;
Tev tev;
RasterBlock rasterBlock;
void Init()
{
tev.Init();
}
inline int iround(float x)
{
int t;
#if defined(_WIN32) && !defined(_M_X64)
__asm
{
fld x
fistp t
}
#else
t = (int)x;
if((x - t) >= 0.5)
return t + 1;
#endif
return t;
}
void SetScissor()
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
int yoff = bpmem.scissorOffset.y * 2 - 342;
scissorLeft = bpmem.scissorTL.x - xoff - 342;
if (scissorLeft < 0) scissorLeft = 0;
scissorTop = bpmem.scissorTL.y - yoff - 342;
if (scissorTop < 0) scissorTop = 0;
scissorRight = bpmem.scissorBR.x - xoff - 341;
if (scissorRight > EFB_WIDTH) scissorRight = EFB_WIDTH;
scissorBottom = bpmem.scissorBR.y - yoff - 341;
if (scissorBottom > EFB_HEIGHT) scissorBottom = EFB_HEIGHT;
}
void SetTevReg(int reg, int comp, bool konst, s16 color)
{
tev.SetRegColor(reg, comp, konst, color);
}
inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
{
INCSTAT(stats.thisFrame.rasterizedPixels);
float dx = vertexOffsetX + (float)(x - vertex0X);
float dy = vertexOffsetY + (float)(y - vertex0Y);
float zFloat = 1.0f + ZSlope.GetValue(dx, dy);
if (zFloat < 0.0f || zFloat > 1.0f)
return;
s32 z = (s32)(zFloat * 0x00ffffff);
if (bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
{
// early z
if (!EfbInterface::ZCompare(x, y, z))
return;
}
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
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++)
tev.Color[i][comp] = (u8)ColorSlopes[i][comp].GetValue(dx, dy);
}
// tex coords
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
// multiply by 128 because TEV stores 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.numtevstages; i++)
{
tev.TextureLod[i] = rasterBlock.TextureLod[i];
tev.TextureLinear[i] = rasterBlock.TextureLinear[i];
}
tev.Draw();
}
void InitTriangle(float X1, float Y1, s32 xi, s32 yi)
{
vertex0X = xi;
vertex0Y = yi;
// adjust a little less than 0.5
const float adjust = 0.495f;
vertexOffsetX = ((float)xi - X1) + adjust;
vertexOffsetY = ((float)yi - Y1) + adjust;
}
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;
}
inline void CalculateLOD(s32 &lod, bool &linear, u32 texmap, u32 texcoord)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
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
TexMode0& tm0 = texUnit.texMode0[subTexmap];
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];
sDelta = abs(uv0[0] - uv1[0]);
tDelta = abs(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 = max(abs(uv0[0] - uv1[0]), abs(uv0[0] - uv2[0]));
tDelta = max(abs(uv0[1] - uv1[1]), abs(uv0[1] - uv2[1]));
}
// get LOD in s28.4
lod = FixedLog2(max(sDelta, tDelta));
// 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));
// order of checks matters
// should be:
// if lod > max then max
// else if lod < min then min
lod = CLAMP(lod, (s32)tm1.min_lod, (s32)tm1.max_lod);
}
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];
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;
// tex coords
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
float projection;
if (xfregs.texMtxInfo[i].projection)
{
float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
projection = invW / q;
}
else
projection = invW;
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;
CalculateLOD(rasterBlock.IndirectLod[i], rasterBlock.IndirectLinear[i], texmap, texcoord);
}
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
{
int stageOdd = i&1;
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);
}
}
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(stats.thisFrame.numTrianglesDrawn);
if (g_Config.bHwRasterizer)
{
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
return;
}
// adapted from http://www.devmaster.net/forums/showthread.php?t=1884
// 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;
// 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;
// Fixed-pos32 deltas
const s32 FDX12 = DX12 << 4;
const s32 FDX23 = DX23 << 4;
const s32 FDX31 = DX31 << 4;
const s32 FDY12 = DY12 << 4;
const s32 FDY23 = DY23 << 4;
const s32 FDY31 = DY31 << 4;
// Bounding rectangle
s32 minx = (min(min(X1, X2), X3) + 0xF) >> 4;
s32 maxx = (max(max(X1, X2), X3) + 0xF) >> 4;
s32 miny = (min(min(Y1, Y2), Y3) + 0xF) >> 4;
s32 maxy = (max(max(Y1, Y2), Y3) + 0xF) >> 4;
// scissor
minx = max(minx, scissorLeft);
maxx = min(maxx, scissorRight);
miny = max(miny, scissorTop);
maxy = min(maxy, scissorBottom);
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;
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);
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.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);
}
// Start in corner of 8x8 block
minx &= ~(BLOCK_SIZE - 1);
miny &= ~(BLOCK_SIZE - 1);
// 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++;
// 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);
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);
// Skip block when outside an edge
if(a == 0x0 || b == 0x0 || c == 0x0) continue;
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;
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);
}
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
}
}
}
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Rasterizer.h"
#include "HwRasterizer.h"
#include "EfbInterface.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Tev.h"
#include "Statistics.h"
#include "VideoConfig.h"
#define BLOCK_SIZE 2
#define CLAMP(x, a, b) (x>b)?b:(x<a)?a:x
// returns approximation of log2(f) in s28.4
// results are close enough to use for LOD
static inline s32 FixedLog2(float f)
{
u32 *x = (u32*)&f;
s32 logInt = ((*x & 0x7F800000) >> 19) - 2032; // integer part
s32 logFract = (*x & 0x007fffff) >> 19; // approximate fractional part
return logInt + logFract;
}
namespace Rasterizer
{
Slope ZSlope;
Slope WSlope;
Slope ColorSlopes[2][4];
Slope TexSlopes[8][3];
s32 vertex0X;
s32 vertex0Y;
float vertexOffsetX;
float vertexOffsetY;
s32 scissorLeft = 0;
s32 scissorTop = 0;
s32 scissorRight = 0;
s32 scissorBottom = 0;
Tev tev;
RasterBlock rasterBlock;
void Init()
{
tev.Init();
}
inline int iround(float x)
{
int t;
#if defined(_WIN32) && !defined(_M_X64)
__asm
{
fld x
fistp t
}
#else
t = (int)x;
if((x - t) >= 0.5)
return t + 1;
#endif
return t;
}
void SetScissor()
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
int yoff = bpmem.scissorOffset.y * 2 - 342;
scissorLeft = bpmem.scissorTL.x - xoff - 342;
if (scissorLeft < 0) scissorLeft = 0;
scissorTop = bpmem.scissorTL.y - yoff - 342;
if (scissorTop < 0) scissorTop = 0;
scissorRight = bpmem.scissorBR.x - xoff - 341;
if (scissorRight > EFB_WIDTH) scissorRight = EFB_WIDTH;
scissorBottom = bpmem.scissorBR.y - yoff - 341;
if (scissorBottom > EFB_HEIGHT) scissorBottom = EFB_HEIGHT;
}
void SetTevReg(int reg, int comp, bool konst, s16 color)
{
tev.SetRegColor(reg, comp, konst, color);
}
inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
{
INCSTAT(stats.thisFrame.rasterizedPixels);
float dx = vertexOffsetX + (float)(x - vertex0X);
float dy = vertexOffsetY + (float)(y - vertex0Y);
float zFloat = 1.0f + ZSlope.GetValue(dx, dy);
if (zFloat < 0.0f || zFloat > 1.0f)
return;
s32 z = (s32)(zFloat * 0x00ffffff);
if (bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
{
// early z
if (!EfbInterface::ZCompare(x, y, z))
return;
}
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
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++)
tev.Color[i][comp] = (u8)ColorSlopes[i][comp].GetValue(dx, dy);
}
// tex coords
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
// multiply by 128 because TEV stores 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.numtevstages; i++)
{
tev.TextureLod[i] = rasterBlock.TextureLod[i];
tev.TextureLinear[i] = rasterBlock.TextureLinear[i];
}
tev.Draw();
}
void InitTriangle(float X1, float Y1, s32 xi, s32 yi)
{
vertex0X = xi;
vertex0Y = yi;
// adjust a little less than 0.5
const float adjust = 0.495f;
vertexOffsetX = ((float)xi - X1) + adjust;
vertexOffsetY = ((float)yi - Y1) + adjust;
}
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;
}
inline void CalculateLOD(s32 &lod, bool &linear, u32 texmap, u32 texcoord)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
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
TexMode0& tm0 = texUnit.texMode0[subTexmap];
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];
sDelta = abs(uv0[0] - uv1[0]);
tDelta = abs(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 = max(abs(uv0[0] - uv1[0]), abs(uv0[0] - uv2[0]));
tDelta = max(abs(uv0[1] - uv1[1]), abs(uv0[1] - uv2[1]));
}
// get LOD in s28.4
lod = FixedLog2(max(sDelta, tDelta));
// 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));
// order of checks matters
// should be:
// if lod > max then max
// else if lod < min then min
lod = CLAMP(lod, (s32)tm1.min_lod, (s32)tm1.max_lod);
}
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];
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;
// tex coords
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
float projection;
if (xfregs.texMtxInfo[i].projection)
{
float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
projection = invW / q;
}
else
projection = invW;
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;
CalculateLOD(rasterBlock.IndirectLod[i], rasterBlock.IndirectLinear[i], texmap, texcoord);
}
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
{
int stageOdd = i&1;
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);
}
}
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(stats.thisFrame.numTrianglesDrawn);
if (g_Config.bHwRasterizer)
{
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
return;
}
// adapted from http://www.devmaster.net/forums/showthread.php?t=1884
// 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;
// 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;
// Fixed-pos32 deltas
const s32 FDX12 = DX12 << 4;
const s32 FDX23 = DX23 << 4;
const s32 FDX31 = DX31 << 4;
const s32 FDY12 = DY12 << 4;
const s32 FDY23 = DY23 << 4;
const s32 FDY31 = DY31 << 4;
// Bounding rectangle
s32 minx = (min(min(X1, X2), X3) + 0xF) >> 4;
s32 maxx = (max(max(X1, X2), X3) + 0xF) >> 4;
s32 miny = (min(min(Y1, Y2), Y3) + 0xF) >> 4;
s32 maxy = (max(max(Y1, Y2), Y3) + 0xF) >> 4;
// scissor
minx = max(minx, scissorLeft);
maxx = min(maxx, scissorRight);
miny = max(miny, scissorTop);
maxy = min(maxy, scissorBottom);
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;
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);
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.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);
}
// Start in corner of 8x8 block
minx &= ~(BLOCK_SIZE - 1);
miny &= ~(BLOCK_SIZE - 1);
// 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++;
// 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);
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);
// Skip block when outside an edge
if(a == 0x0 || b == 0x0 || c == 0x0) continue;
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;
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);
}
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
}
}
}
}
}
}

View File

@ -1,59 +1,59 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RASTERIZER_H_
#define _RASTERIZER_H_
#include "NativeVertexFormat.h"
namespace Rasterizer
{
void Init();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void SetScissor();
void SetTevReg(int reg, int comp, bool konst, s16 color);
struct Slope
{
float dfdx;
float dfdy;
float f0;
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
};
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];
};
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RASTERIZER_H_
#define _RASTERIZER_H_
#include "NativeVertexFormat.h"
namespace Rasterizer
{
void Init();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void SetScissor();
void SetTevReg(int reg, int comp, bool konst, s16 color);
struct Slope
{
float dfdx;
float dfdy;
float f0;
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
};
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];
};
}
#endif

View File

@ -1,204 +1,204 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "GLUtil.h"
#include "Renderer.h"
#include "main.h"
#include "Statistics.h"
#include "RasterFont.h"
#define VSYNC_ENABLED 0
static GLuint s_RenderTarget = 0;
RasterFont* s_pfont = NULL;
void Renderer::Init(SVideoInitialize *_pVideoInitialize)
{
if (!OpenGL_Create(g_VideoInitialize, 640, 480)) // 640x480 will be the default if all else fails
{
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
return;
}
_pVideoInitialize->pPeekMessages = g_VideoInitialize.pPeekMessages;
_pVideoInitialize->pUpdateFPSDisplay = g_VideoInitialize.pUpdateFPSDisplay;
_pVideoInitialize->pWindowHandle = g_VideoInitialize.pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
_pVideoInitialize->pXWindow = g_VideoInitialize.pXWindow;
#endif
}
void Renderer::Shutdown()
{
glDeleteTextures(1, &s_RenderTarget);
delete s_pfont;
s_pfont = 0;
}
void Renderer::Prepare()
{
OpenGL_MakeCurrent();
// Init extension support.
if (glewInit() != GLEW_OK) {
ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?");
return;
}
// Handle VSync on/off
#ifdef _WIN32
if (WGLEW_EXT_swap_control)
wglSwapIntervalEXT(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)Does your video card support OpenGL 2.x?");
#elif defined(HAVE_X11) && HAVE_X11
if (glXSwapIntervalSGI)
glXSwapIntervalSGI(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)");
#endif
glStencilFunc(GL_ALWAYS, 0, 0);
// used by hw rasterizer if it enables blending and depth test
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_SCISSOR_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
//glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
s_pfont = new RasterFont();
// legacy multitexturing: select texture channel only.
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glGenTextures(1, &s_RenderTarget);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
{
int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth();
int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight();
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
s_pfont->printMultilineText(pstr,
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
}
void Renderer::DrawDebugText()
{
char debugtext_buffer[8192];
char *p = debugtext_buffer;
p[0] = 0;
if (g_Config.bShowStats)
{
p+=sprintf(p,"Objects: %i\n",stats.thisFrame.numDrawnObjects);
p+=sprintf(p,"Primatives: %i\n",stats.thisFrame.numPrimatives);
p+=sprintf(p,"Vertices Loaded: %i\n",stats.thisFrame.numVerticesLoaded);
p+=sprintf(p,"Triangles Input: %i\n",stats.thisFrame.numTrianglesIn);
p+=sprintf(p,"Triangles Rejected: %i\n",stats.thisFrame.numTrianglesRejected);
p+=sprintf(p,"Triangles Culled: %i\n",stats.thisFrame.numTrianglesCulled);
p+=sprintf(p,"Triangles Clipped: %i\n",stats.thisFrame.numTrianglesClipped);
p+=sprintf(p,"Triangles Drawn: %i\n",stats.thisFrame.numTrianglesDrawn);
p+=sprintf(p,"Rasterized Pix: %i\n",stats.thisFrame.rasterizedPixels);
p+=sprintf(p,"TEV Pix In: %i\n",stats.thisFrame.tevPixelsIn);
p+=sprintf(p,"TEV Pix Out: %i\n",stats.thisFrame.tevPixelsOut);
}
// Render a shadow, and then the text.
Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
Renderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00);
}
void Renderer::DrawTexture(u8 *texture, int width, int height)
{
OpenGL_Update(); // just updates the render window position and the backbuffer size
GLsizei glWidth = (GLsizei)OpenGL_GetBackbufferWidth();
GLsizei glHeight = (GLsizei)OpenGL_GetBackbufferHeight();
// Update GLViewPort
glViewport(0, 0, glWidth, glHeight);
glScissor(0, 0, glWidth, glHeight);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GL_REPORT_ERRORD();
GLfloat u_max = (GLfloat)width;
GLfloat v_max = (GLfloat)glHeight;
glBegin(GL_QUADS);
glTexCoord2f(0, v_max); glVertex2f(-1, -1);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glTexCoord2f(u_max, 0); glVertex2f( 1, 1);
glTexCoord2f(u_max, v_max); glVertex2f( 1, -1);
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void Renderer::SwapBuffer()
{
DrawDebugText();
glFlush();
OpenGL_SwapBuffers();
GL_REPORT_ERRORD();
stats.ResetFrame();
// Clear framebuffer
glClearColor(0, 0, 0, 0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL_REPORT_ERRORD();
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "GLUtil.h"
#include "Renderer.h"
#include "main.h"
#include "Statistics.h"
#include "RasterFont.h"
#define VSYNC_ENABLED 0
static GLuint s_RenderTarget = 0;
RasterFont* s_pfont = NULL;
void Renderer::Init(SVideoInitialize *_pVideoInitialize)
{
if (!OpenGL_Create(g_VideoInitialize, 640, 480)) // 640x480 will be the default if all else fails
{
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
return;
}
_pVideoInitialize->pPeekMessages = g_VideoInitialize.pPeekMessages;
_pVideoInitialize->pUpdateFPSDisplay = g_VideoInitialize.pUpdateFPSDisplay;
_pVideoInitialize->pWindowHandle = g_VideoInitialize.pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
_pVideoInitialize->pXWindow = g_VideoInitialize.pXWindow;
#endif
}
void Renderer::Shutdown()
{
glDeleteTextures(1, &s_RenderTarget);
delete s_pfont;
s_pfont = 0;
}
void Renderer::Prepare()
{
OpenGL_MakeCurrent();
// Init extension support.
if (glewInit() != GLEW_OK) {
ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?");
return;
}
// Handle VSync on/off
#ifdef _WIN32
if (WGLEW_EXT_swap_control)
wglSwapIntervalEXT(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)Does your video card support OpenGL 2.x?");
#elif defined(HAVE_X11) && HAVE_X11
if (glXSwapIntervalSGI)
glXSwapIntervalSGI(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)");
#endif
glStencilFunc(GL_ALWAYS, 0, 0);
// used by hw rasterizer if it enables blending and depth test
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_SCISSOR_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
//glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
s_pfont = new RasterFont();
// legacy multitexturing: select texture channel only.
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glGenTextures(1, &s_RenderTarget);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
{
int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth();
int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight();
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
s_pfont->printMultilineText(pstr,
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
}
void Renderer::DrawDebugText()
{
char debugtext_buffer[8192];
char *p = debugtext_buffer;
p[0] = 0;
if (g_Config.bShowStats)
{
p+=sprintf(p,"Objects: %i\n",stats.thisFrame.numDrawnObjects);
p+=sprintf(p,"Primatives: %i\n",stats.thisFrame.numPrimatives);
p+=sprintf(p,"Vertices Loaded: %i\n",stats.thisFrame.numVerticesLoaded);
p+=sprintf(p,"Triangles Input: %i\n",stats.thisFrame.numTrianglesIn);
p+=sprintf(p,"Triangles Rejected: %i\n",stats.thisFrame.numTrianglesRejected);
p+=sprintf(p,"Triangles Culled: %i\n",stats.thisFrame.numTrianglesCulled);
p+=sprintf(p,"Triangles Clipped: %i\n",stats.thisFrame.numTrianglesClipped);
p+=sprintf(p,"Triangles Drawn: %i\n",stats.thisFrame.numTrianglesDrawn);
p+=sprintf(p,"Rasterized Pix: %i\n",stats.thisFrame.rasterizedPixels);
p+=sprintf(p,"TEV Pix In: %i\n",stats.thisFrame.tevPixelsIn);
p+=sprintf(p,"TEV Pix Out: %i\n",stats.thisFrame.tevPixelsOut);
}
// Render a shadow, and then the text.
Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
Renderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00);
}
void Renderer::DrawTexture(u8 *texture, int width, int height)
{
OpenGL_Update(); // just updates the render window position and the backbuffer size
GLsizei glWidth = (GLsizei)OpenGL_GetBackbufferWidth();
GLsizei glHeight = (GLsizei)OpenGL_GetBackbufferHeight();
// Update GLViewPort
glViewport(0, 0, glWidth, glHeight);
glScissor(0, 0, glWidth, glHeight);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GL_REPORT_ERRORD();
GLfloat u_max = (GLfloat)width;
GLfloat v_max = (GLfloat)glHeight;
glBegin(GL_QUADS);
glTexCoord2f(0, v_max); glVertex2f(-1, -1);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glTexCoord2f(u_max, 0); glVertex2f( 1, 1);
glTexCoord2f(u_max, v_max); glVertex2f( 1, -1);
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void Renderer::SwapBuffer()
{
DrawDebugText();
glFlush();
OpenGL_SwapBuffers();
GL_REPORT_ERRORD();
stats.ResetFrame();
// Clear framebuffer
glClearColor(0, 0, 0, 0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL_REPORT_ERRORD();
}

View File

@ -1,37 +1,37 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RENDERER_H_
#define _RENDERER_H_
#include "pluginspecs_video.h"
namespace Renderer
{
void Init(SVideoInitialize *_pVideoInitialize);
void Prepare();
void Shutdown();
void RenderText(const char* pstr, int left, int top, u32 color);
void DrawDebugText();
void DrawTexture(u8 *texture, int width, int height);
void SwapBuffer();
}
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RENDERER_H_
#define _RENDERER_H_
#include "pluginspecs_video.h"
namespace Renderer
{
void Init(SVideoInitialize *_pVideoInitialize);
void Prepare();
void Shutdown();
void RenderText(const char* pstr, int left, int top, u32 color);
void DrawDebugText();
void DrawTexture(u8 *texture, int width, int height);
void SwapBuffer();
}
#endif

View File

@ -1,171 +1,171 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "SetupUnit.h"
#include "CPMemLoader.h"
#include "OpcodeDecoder.h"
#include "Statistics.h"
#include "Clipper.h"
void SetupUnit::Init(u8 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];
}
void SetupUnit::SetupVertex()
{
switch(m_PrimType)
{
case GX_DRAW_QUADS:
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;
}
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;
}
void SetupUnit::SetupTriangle()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter = 0;
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupTriStrip()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
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_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
}
void SetupUnit::SetupTriFan()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
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_VertWritePointer = m_VertPointer[2];
}
void SetupUnit::SetupLine()
{
if (m_VertexCounter < 1)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
m_VertexCounter = 0;
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupLineStrip()
{
if (m_VertexCounter < 1)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
m_VertexCounter++;
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
m_VertWritePointer = m_VertPointer[0];
m_VertPointer[0] = m_VertPointer[1];
m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1];
}
void SetupUnit::SetupPoint()
{}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "SetupUnit.h"
#include "CPMemLoader.h"
#include "OpcodeDecoder.h"
#include "Statistics.h"
#include "Clipper.h"
void SetupUnit::Init(u8 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];
}
void SetupUnit::SetupVertex()
{
switch(m_PrimType)
{
case GX_DRAW_QUADS:
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;
}
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;
}
void SetupUnit::SetupTriangle()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter = 0;
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupTriStrip()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
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_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
}
void SetupUnit::SetupTriFan()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
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_VertWritePointer = m_VertPointer[2];
}
void SetupUnit::SetupLine()
{
if (m_VertexCounter < 1)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
m_VertexCounter = 0;
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupLineStrip()
{
if (m_VertexCounter < 1)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
m_VertexCounter++;
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
m_VertWritePointer = m_VertPointer[0];
m_VertPointer[0] = m_VertPointer[1];
m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1];
}
void SetupUnit::SetupPoint()
{}

View File

@ -1,38 +1,38 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Statistics.h"
Statistics stats;
template <class T>
void Xchg(T& a, T&b)
{
T c = a;
a = b;
b = c;
}
Statistics::Statistics()
{
frameCount = 0;
}
void Statistics::ResetFrame()
{
memset(&thisFrame, 0, sizeof(ThisFrame));
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Statistics.h"
Statistics stats;
template <class T>
void Xchg(T& a, T&b)
{
T c = a;
a = b;
b = c;
}
Statistics::Statistics()
{
frameCount = 0;
}
void Statistics::ResetFrame()
{
memset(&thisFrame, 0, sizeof(ThisFrame));
}

View File

@ -1,63 +1,63 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "CommonTypes.h"
#include "VideoConfig.h"
#ifndef _STATISTICS_H
#define _STATISTICS_H
struct Statistics
{
struct ThisFrame
{
u32 numDrawnObjects;
u32 numPrimatives;
u32 numVerticesLoaded;
u32 numVerticesOut;
u32 numTrianglesIn;
u32 numTrianglesRejected;
u32 numTrianglesCulled;
u32 numTrianglesClipped;
u32 numTrianglesDrawn;
u32 rasterizedPixels;
u32 tevPixelsIn;
u32 tevPixelsOut;
};
u32 frameCount;
Statistics();
ThisFrame thisFrame;
void ResetFrame();
};
extern Statistics stats;
#if (STATISTICS)
#define INCSTAT(a) (a)++;
#define ADDSTAT(a,b) (a)+=(b);
#define SETSTAT(a,x) (a)=(int)(x);
#else
#define INCSTAT(a) ;
#define ADDSTAT(a,b) ;
#define SETSTAT(a,x) ;
#endif
#endif // _STATISTICS_H
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "CommonTypes.h"
#include "VideoConfig.h"
#ifndef _STATISTICS_H
#define _STATISTICS_H
struct Statistics
{
struct ThisFrame
{
u32 numDrawnObjects;
u32 numPrimatives;
u32 numVerticesLoaded;
u32 numVerticesOut;
u32 numTrianglesIn;
u32 numTrianglesRejected;
u32 numTrianglesCulled;
u32 numTrianglesClipped;
u32 numTrianglesDrawn;
u32 rasterizedPixels;
u32 tevPixelsIn;
u32 tevPixelsOut;
};
u32 frameCount;
Statistics();
ThisFrame thisFrame;
void ResetFrame();
};
extern Statistics stats;
#if (STATISTICS)
#define INCSTAT(a) (a)++;
#define ADDSTAT(a,b) (a)+=(b);
#define SETSTAT(a,x) (a)=(int)(x);
#else
#define INCSTAT(a) ;
#define ADDSTAT(a,b) ;
#define SETSTAT(a,x) ;
#endif
#endif // _STATISTICS_H

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +1,85 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TEV_H_
#define _TEV_H_
#include "BPMemLoader.h"
class Tev
{
struct InputRegType {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
};
struct TextureCoordinateType
{
signed s : 24;
signed t : 24;
};
// color order: RGBA
s16 Reg[4][4];
s16 KonstantColors[4][4];
s16 FixedConstants[9];
s16 TexColor[4];
s16 RasColor[4];
s16 StageKonst[4];
s16 Zero16[4];
u8 AlphaBump;
u8 IndirectTex[4][4];
TextureCoordinateType TexCoord;
s16 *m_ColorInputLUT[16][3];
s16 *m_AlphaInputLUT[8]; // values must point to RGBA color
s16 *m_KonstLUT[32][4];
u8 *m_RasColorLUT[8];
s16 m_BiasLUT[4];
u8 m_ScaleLShiftLUT[4];
u8 m_ScaleRShiftLUT[4];
void SetRasColor(int colorChan, int swaptable);
void DrawColorRegular(TevStageCombiner::ColorCombiner &cc);
void DrawColorCompare(TevStageCombiner::ColorCombiner &cc);
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac);
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac);
void Indirect(unsigned int stageNum, s32 s, s32 t);
public:
s32 Position[3];
u8 Color[2][4];
TextureCoordinateType Uv[8];
s32 IndirectLod[4];
bool IndirectLinear[4];
s32 TextureLod[16];
bool TextureLinear[16];
void Init();
void Draw();
void SetRegColor(int reg, int comp, bool konst, s16 color);
enum { RED_C, GRN_C, BLU_C, ALP_C };
};
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TEV_H_
#define _TEV_H_
#include "BPMemLoader.h"
class Tev
{
struct InputRegType {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
};
struct TextureCoordinateType
{
signed s : 24;
signed t : 24;
};
// color order: RGBA
s16 Reg[4][4];
s16 KonstantColors[4][4];
s16 FixedConstants[9];
s16 TexColor[4];
s16 RasColor[4];
s16 StageKonst[4];
s16 Zero16[4];
u8 AlphaBump;
u8 IndirectTex[4][4];
TextureCoordinateType TexCoord;
s16 *m_ColorInputLUT[16][3];
s16 *m_AlphaInputLUT[8]; // values must point to RGBA color
s16 *m_KonstLUT[32][4];
u8 *m_RasColorLUT[8];
s16 m_BiasLUT[4];
u8 m_ScaleLShiftLUT[4];
u8 m_ScaleRShiftLUT[4];
void SetRasColor(int colorChan, int swaptable);
void DrawColorRegular(TevStageCombiner::ColorCombiner &cc);
void DrawColorCompare(TevStageCombiner::ColorCombiner &cc);
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac);
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac);
void Indirect(unsigned int stageNum, s32 s, s32 t);
public:
s32 Position[3];
u8 Color[2][4];
TextureCoordinateType Uv[8];
s32 IndirectLod[4];
bool IndirectLinear[4];
s32 TextureLod[16];
bool TextureLinear[16];
void Init();
void Draw();
void SetRegColor(int reg, int comp, bool konst, s16 color);
enum { RED_C, GRN_C, BLU_C, ALP_C };
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +1,216 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "TextureSampler.h"
#include "main.h"
#include "BPMemLoader.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
#include <cmath>
#define ALLOW_MIPMAP 1
namespace TextureSampler
{
inline void WrapCoord(int &coord, int wrapMode, int imageSize)
{
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;
}
}
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;
}
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;
}
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
{
int baseMip = 0;
bool mipLinear = false;
#if (ALLOW_MIPMAP)
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
s32 lodFract = lod & 0xf;
if (lod > 0 && tm0.min_filter & 3)
{
// use mipmap
baseMip = lod >> 4;
mipLinear = (lodFract && tm0.min_filter & 2);
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
baseMip += (lodFract >> 3) & (tm0.min_filter & 1);
}
if (mipLinear)
{
u8 sampledTex[4];
u32 texel[4];
SampleMip(s, t, baseMip, linear, texmap, sampledTex);
SetTexel(sampledTex, texel, (16 - 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
#endif
{
SampleMip(s, t, baseMip, linear, texmap, 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;
TexMode0& tm0 = texUnit.texMode0[subTexmap];
TexImage0& ti0 = texUnit.texImage0[subTexmap];
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
u8 *imageSrc = g_VideoInitialize.pGetMemoryPointer(imageBase);
int imageWidth = ti0.width;
int imageHeight = ti0.height;
int tlutAddress = texTlut.tmem_offset << 9;
// 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);
imageWidth >>= mip;
imageHeight >>= mip;
s >>= mip;
t >>= mip;
while (mip)
{
mipWidth = max(mipWidth, fmtWidth);
mipHeight = max(mipHeight, fmtHeight);
u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
imageSrc += size;
mipWidth >>= 1;
mipHeight >>= 1;
mip--;
}
}
if (linear)
{
// offset linear sampling
s -= 64;
t -= 64;
// integer part of sample location
int imageS = s >> 7;
int imageT = t >> 7;
// linear sampling
int imageSPlus1 = imageS + 1;
int fractS = s & 0x7f;
int imageTPlus1 = imageT + 1;
int fractT = t & 0x7f;
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);
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
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;
// nearest neighbor sampling
WrapCoord(imageS, tm0.wrap_s, imageWidth);
WrapCoord(imageT, tm0.wrap_t, imageHeight);
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
}
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "TextureSampler.h"
#include "main.h"
#include "BPMemLoader.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
#include <cmath>
#define ALLOW_MIPMAP 1
namespace TextureSampler
{
inline void WrapCoord(int &coord, int wrapMode, int imageSize)
{
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;
}
}
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;
}
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;
}
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
{
int baseMip = 0;
bool mipLinear = false;
#if (ALLOW_MIPMAP)
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
s32 lodFract = lod & 0xf;
if (lod > 0 && tm0.min_filter & 3)
{
// use mipmap
baseMip = lod >> 4;
mipLinear = (lodFract && tm0.min_filter & 2);
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
baseMip += (lodFract >> 3) & (tm0.min_filter & 1);
}
if (mipLinear)
{
u8 sampledTex[4];
u32 texel[4];
SampleMip(s, t, baseMip, linear, texmap, sampledTex);
SetTexel(sampledTex, texel, (16 - 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
#endif
{
SampleMip(s, t, baseMip, linear, texmap, 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;
TexMode0& tm0 = texUnit.texMode0[subTexmap];
TexImage0& ti0 = texUnit.texImage0[subTexmap];
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
u8 *imageSrc = g_VideoInitialize.pGetMemoryPointer(imageBase);
int imageWidth = ti0.width;
int imageHeight = ti0.height;
int tlutAddress = texTlut.tmem_offset << 9;
// 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);
imageWidth >>= mip;
imageHeight >>= mip;
s >>= mip;
t >>= mip;
while (mip)
{
mipWidth = max(mipWidth, fmtWidth);
mipHeight = max(mipHeight, fmtHeight);
u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
imageSrc += size;
mipWidth >>= 1;
mipHeight >>= 1;
mip--;
}
}
if (linear)
{
// offset linear sampling
s -= 64;
t -= 64;
// integer part of sample location
int imageS = s >> 7;
int imageT = t >> 7;
// linear sampling
int imageSPlus1 = imageS + 1;
int fractS = s & 0x7f;
int imageTPlus1 = imageT + 1;
int fractT = t & 0x7f;
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);
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
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;
// nearest neighbor sampling
WrapCoord(imageS, tm0.wrap_s, imageWidth);
WrapCoord(imageT, tm0.wrap_t, imageHeight);
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
}
}
}

View File

@ -1,344 +1,344 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "VertexLoader.h"
#include "VertexLoader_Position.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Normal.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Color.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_TextCoord.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "TransformUnit.h"
#include "SetupUnit.h"
#include "Statistics.h"
#include "NativeVertexWriter.h"
#include "VertexFormatConverter.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
// Vertex loaders read these
int tcIndex;
int colIndex;
int colElements[2];
float posScale;
float tcScale[8];
VertexLoader::VertexLoader() :
m_VertexSize(0),
m_NumAttributeLoaders(0)
{
VertexLoader_Normal::Init();
VertexLoader_Position::Init();
VertexLoader_TextCoord::Init();
m_SetupUnit = new SetupUnit;
}
VertexLoader::~VertexLoader()
{
delete m_SetupUnit;
m_SetupUnit = NULL;
}
void VertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
{
m_CurrentVat = &g_VtxAttr[attributeIndex];
posScale = 1.0f / float(1 << m_CurrentVat->g0.PosFrac);
tcScale[0] = 1.0f / float(1 << m_CurrentVat->g0.Tex0Frac);
tcScale[1] = 1.0f / float(1 << m_CurrentVat->g1.Tex1Frac);
tcScale[2] = 1.0f / float(1 << m_CurrentVat->g1.Tex2Frac);
tcScale[3] = 1.0f / float(1 << m_CurrentVat->g1.Tex3Frac);
tcScale[4] = 1.0f / float(1 << m_CurrentVat->g2.Tex4Frac);
tcScale[5] = 1.0f / float(1 << m_CurrentVat->g2.Tex5Frac);
tcScale[6] = 1.0f / float(1 << m_CurrentVat->g2.Tex6Frac);
tcScale[7] = 1.0f / float(1 << m_CurrentVat->g2.Tex7Frac);
//TexMtx
const int tmDesc[8] = {
g_VtxDesc.Tex0MatIdx, g_VtxDesc.Tex1MatIdx, g_VtxDesc.Tex2MatIdx, g_VtxDesc.Tex3MatIdx,
g_VtxDesc.Tex4MatIdx, g_VtxDesc.Tex5MatIdx, g_VtxDesc.Tex6MatIdx, g_VtxDesc.Tex7MatIdx
};
// Colors
const int colDesc[2] = {g_VtxDesc.Color0, g_VtxDesc.Color1};
colElements[0] = m_CurrentVat->g0.Color0Elements;
colElements[1] = m_CurrentVat->g0.Color1Elements;
const int colComp[2] = {m_CurrentVat->g0.Color0Comp, m_CurrentVat->g0.Color1Comp};
// TextureCoord
const int tcDesc[8] = {
g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord,
g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (g_VtxDesc.Hex >> 31) & 3
};
const int tcElements[8] = {
m_CurrentVat->g0.Tex0CoordElements, m_CurrentVat->g1.Tex1CoordElements, m_CurrentVat->g1.Tex2CoordElements,
m_CurrentVat->g1.Tex3CoordElements, m_CurrentVat->g1.Tex4CoordElements, m_CurrentVat->g2.Tex5CoordElements,
m_CurrentVat->g2.Tex6CoordElements, m_CurrentVat->g2.Tex7CoordElements
};
const int tcFormat[8] = {
m_CurrentVat->g0.Tex0CoordFormat, m_CurrentVat->g1.Tex1CoordFormat, m_CurrentVat->g1.Tex2CoordFormat,
m_CurrentVat->g1.Tex3CoordFormat, m_CurrentVat->g1.Tex4CoordFormat, m_CurrentVat->g2.Tex5CoordFormat,
m_CurrentVat->g2.Tex6CoordFormat, m_CurrentVat->g2.Tex7CoordFormat
};
m_VertexSize = 0;
// Reset pipeline
m_positionLoader = NULL;
m_normalLoader = NULL;
m_NumAttributeLoaders = 0;
// Reset vertex
// matrix index from xfregs or cp memory?
_assert_msg_(VIDEO, xfregs.MatrixIndexA.PosNormalMtxIdx == MatrixIndexA.PosNormalMtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex0MtxIdx == MatrixIndexA.Tex0MtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex1MtxIdx == MatrixIndexA.Tex1MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex2MtxIdx == MatrixIndexA.Tex2MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex3MtxIdx == MatrixIndexA.Tex3MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex4MtxIdx == MatrixIndexB.Tex4MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex5MtxIdx == MatrixIndexB.Tex5MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex6MtxIdx == MatrixIndexB.Tex6MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex7MtxIdx == MatrixIndexB.Tex7MtxIdx, "Matrix indices don't match");
m_Vertex.posMtx = xfregs.MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = xfregs.MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = xfregs.MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = xfregs.MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = xfregs.MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = xfregs.MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = xfregs.MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = xfregs.MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = xfregs.MatrixIndexB.Tex7MtxIdx;
/*m_Vertex.posMtx = MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = MatrixIndexB.Tex7MtxIdx;*/
if (g_VtxDesc.PosMatIdx != NOT_PRESENT) {
AddAttributeLoader(LoadPosMtx);
m_VertexSize++;
}
for (int i = 0; i < 8; ++i) {
if (tmDesc[i] != NOT_PRESENT)
{
AddAttributeLoader(LoadTexMtx, i);
m_VertexSize++;
}
}
// Write vertex position loader
m_positionLoader = VertexLoader_Position::GetFunction(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
m_VertexSize += VertexLoader_Position::GetSize(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
AddAttributeLoader(LoadPosition);
// Normals
if (g_VtxDesc.Normal != NOT_PRESENT) {
m_VertexSize += VertexLoader_Normal::GetSize(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3);
m_normalLoader = VertexLoader_Normal::GetFunction(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3, true);
if (m_normalLoader == 0)
{
ERROR_LOG(VIDEO, "VertexLoader_Normal::GetFunction returned zero!");
}
AddAttributeLoader(LoadNormal);
switch (m_CurrentVat->g0.NormalFormat) {
case FORMAT_UBYTE:
case FORMAT_BYTE:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Byte;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Byte;
break;
case FORMAT_USHORT:
case FORMAT_SHORT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Short;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Short;
break;
case FORMAT_FLOAT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Float;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Float;
break;
default: _assert_(0); break;
}
}
for (int i = 0; i < 2; i++) {
switch (colDesc[i])
{
case NOT_PRESENT:
m_colorLoader[i] = NULL;
break;
case DIRECT:
switch (colComp[i])
{
case FORMAT_16B_565: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_565); break;
case FORMAT_24B_888: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_888); break;
case FORMAT_32B_888x: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_888x); break;
case FORMAT_16B_4444: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_4444); break;
case FORMAT_24B_6666: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_6666); break;
case FORMAT_32B_8888: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX8:
m_VertexSize += 1;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex8_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex8_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex8_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex8_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex8_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex8_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX16:
m_VertexSize += 2;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex16_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex16_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex16_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex16_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex16_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex16_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
}
}
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
for (int i = 0; i < 8; i++) {
const int desc = tcDesc[i];
const int format = tcFormat[i];
const int elements = tcElements[i];
_assert_msg_(VIDEO, NOT_PRESENT <= desc && desc <= INDEX16, "Invalid texture coordinates description!\n(desc = %d)", desc);
_assert_msg_(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, "Invalid texture coordinates format!\n(format = %d)", format);
_assert_msg_(VIDEO, 0 <= elements && elements <= 1, "Invalid number of texture coordinates elemnts!\n(elements = %d)", elements);
m_texCoordLoader[i] = VertexLoader_TextCoord::GetFunction(desc, format, elements);
m_VertexSize += VertexLoader_TextCoord::GetSize(desc, format, elements);
if (m_texCoordLoader[i])
AddAttributeLoader(LoadTexCoord, i);
}
// special case if only pos and tex coord 0 and tex coord input is AB11
m_TexGenSpecialCase =
((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0
(g_VtxDesc.Tex0Coord != NOT_PRESENT) &&
(xfregs.texMtxInfo[0].inputform == XF_TEXINPUT_AB11);
m_SetupUnit->Init(primitiveType);
}
void VertexLoader::LoadVertex()
{
for (int i = 0; i < m_NumAttributeLoaders; i++)
m_AttributeLoaders[i].loader(this, &m_Vertex, m_AttributeLoaders[i].index);
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
// transform input data
TransformUnit::TransformPosition(&m_Vertex, outVertex);
if (g_VtxDesc.Normal != NOT_PRESENT)
{
TransformUnit::TransformNormal(&m_Vertex, m_CurrentVat->g0.NormalElements, outVertex);
}
TransformUnit::TransformColor(&m_Vertex, outVertex);
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
m_SetupUnit->SetupVertex();
INCSTAT(stats.thisFrame.numVerticesLoaded)
}
void VertexLoader::AddAttributeLoader(AttributeLoader loader, u8 index)
{
_assert_msg_(VIDEO, m_NumAttributeLoaders < 21, "Too many attribute loaders");
m_AttributeLoaders[m_NumAttributeLoaders].loader = loader;
m_AttributeLoaders[m_NumAttributeLoaders++].index = index;
}
void VertexLoader::LoadPosMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
vertex->posMtx = DataReadU8() & 0x3f;
}
void VertexLoader::LoadTexMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
vertex->texMtx[index] = DataReadU8() & 0x3f;
}
void VertexLoader::LoadPosition(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->position;
vertexLoader->m_positionLoader();
}
void VertexLoader::LoadNormal(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
u8 buffer[3*3*4];
VertexManager::s_pCurBufferPointer = buffer;
vertexLoader->m_normalLoader();
// the common vertex loader loads data as bytes, shorts or floats so an extra step is needed to make it floats
vertexLoader->m_normalConverter(vertex, buffer);
}
void VertexLoader::LoadColor(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
u32 color;
VertexManager::s_pCurBufferPointer = (u8*)&color;
colIndex = index;
vertexLoader->m_colorLoader[index]();
// rgba -> abgr
*(u32*)vertex->color[index] = Common::swap32(color);
}
void VertexLoader::LoadTexCoord(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->texCoords[index];
tcIndex = index;
vertexLoader->m_texCoordLoader[index]();
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "VertexLoader.h"
#include "VertexLoader_Position.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Normal.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Color.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_TextCoord.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "TransformUnit.h"
#include "SetupUnit.h"
#include "Statistics.h"
#include "NativeVertexWriter.h"
#include "VertexFormatConverter.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
// Vertex loaders read these
int tcIndex;
int colIndex;
int colElements[2];
float posScale;
float tcScale[8];
VertexLoader::VertexLoader() :
m_VertexSize(0),
m_NumAttributeLoaders(0)
{
VertexLoader_Normal::Init();
VertexLoader_Position::Init();
VertexLoader_TextCoord::Init();
m_SetupUnit = new SetupUnit;
}
VertexLoader::~VertexLoader()
{
delete m_SetupUnit;
m_SetupUnit = NULL;
}
void VertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
{
m_CurrentVat = &g_VtxAttr[attributeIndex];
posScale = 1.0f / float(1 << m_CurrentVat->g0.PosFrac);
tcScale[0] = 1.0f / float(1 << m_CurrentVat->g0.Tex0Frac);
tcScale[1] = 1.0f / float(1 << m_CurrentVat->g1.Tex1Frac);
tcScale[2] = 1.0f / float(1 << m_CurrentVat->g1.Tex2Frac);
tcScale[3] = 1.0f / float(1 << m_CurrentVat->g1.Tex3Frac);
tcScale[4] = 1.0f / float(1 << m_CurrentVat->g2.Tex4Frac);
tcScale[5] = 1.0f / float(1 << m_CurrentVat->g2.Tex5Frac);
tcScale[6] = 1.0f / float(1 << m_CurrentVat->g2.Tex6Frac);
tcScale[7] = 1.0f / float(1 << m_CurrentVat->g2.Tex7Frac);
//TexMtx
const int tmDesc[8] = {
g_VtxDesc.Tex0MatIdx, g_VtxDesc.Tex1MatIdx, g_VtxDesc.Tex2MatIdx, g_VtxDesc.Tex3MatIdx,
g_VtxDesc.Tex4MatIdx, g_VtxDesc.Tex5MatIdx, g_VtxDesc.Tex6MatIdx, g_VtxDesc.Tex7MatIdx
};
// Colors
const int colDesc[2] = {g_VtxDesc.Color0, g_VtxDesc.Color1};
colElements[0] = m_CurrentVat->g0.Color0Elements;
colElements[1] = m_CurrentVat->g0.Color1Elements;
const int colComp[2] = {m_CurrentVat->g0.Color0Comp, m_CurrentVat->g0.Color1Comp};
// TextureCoord
const int tcDesc[8] = {
g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord,
g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (g_VtxDesc.Hex >> 31) & 3
};
const int tcElements[8] = {
m_CurrentVat->g0.Tex0CoordElements, m_CurrentVat->g1.Tex1CoordElements, m_CurrentVat->g1.Tex2CoordElements,
m_CurrentVat->g1.Tex3CoordElements, m_CurrentVat->g1.Tex4CoordElements, m_CurrentVat->g2.Tex5CoordElements,
m_CurrentVat->g2.Tex6CoordElements, m_CurrentVat->g2.Tex7CoordElements
};
const int tcFormat[8] = {
m_CurrentVat->g0.Tex0CoordFormat, m_CurrentVat->g1.Tex1CoordFormat, m_CurrentVat->g1.Tex2CoordFormat,
m_CurrentVat->g1.Tex3CoordFormat, m_CurrentVat->g1.Tex4CoordFormat, m_CurrentVat->g2.Tex5CoordFormat,
m_CurrentVat->g2.Tex6CoordFormat, m_CurrentVat->g2.Tex7CoordFormat
};
m_VertexSize = 0;
// Reset pipeline
m_positionLoader = NULL;
m_normalLoader = NULL;
m_NumAttributeLoaders = 0;
// Reset vertex
// matrix index from xfregs or cp memory?
_assert_msg_(VIDEO, xfregs.MatrixIndexA.PosNormalMtxIdx == MatrixIndexA.PosNormalMtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex0MtxIdx == MatrixIndexA.Tex0MtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex1MtxIdx == MatrixIndexA.Tex1MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex2MtxIdx == MatrixIndexA.Tex2MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex3MtxIdx == MatrixIndexA.Tex3MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex4MtxIdx == MatrixIndexB.Tex4MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex5MtxIdx == MatrixIndexB.Tex5MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex6MtxIdx == MatrixIndexB.Tex6MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex7MtxIdx == MatrixIndexB.Tex7MtxIdx, "Matrix indices don't match");
m_Vertex.posMtx = xfregs.MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = xfregs.MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = xfregs.MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = xfregs.MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = xfregs.MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = xfregs.MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = xfregs.MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = xfregs.MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = xfregs.MatrixIndexB.Tex7MtxIdx;
/*m_Vertex.posMtx = MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = MatrixIndexB.Tex7MtxIdx;*/
if (g_VtxDesc.PosMatIdx != NOT_PRESENT) {
AddAttributeLoader(LoadPosMtx);
m_VertexSize++;
}
for (int i = 0; i < 8; ++i) {
if (tmDesc[i] != NOT_PRESENT)
{
AddAttributeLoader(LoadTexMtx, i);
m_VertexSize++;
}
}
// Write vertex position loader
m_positionLoader = VertexLoader_Position::GetFunction(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
m_VertexSize += VertexLoader_Position::GetSize(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
AddAttributeLoader(LoadPosition);
// Normals
if (g_VtxDesc.Normal != NOT_PRESENT) {
m_VertexSize += VertexLoader_Normal::GetSize(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3);
m_normalLoader = VertexLoader_Normal::GetFunction(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3, true);
if (m_normalLoader == 0)
{
ERROR_LOG(VIDEO, "VertexLoader_Normal::GetFunction returned zero!");
}
AddAttributeLoader(LoadNormal);
switch (m_CurrentVat->g0.NormalFormat) {
case FORMAT_UBYTE:
case FORMAT_BYTE:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Byte;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Byte;
break;
case FORMAT_USHORT:
case FORMAT_SHORT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Short;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Short;
break;
case FORMAT_FLOAT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Float;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Float;
break;
default: _assert_(0); break;
}
}
for (int i = 0; i < 2; i++) {
switch (colDesc[i])
{
case NOT_PRESENT:
m_colorLoader[i] = NULL;
break;
case DIRECT:
switch (colComp[i])
{
case FORMAT_16B_565: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_565); break;
case FORMAT_24B_888: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_888); break;
case FORMAT_32B_888x: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_888x); break;
case FORMAT_16B_4444: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_4444); break;
case FORMAT_24B_6666: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_6666); break;
case FORMAT_32B_8888: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX8:
m_VertexSize += 1;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex8_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex8_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex8_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex8_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex8_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex8_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX16:
m_VertexSize += 2;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex16_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex16_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex16_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex16_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex16_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex16_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
}
}
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
for (int i = 0; i < 8; i++) {
const int desc = tcDesc[i];
const int format = tcFormat[i];
const int elements = tcElements[i];
_assert_msg_(VIDEO, NOT_PRESENT <= desc && desc <= INDEX16, "Invalid texture coordinates description!\n(desc = %d)", desc);
_assert_msg_(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, "Invalid texture coordinates format!\n(format = %d)", format);
_assert_msg_(VIDEO, 0 <= elements && elements <= 1, "Invalid number of texture coordinates elemnts!\n(elements = %d)", elements);
m_texCoordLoader[i] = VertexLoader_TextCoord::GetFunction(desc, format, elements);
m_VertexSize += VertexLoader_TextCoord::GetSize(desc, format, elements);
if (m_texCoordLoader[i])
AddAttributeLoader(LoadTexCoord, i);
}
// special case if only pos and tex coord 0 and tex coord input is AB11
m_TexGenSpecialCase =
((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0
(g_VtxDesc.Tex0Coord != NOT_PRESENT) &&
(xfregs.texMtxInfo[0].inputform == XF_TEXINPUT_AB11);
m_SetupUnit->Init(primitiveType);
}
void VertexLoader::LoadVertex()
{
for (int i = 0; i < m_NumAttributeLoaders; i++)
m_AttributeLoaders[i].loader(this, &m_Vertex, m_AttributeLoaders[i].index);
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
// transform input data
TransformUnit::TransformPosition(&m_Vertex, outVertex);
if (g_VtxDesc.Normal != NOT_PRESENT)
{
TransformUnit::TransformNormal(&m_Vertex, m_CurrentVat->g0.NormalElements, outVertex);
}
TransformUnit::TransformColor(&m_Vertex, outVertex);
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
m_SetupUnit->SetupVertex();
INCSTAT(stats.thisFrame.numVerticesLoaded)
}
void VertexLoader::AddAttributeLoader(AttributeLoader loader, u8 index)
{
_assert_msg_(VIDEO, m_NumAttributeLoaders < 21, "Too many attribute loaders");
m_AttributeLoaders[m_NumAttributeLoaders].loader = loader;
m_AttributeLoaders[m_NumAttributeLoaders++].index = index;
}
void VertexLoader::LoadPosMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
vertex->posMtx = DataReadU8() & 0x3f;
}
void VertexLoader::LoadTexMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
vertex->texMtx[index] = DataReadU8() & 0x3f;
}
void VertexLoader::LoadPosition(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->position;
vertexLoader->m_positionLoader();
}
void VertexLoader::LoadNormal(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
u8 buffer[3*3*4];
VertexManager::s_pCurBufferPointer = buffer;
vertexLoader->m_normalLoader();
// the common vertex loader loads data as bytes, shorts or floats so an extra step is needed to make it floats
vertexLoader->m_normalConverter(vertex, buffer);
}
void VertexLoader::LoadColor(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
u32 color;
VertexManager::s_pCurBufferPointer = (u8*)&color;
colIndex = index;
vertexLoader->m_colorLoader[index]();
// rgba -> abgr
*(u32*)vertex->color[index] = Common::swap32(color);
}
void VertexLoader::LoadTexCoord(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->texCoords[index];
tcIndex = index;
vertexLoader->m_texCoordLoader[index]();
}

View File

@ -1,64 +1,64 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "FileUtil.h"
#include "IniFile.h"
#include "VideoConfig.h"
Config g_Config;
Config::Config()
{
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bShowStats = false;
bDumpTextures = false;
bDumpObjects = false;
bDumpFrames = false;
bDumpTevStages = false;
bHwRasterizer = false;
drawStart = 0;
drawEnd = 100000;
}
void Config::Load()
{
std::string temp;
IniFile iniFile;
iniFile.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_software.ini").c_str());
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
}
void Config::Save()
{
IniFile iniFile;
iniFile.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_software.ini").c_str());
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
iniFile.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_opengl.ini").c_str());
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "FileUtil.h"
#include "IniFile.h"
#include "VideoConfig.h"
Config g_Config;
Config::Config()
{
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bShowStats = false;
bDumpTextures = false;
bDumpObjects = false;
bDumpFrames = false;
bDumpTevStages = false;
bHwRasterizer = false;
drawStart = 0;
drawEnd = 100000;
}
void Config::Load()
{
std::string temp;
IniFile iniFile;
iniFile.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_software.ini").c_str());
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
}
void Config::Save()
{
IniFile iniFile;
iniFile.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_software.ini").c_str());
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
iniFile.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_opengl.ini").c_str());
}

View File

@ -1,54 +1,54 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#define _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#include "Common.h"
#define STATISTICS 1
// NEVER inherit from this class.
struct Config
{
Config();
void Load();
void Save();
// General
bool bFullscreen;
bool bHideCursor;
bool renderToMainframe;
bool bShowStats;
bool bDumpTextures;
bool bDumpObjects;
bool bDumpFrames;
bool bDumpTevStages;
bool bHwRasterizer;
u32 drawStart;
u32 drawEnd;
private:
DISALLOW_COPY_AND_ASSIGN(Config);
};
extern Config g_Config;
#endif // _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#define _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#include "Common.h"
#define STATISTICS 1
// NEVER inherit from this class.
struct Config
{
Config();
void Load();
void Save();
// General
bool bFullscreen;
bool bHideCursor;
bool renderToMainframe;
bool bShowStats;
bool bDumpTextures;
bool bDumpObjects;
bool bDumpFrames;
bool bDumpTevStages;
bool bHwRasterizer;
u32 drawStart;
u32 drawEnd;
private:
DISALLOW_COPY_AND_ASSIGN(Config);
};
extern Config g_Config;
#endif // _PLUGIN_VIDEOSOFTWARE_CONFIG_H_

View File

@ -1,389 +1,389 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <windows.h>
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#include "VideoConfig.h"
#include "main.h"
#include "Win32.h"
#include "StringUtil.h"
HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
// ------------------
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
LPVOID lpvReserved) // reserved
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
#if defined(HAVE_WX) && HAVE_WX
wxSetInstance((HINSTANCE)hinstDLL);
wxInitialize();
#endif
}
break;
case DLL_PROCESS_DETACH:
#if defined(HAVE_WX) && HAVE_WX
wxUninitialize();
#endif
break;
}
g_hInstance = hinstDLL;
return TRUE;
}
// ----------------------
// The rendering window
// ----------------------
namespace EmuWindow
{
HWND m_hWnd = NULL; // The new window that is created here
HWND m_hParent = NULL;
HINSTANCE m_hInstance = NULL;
WNDCLASSEX wndClass;
const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
int g_winstyle;
// ------------------------------------------
/* Invisible cursor option. In the lack of a predefined IDC_BLANK we make
an empty transparent cursor */
// ------------------
HCURSOR hCursor = NULL, hCursorBlank = NULL;
void CreateCursors(HINSTANCE hInstance)
{
BYTE ANDmaskCursor[] = { 0xff };
BYTE XORmaskCursor[] = { 0x00 };
hCursorBlank = CreateCursor(hInstance, 0,0, 1,1, ANDmaskCursor,XORmaskCursor);
hCursor = LoadCursor(NULL, IDC_ARROW);
}
HWND GetWnd()
{
return m_hWnd;
}
HWND GetParentWnd()
{
return m_hParent;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
switch( iMsg )
{
case WM_CREATE:
PostMessage(m_hParent, WM_USER, WM_USER_CREATE, (int)m_hParent);
break;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_SYSKEYDOWN:
switch( LOWORD( wParam ))
{
case VK_RETURN:
// Pressing Alt+Enter switch FullScreen/Windowed
if (m_hParent == NULL && !g_Config.renderToMainframe)
{
ToggleFullscreen(hWnd);
}
break;
case VK_F5: case VK_F6: case VK_F7: case VK_F8:
PostMessage(m_hParent, WM_SYSKEYDOWN, wParam, lParam);
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
break;
case WM_KEYDOWN:
switch (LOWORD( wParam ))
{
case VK_ESCAPE:
if (g_Config.bFullscreen)
{
// Pressing Esc switches to Windowed mode from Fullscreen mode
ToggleFullscreen(hWnd);
}
// And pause the emulation when already in Windowed mode
PostMessage(m_hParent, WM_USER, WM_USER_PAUSE, 0);
break;
}
break;
/* The reason we pick up the WM_MOUSEMOVE is to be able to change this option
during gameplay. The alternative is to load one of the cursors when the plugin
is loaded and go with that. This should only produce a minimal performance hit
because SetCursor is not supposed to actually change the cursor if it's the
same as the one before. */
case WM_MOUSEMOVE:
/* Check rendering mode; child or parent. Then post the mouse moves to the main window
it's nessesary for both the chil dwindow and separate rendering window because
moves over the rendering window do not reach the main program then. */
if (GetParentWnd() == NULL) // Separate rendering window
PostMessage(m_hParent, iMsg, wParam, -1);
else
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
/* To support the separate window rendering we get the message back here. So we basically
only let it pass through Dolphin > Frame.cpp to determine if it should be on or off
and coordinate it with the other settings if necessary */
case WM_USER:
if (wParam == WM_USER_STOP)
SetCursor((lParam) ? hCursor : hCursorBlank);
else if (wParam == WIIMOTE_DISCONNECT)
PostMessage(m_hParent, WM_USER, wParam, lParam);
break;
/* Post these mouse events to the main window, it's nessesary becase in difference to the
keyboard inputs these events only appear here, not in the main WndProc() */
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
// This is called when we close the window when we render to a separate window
case WM_CLOSE:
if (m_hParent == NULL)
{
// Take it out of fullscreen and stop the game
if( g_Config.bFullscreen )
ToggleFullscreen(m_hParent);
PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0);
}
break;
case WM_DESTROY:
Shutdown();
break;
// Called when a screensaver wants to show up while this window is active
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
return 0;
}
// This is called from Create()
HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title)
{
wndClass.cbSize = sizeof( wndClass );
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
// To interfer less with SetCursor() later we set this to NULL
//wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = m_szClassName;
wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
m_hInstance = hInstance;
RegisterClassEx( &wndClass );
CreateCursors(m_hInstance);
// Create child window
if (parent)
{
m_hParent = parent;
m_hWnd = CreateWindow(m_szClassName, title,
WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent, NULL, hInstance, NULL);
ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
}
// Create new separate window
else
{
DWORD style = g_Config.bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW;
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, style, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
m_hParent = (HWND)g_VideoInitialize.pWindowHandle;
m_hWnd = CreateWindow(m_szClassName, title,
style,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
parent, NULL, hInstance, NULL );
g_winstyle = GetWindowLong( m_hWnd, GWL_STYLE );
g_winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style
}
return m_hWnd;
}
void ToggleFullscreen(HWND hParent)
{
if (m_hParent == NULL)
{
int w_fs = 640, h_fs = 480;
if (g_Config.bFullscreen)
{
// Get out of fullscreen
g_Config.bFullscreen = false;
RECT rc = {0, 0, w_fs, h_fs};
// FullScreen -> Desktop
ChangeDisplaySettings(NULL, 0);
RECT rcdesktop; // Get desktop resolution
GetWindowRect(GetDesktopWindow(), &rcdesktop);
ShowCursor(TRUE);
int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// SetWindowPos to the center of the screen
SetWindowPos(hParent, NULL, X, Y, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Set new window style FS -> Windowed
SetWindowLong(hParent, GWL_STYLE, WS_OVERLAPPEDWINDOW);
// Eventually show the window!
EmuWindow::Show();
}
else
{
// Get into fullscreen
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
// Desktop -> FullScreen
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = w_fs;
dmScreenSettings.dmPelsHeight = h_fs;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
return;
// Set new window style -> PopUp
SetWindowLong(hParent, GWL_STYLE, WS_POPUP);
g_Config.bFullscreen = true;
ShowCursor(FALSE);
// SetWindowPos to the upper-left corner of the screen
SetWindowPos(hParent, NULL, 0, 0, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Eventually show the window!
EmuWindow::Show();
}
}
}
void Show()
{
ShowWindow(m_hWnd, SW_SHOW);
BringWindowToTop(m_hWnd);
UpdateWindow(m_hWnd);
}
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title)
{
return OpenWindow(hParent, hInstance, 640, 480, title);
}
void Close()
{
if (!m_hParent)
DestroyWindow(m_hWnd);
UnregisterClass(m_szClassName, m_hInstance);
}
// ------------------------------------------
// Set the size of the child or main window
// ------------------------------------------
void SetSize(int width, int height)
{
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
// Move and resize the window
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
MoveWindow(m_hWnd, rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top, TRUE);
}
} // EmuWindow
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <windows.h>
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#include "VideoConfig.h"
#include "main.h"
#include "Win32.h"
#include "StringUtil.h"
HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
// ------------------
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
LPVOID lpvReserved) // reserved
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
#if defined(HAVE_WX) && HAVE_WX
wxSetInstance((HINSTANCE)hinstDLL);
wxInitialize();
#endif
}
break;
case DLL_PROCESS_DETACH:
#if defined(HAVE_WX) && HAVE_WX
wxUninitialize();
#endif
break;
}
g_hInstance = hinstDLL;
return TRUE;
}
// ----------------------
// The rendering window
// ----------------------
namespace EmuWindow
{
HWND m_hWnd = NULL; // The new window that is created here
HWND m_hParent = NULL;
HINSTANCE m_hInstance = NULL;
WNDCLASSEX wndClass;
const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
int g_winstyle;
// ------------------------------------------
/* Invisible cursor option. In the lack of a predefined IDC_BLANK we make
an empty transparent cursor */
// ------------------
HCURSOR hCursor = NULL, hCursorBlank = NULL;
void CreateCursors(HINSTANCE hInstance)
{
BYTE ANDmaskCursor[] = { 0xff };
BYTE XORmaskCursor[] = { 0x00 };
hCursorBlank = CreateCursor(hInstance, 0,0, 1,1, ANDmaskCursor,XORmaskCursor);
hCursor = LoadCursor(NULL, IDC_ARROW);
}
HWND GetWnd()
{
return m_hWnd;
}
HWND GetParentWnd()
{
return m_hParent;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
switch( iMsg )
{
case WM_CREATE:
PostMessage(m_hParent, WM_USER, WM_USER_CREATE, (int)m_hParent);
break;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_SYSKEYDOWN:
switch( LOWORD( wParam ))
{
case VK_RETURN:
// Pressing Alt+Enter switch FullScreen/Windowed
if (m_hParent == NULL && !g_Config.renderToMainframe)
{
ToggleFullscreen(hWnd);
}
break;
case VK_F5: case VK_F6: case VK_F7: case VK_F8:
PostMessage(m_hParent, WM_SYSKEYDOWN, wParam, lParam);
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
break;
case WM_KEYDOWN:
switch (LOWORD( wParam ))
{
case VK_ESCAPE:
if (g_Config.bFullscreen)
{
// Pressing Esc switches to Windowed mode from Fullscreen mode
ToggleFullscreen(hWnd);
}
// And pause the emulation when already in Windowed mode
PostMessage(m_hParent, WM_USER, WM_USER_PAUSE, 0);
break;
}
break;
/* The reason we pick up the WM_MOUSEMOVE is to be able to change this option
during gameplay. The alternative is to load one of the cursors when the plugin
is loaded and go with that. This should only produce a minimal performance hit
because SetCursor is not supposed to actually change the cursor if it's the
same as the one before. */
case WM_MOUSEMOVE:
/* Check rendering mode; child or parent. Then post the mouse moves to the main window
it's nessesary for both the chil dwindow and separate rendering window because
moves over the rendering window do not reach the main program then. */
if (GetParentWnd() == NULL) // Separate rendering window
PostMessage(m_hParent, iMsg, wParam, -1);
else
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
/* To support the separate window rendering we get the message back here. So we basically
only let it pass through Dolphin > Frame.cpp to determine if it should be on or off
and coordinate it with the other settings if necessary */
case WM_USER:
if (wParam == WM_USER_STOP)
SetCursor((lParam) ? hCursor : hCursorBlank);
else if (wParam == WIIMOTE_DISCONNECT)
PostMessage(m_hParent, WM_USER, wParam, lParam);
break;
/* Post these mouse events to the main window, it's nessesary becase in difference to the
keyboard inputs these events only appear here, not in the main WndProc() */
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
// This is called when we close the window when we render to a separate window
case WM_CLOSE:
if (m_hParent == NULL)
{
// Take it out of fullscreen and stop the game
if( g_Config.bFullscreen )
ToggleFullscreen(m_hParent);
PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0);
}
break;
case WM_DESTROY:
Shutdown();
break;
// Called when a screensaver wants to show up while this window is active
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
break;
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
return 0;
}
// This is called from Create()
HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title)
{
wndClass.cbSize = sizeof( wndClass );
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
// To interfer less with SetCursor() later we set this to NULL
//wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = m_szClassName;
wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
m_hInstance = hInstance;
RegisterClassEx( &wndClass );
CreateCursors(m_hInstance);
// Create child window
if (parent)
{
m_hParent = parent;
m_hWnd = CreateWindow(m_szClassName, title,
WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent, NULL, hInstance, NULL);
ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
}
// Create new separate window
else
{
DWORD style = g_Config.bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW;
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, style, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
m_hParent = (HWND)g_VideoInitialize.pWindowHandle;
m_hWnd = CreateWindow(m_szClassName, title,
style,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
parent, NULL, hInstance, NULL );
g_winstyle = GetWindowLong( m_hWnd, GWL_STYLE );
g_winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style
}
return m_hWnd;
}
void ToggleFullscreen(HWND hParent)
{
if (m_hParent == NULL)
{
int w_fs = 640, h_fs = 480;
if (g_Config.bFullscreen)
{
// Get out of fullscreen
g_Config.bFullscreen = false;
RECT rc = {0, 0, w_fs, h_fs};
// FullScreen -> Desktop
ChangeDisplaySettings(NULL, 0);
RECT rcdesktop; // Get desktop resolution
GetWindowRect(GetDesktopWindow(), &rcdesktop);
ShowCursor(TRUE);
int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// SetWindowPos to the center of the screen
SetWindowPos(hParent, NULL, X, Y, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Set new window style FS -> Windowed
SetWindowLong(hParent, GWL_STYLE, WS_OVERLAPPEDWINDOW);
// Eventually show the window!
EmuWindow::Show();
}
else
{
// Get into fullscreen
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
// Desktop -> FullScreen
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = w_fs;
dmScreenSettings.dmPelsHeight = h_fs;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
return;
// Set new window style -> PopUp
SetWindowLong(hParent, GWL_STYLE, WS_POPUP);
g_Config.bFullscreen = true;
ShowCursor(FALSE);
// SetWindowPos to the upper-left corner of the screen
SetWindowPos(hParent, NULL, 0, 0, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Eventually show the window!
EmuWindow::Show();
}
}
}
void Show()
{
ShowWindow(m_hWnd, SW_SHOW);
BringWindowToTop(m_hWnd);
UpdateWindow(m_hWnd);
}
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title)
{
return OpenWindow(hParent, hInstance, 640, 480, title);
}
void Close()
{
if (!m_hParent)
DestroyWindow(m_hWnd);
UnregisterClass(m_szClassName, m_hInstance);
}
// ------------------------------------------
// Set the size of the child or main window
// ------------------------------------------
void SetSize(int width, int height)
{
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
// Move and resize the window
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
MoveWindow(m_hWnd, rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top, TRUE);
}
} // EmuWindow

View File

@ -1,39 +1,39 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WIN32_H_
#define _WIN32_H_
#pragma once
#include "stdafx.h"
namespace EmuWindow
{
extern int g_winstyle;
HWND GetWnd();
HWND GetParentWnd();
HWND GetChildParentWnd();
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title);
void Show();
void Close();
void ToggleFullscreen(HWND hParent);
void SetSize(int displayWidth, int displayHeight);
}
#endif // _WIN32_H_
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WIN32_H_
#define _WIN32_H_
#pragma once
#include "stdafx.h"
namespace EmuWindow
{
extern int g_winstyle;
HWND GetWnd();
HWND GetParentWnd();
HWND GetChildParentWnd();
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title);
void Show();
void Close();
void ToggleFullscreen(HWND hParent);
void SetSize(int displayWidth, int displayHeight);
}
#endif // _WIN32_H_

View File

@ -1,96 +1,96 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "XFMemLoader.h"
#include "CPMemLoader.h"
#include "Clipper.h"
XFRegisters xfregs;
void InitXFMemory()
{
memset(&xfregs, 0, sizeof(xfregs));
}
void XFWritten(u32 transferSize, u32 baseAddress)
{
u32 topAddress = baseAddress + transferSize;
if (baseAddress <= 0x1026 && topAddress >= 0x1020)
Clipper::SetViewOffset();
// fix lights so invalid values don't trash the lighting computations
if (baseAddress <= 0x067f && topAddress >= 0x0604)
{
u32* x = xfregs.lights;
// go through all lights
for (int light = 0; light < 8; light++)
{
// skip to floating point values
x += 4;
for (int i = 0; i < 12; i++)
{
u32 xVal = *x;
// if the exponent is 255 then the number is inf or nan
if ((xVal & 0x7f800000) == 0x7f800000)
*x = 0;
x++;
}
}
}
}
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
u32 size = transferSize;
// do not allow writes past registers
if (baseAddress + transferSize > 0x1058)
{
INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize);
if (baseAddress >= 0x1058)
size = 0;
else
size = 0x1058 - baseAddress;
}
if (size > 0) {
memcpy_gc( &((u32*)&xfregs)[baseAddress], pData, size * 4);
XFWritten(transferSize, baseAddress);
}
}
void LoadIndexedXF(u32 val, int array)
{
int index = val >> 16;
int address = val & 0xFFF; //check mask
int size = ((val >> 12) & 0xF) + 1;
//load stuff from array to address in xf mem
u32 *pData = (u32*)g_VideoInitialize.pGetMemoryPointer(arraybases[array] + arraystrides[array]*index);
LoadXFReg(size, address, pData);
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "XFMemLoader.h"
#include "CPMemLoader.h"
#include "Clipper.h"
XFRegisters xfregs;
void InitXFMemory()
{
memset(&xfregs, 0, sizeof(xfregs));
}
void XFWritten(u32 transferSize, u32 baseAddress)
{
u32 topAddress = baseAddress + transferSize;
if (baseAddress <= 0x1026 && topAddress >= 0x1020)
Clipper::SetViewOffset();
// fix lights so invalid values don't trash the lighting computations
if (baseAddress <= 0x067f && topAddress >= 0x0604)
{
u32* x = xfregs.lights;
// go through all lights
for (int light = 0; light < 8; light++)
{
// skip to floating point values
x += 4;
for (int i = 0; i < 12; i++)
{
u32 xVal = *x;
// if the exponent is 255 then the number is inf or nan
if ((xVal & 0x7f800000) == 0x7f800000)
*x = 0;
x++;
}
}
}
}
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
u32 size = transferSize;
// do not allow writes past registers
if (baseAddress + transferSize > 0x1058)
{
INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize);
if (baseAddress >= 0x1058)
size = 0;
else
size = 0x1058 - baseAddress;
}
if (size > 0) {
memcpy_gc( &((u32*)&xfregs)[baseAddress], pData, size * 4);
XFWritten(transferSize, baseAddress);
}
}
void LoadIndexedXF(u32 val, int array)
{
int index = val >> 16;
int address = val & 0xFFF; //check mask
int size = ((val >> 12) & 0xF) + 1;
//load stuff from array to address in xf mem
u32 *pData = (u32*)g_VideoInitialize.pGetMemoryPointer(arraybases[array] + arraystrides[array]*index);
LoadXFReg(size, address, pData);
}

View File

@ -1,211 +1,211 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "pluginspecs_video.h"
#include "CommandProcessor.h"
#include "OpcodeDecoder.h"
#include "VideoConfig.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Clipper.h"
#include "Rasterizer.h"
#include "Renderer.h"
#include "../../../Core/VideoCommon/Src/LookUpTables.h"
#include "HwRasterizer.h"
#include "LogManager.h"
#include "EfbInterface.h"
#include "DebugUtil.h"
PLUGIN_GLOBALS* globals = NULL;
SVideoInitialize g_VideoInitialize;
void GetDllInfo (PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_VIDEO;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin Software Renderer");
#else
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
}
void DllDebugger(HWND _hParent, bool Show)
{
}
void DllConfig(HWND _hParent)
{
}
void Initialize(void *init)
{
SVideoInitialize *_pVideoInitialize = (SVideoInitialize*)init;
g_VideoInitialize = *_pVideoInitialize;
g_Config.Load();
InitBPMemory();
InitXFMemory();
CommandProcessor::Init();
PixelEngine::Init();
OpcodeDecoder::Init();
Clipper::Init();
Rasterizer::Init();
HwRasterizer::Init();
Renderer::Init(_pVideoInitialize);
DebugUtil::Init();
}
void DoState(unsigned char **ptr, int mode)
{
}
void EmuStateChange(PLUGIN_EMUSTATE newState)
{
}
void Shutdown(void)
{
Renderer::Shutdown();
OpenGL_Shutdown();
}
// This is called after Video_Initialize() from the Core
void Video_Prepare(void)
{
Renderer::Prepare();
INFO_LOG(VIDEO, "Video plugin initialized.");
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_EndField()
{
}
u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case POKE_Z:
break;
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
case POKE_COLOR:
break;
}
return value;
}
void Video_Screenshot(const char *_szFilename)
{
}
// -------------------------------
// Enter and exit the video loop
// -------------------------------
void Video_EnterLoop()
{
Fifo_EnterLoop(g_VideoInitialize);
}
void Video_ExitLoop()
{
Fifo_ExitLoop();
}
void Video_AddMessage(const char* pstr, u32 milliseconds)
{
}
void Video_SetRendering(bool bEnabled)
{
Fifo_SetRendering(bEnabled);
}
void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address)
{
CommandProcessor::Read16(_rReturnValue, _Address);
}
void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address)
{
CommandProcessor::Write16(_Data, _Address);
}
void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address)
{
PixelEngine::Read16(_rReturnValue, _Address);
}
void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address)
{
PixelEngine::Write16(_Data, _Address);
}
void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address)
{
PixelEngine::Write32(_Data, _Address);
}
void Video_GatherPipeBursted(void)
{
CommandProcessor::GatherPipeBursted();
}
void Video_WaitForFrameFinish(void)
{
}
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "pluginspecs_video.h"
#include "CommandProcessor.h"
#include "OpcodeDecoder.h"
#include "VideoConfig.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Clipper.h"
#include "Rasterizer.h"
#include "Renderer.h"
#include "../../../Core/VideoCommon/Src/LookUpTables.h"
#include "HwRasterizer.h"
#include "LogManager.h"
#include "EfbInterface.h"
#include "DebugUtil.h"
PLUGIN_GLOBALS* globals = NULL;
SVideoInitialize g_VideoInitialize;
void GetDllInfo (PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_VIDEO;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin Software Renderer");
#else
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
}
void DllDebugger(HWND _hParent, bool Show)
{
}
void DllConfig(HWND _hParent)
{
}
void Initialize(void *init)
{
SVideoInitialize *_pVideoInitialize = (SVideoInitialize*)init;
g_VideoInitialize = *_pVideoInitialize;
g_Config.Load();
InitBPMemory();
InitXFMemory();
CommandProcessor::Init();
PixelEngine::Init();
OpcodeDecoder::Init();
Clipper::Init();
Rasterizer::Init();
HwRasterizer::Init();
Renderer::Init(_pVideoInitialize);
DebugUtil::Init();
}
void DoState(unsigned char **ptr, int mode)
{
}
void EmuStateChange(PLUGIN_EMUSTATE newState)
{
}
void Shutdown(void)
{
Renderer::Shutdown();
OpenGL_Shutdown();
}
// This is called after Video_Initialize() from the Core
void Video_Prepare(void)
{
Renderer::Prepare();
INFO_LOG(VIDEO, "Video plugin initialized.");
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_EndField()
{
}
u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case POKE_Z:
break;
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
case POKE_COLOR:
break;
}
return value;
}
void Video_Screenshot(const char *_szFilename)
{
}
// -------------------------------
// Enter and exit the video loop
// -------------------------------
void Video_EnterLoop()
{
Fifo_EnterLoop(g_VideoInitialize);
}
void Video_ExitLoop()
{
Fifo_ExitLoop();
}
void Video_AddMessage(const char* pstr, u32 milliseconds)
{
}
void Video_SetRendering(bool bEnabled)
{
Fifo_SetRendering(bEnabled);
}
void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address)
{
CommandProcessor::Read16(_rReturnValue, _Address);
}
void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address)
{
CommandProcessor::Write16(_Data, _Address);
}
void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address)
{
PixelEngine::Read16(_rReturnValue, _Address);
}
void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address)
{
PixelEngine::Write16(_Data, _Address);
}
void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address)
{
PixelEngine::Write32(_Data, _Address);
}
void Video_GatherPipeBursted(void)
{
CommandProcessor::GatherPipeBursted();
}
void Video_WaitForFrameFinish(void)
{
}

View File

@ -1,25 +1,25 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef MAIN_H
#define MAIN_H
#include "pluginspecs_video.h"
extern SVideoInitialize g_VideoInitialize;
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef MAIN_H
#define MAIN_H
#include "pluginspecs_video.h"
extern SVideoInitialize g_VideoInitialize;
#endif

View File

@ -1,18 +1,18 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "stdafx.h"
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "stdafx.h"

View File

@ -1,26 +1,26 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#define _WIN32_WINNT 0x501
#ifndef _WIN32_IE
#define _WIN32_IE 0x0500 // Default value is 0x0400
#endif
#include <tchar.h>
#include <windows.h>
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#define _WIN32_WINNT 0x501
#ifndef _WIN32_IE
#define _WIN32_IE 0x0500 // Default value is 0x0400
#endif
#include <tchar.h>
#include <windows.h>