Adding software rendering plugin. This is aimed at accurate emulation, not fast. Its more like a debugging tool than actually useful.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4407 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
ab8d182c37
commit
9b16c36014
|
@ -191,6 +191,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxCore28", "..\Externals\wx
|
|||
{1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE} = {1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Plugin_VideoSoftware", "Plugins\Plugin_VideoSoftware\Plugin_VideoSoftware.vcproj", "{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -672,6 +674,18 @@ Global
|
|||
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|Win32.Build.0 = Release|Win32
|
||||
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|x64.ActiveCfg = Release|x64
|
||||
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|x64.Build.0 = Release|x64
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|Win32.ActiveCfg = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|Win32.Build.0 = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|x64.ActiveCfg = Debug|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|Win32.ActiveCfg = Release|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|Win32.Build.0 = Release|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|x64.ActiveCfg = Release|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|Win32.Build.0 = Release|Win32
|
||||
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -0,0 +1,481 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="Plugin_VideoSoftware"
|
||||
ProjectGUID="{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}"
|
||||
RootNamespace="Plugin_VideoSoftware"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
||||
MinimalRebuild="false"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
PrecompiledHeaderFile="$(IntDir)/VideoSoftware.pch"
|
||||
AssemblerListingLocation="$(IntDir)\"
|
||||
ProgramDataBaseFileName="$(IntDir)\"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
IgnoreImportLibrary="false"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib common.lib wxbase28ud.lib wxmsw28ud_core.lib"
|
||||
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoSWD.dll"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
||||
SubSystem="0"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew"
|
||||
PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;_WIN32;PLUGIN_VIDEOSOFTWARE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="stdafx.h"
|
||||
PrecompiledHeaderFile="$(IntDir)/VideoSoftware.pch"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="stdafx.h"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
IgnoreImportLibrary="false"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib libjpeg.lib common.lib wxbase28u.lib wxmsw28u_core.lib"
|
||||
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoSW.dll"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
||||
IgnoreAllDefaultLibraries="false"
|
||||
IgnoreDefaultLibraryNames="msvcprt.lib;libcmt.lib"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Common"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\ImageWrite.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\memcpy_amd.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\NativeVertexWriter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\NativeVertexWriter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\Plugin_VideoOGL\Src\rasterfont.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\TextureDecoder.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Color.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Normal.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Position.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VertexLoader_Position.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_TextCoord.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VideoCommon.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Win32"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\Src\Win32.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Win32.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\Src\BPMemLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\BPMemLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Clipper.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Clipper.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CommandProcessor.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CommandProcessor.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CPMemLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\CPMemLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\DebugUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\DebugUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\EfbCopy.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\EfbCopy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\EfbInterface.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\EfbInterface.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GLUtil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\GLUtil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HwRasterizer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HwRasterizer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\main.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\main.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\NativeVertexFormat.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\OpcodeDecoder.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\OpcodeDecoder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PixelEngine.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\PixelEngine.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Rasterizer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Rasterizer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Renderer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Renderer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\SetupUnit.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\SetupUnit.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Statistics.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Statistics.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Tev.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Tev.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TextureEncoder.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TextureEncoder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TextureSampler.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TextureSampler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TransformUnit.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\TransformUnit.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VertexFormatConverter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VertexFormatConverter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VertexLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VertexLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VideoConfig.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\VideoConfig.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\XFMemLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\XFMemLoader.h"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,149 @@
|
|||
// 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: // Load a Texture Look Up Table
|
||||
case BPMEM_LOADTLUT1:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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 _BPMEMLOADER_H_
|
||||
#define _BPMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../../../Core/VideoCommon/Src/BPMemory.h"
|
||||
|
||||
void InitBPMemory();
|
||||
|
||||
#endif
|
|
@ -0,0 +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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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 _CPMEMLOADER_H_
|
||||
#define _CPMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "../../../Core/VideoCommon/Src/CPMemory.h"
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,300 @@
|
|||
// 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
|
||||
{
|
||||
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;
|
||||
float* pos = v->projectedPosition;
|
||||
if (pos[3] - pos[0] < 0) cmask |= CLIP_POS_X_BIT;
|
||||
if (pos[0] + pos[3] < 0) cmask |= CLIP_NEG_X_BIT;
|
||||
if (pos[3] - pos[1] < 0) cmask |= CLIP_POS_Y_BIT;
|
||||
if (pos[1] + pos[3] < 0) cmask |= CLIP_NEG_Y_BIT;
|
||||
if (pos[3] * pos[2] > 0) cmask |= CLIP_POS_Z_BIT;
|
||||
if (pos[2] + pos[3] < 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[0] * A + Vertices[I]->projectedPosition[1] * B + Vertices[I]->projectedPosition[2] * C + Vertices[I]->projectedPosition[3] * 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; \
|
||||
int i; \
|
||||
\
|
||||
inlist[n] = inlist[0]; \
|
||||
for (i = 1; i <= n; i++) { \
|
||||
int idx = inlist[i]; \
|
||||
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; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
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 idx = 0; idx < 3; idx += 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 i = 3; i < n; ++i) {
|
||||
indices[numIndices++] = inlist[0];
|
||||
indices[numIndices++] = inlist[i - 1];
|
||||
indices[numIndices++] = inlist[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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[0];
|
||||
float x1 = v1->projectedPosition[0];
|
||||
float x2 = v2->projectedPosition[0];
|
||||
float y1 = v1->projectedPosition[1];
|
||||
float y0 = v0->projectedPosition[1];
|
||||
float y2 = v2->projectedPosition[1];
|
||||
float w0 = v0->projectedPosition[3];
|
||||
float w1 = v1->projectedPosition[3];
|
||||
float w2 = v2->projectedPosition[3];
|
||||
|
||||
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)
|
||||
{
|
||||
float *projected = vertex->projectedPosition;
|
||||
float *screen = vertex->screenPosition;
|
||||
|
||||
float wInverse = 1.0f/projected[3];
|
||||
screen[0] = projected[0] * wInverse * xfregs.viewport.wd + m_ViewOffset[0];
|
||||
screen[1] = projected[1] * wInverse * xfregs.viewport.ht + m_ViewOffset[1];
|
||||
screen[2] = projected[2] * wInverse + m_ViewOffset[2];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// 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 _CLIPPER_H_
|
||||
#define _CLIPPER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
|
||||
namespace Clipper
|
||||
{
|
||||
void Init();
|
||||
|
||||
void SetViewOffset();
|
||||
|
||||
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
|
||||
|
||||
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
|
||||
|
||||
void PerspectiveDivide(OutputVertexData *vertex);
|
||||
|
||||
static float m_ViewOffset[3];
|
||||
|
||||
static OutputVertexData ClippedVertices[18];
|
||||
static OutputVertexData *Vertices[21];
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +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/
|
||||
|
||||
#include "Common.h"
|
||||
#include "pluginspecs_video.h"
|
||||
|
||||
#include "CommandProcessor.h"
|
||||
#include "OpcodeDecoder.h"
|
||||
#include "main.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
|
||||
u8* g_pVideoData; // data reader uses this as the read pointer
|
||||
|
||||
|
||||
namespace CommandProcessor
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
GATHER_PIPE_SIZE = 32,
|
||||
INT_CAUSE_CP = 0x800
|
||||
};
|
||||
|
||||
// STATE_TO_SAVE
|
||||
// variables
|
||||
|
||||
const int commandBufferSize = 4 * 1024;
|
||||
const int commandBufferCopySize = 32;
|
||||
const int maxCommandBufferWrite = commandBufferSize - commandBufferCopySize;
|
||||
u8 commandBuffer[commandBufferSize];
|
||||
u32 readPos;
|
||||
u32 writePos;
|
||||
|
||||
CPReg cpreg; // shared between gfx and emulator thread
|
||||
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(cpreg);
|
||||
}
|
||||
|
||||
// function
|
||||
void UpdateFifoRegister();
|
||||
void UpdateInterrupts();
|
||||
|
||||
// does it matter that there is no synchronization between threads during writes?
|
||||
inline void WriteLow (u32& _reg, u16 lowbits) {_reg = (_reg & 0xFFFF0000) | lowbits;}
|
||||
inline void WriteHigh(u32& _reg, u16 highbits) {_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16);}
|
||||
//inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::SyncInterlockedExchange((LONG*)&_reg,(_reg & 0xFFFF0000) | lowbits);}
|
||||
//inline void WriteHigh(volatile u32& _reg, u16 highbits) {Common::SyncInterlockedExchange((LONG*)&_reg,(_reg & 0x0000FFFF) | ((u32)highbits << 16));}
|
||||
|
||||
inline u16 ReadLow (u32 _reg) {return (u16)(_reg & 0xFFFF);}
|
||||
inline u16 ReadHigh (u32 _reg) {return (u16)(_reg >> 16);}
|
||||
|
||||
int et_UpdateInterrupts;
|
||||
|
||||
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
||||
{
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
cpreg.status.Hex = 0;
|
||||
cpreg.status.CommandIdle = 1;
|
||||
cpreg.status.ReadIdle = 1;
|
||||
|
||||
cpreg.ctrl.Hex = 0;
|
||||
cpreg.clear.Hex = 0;
|
||||
|
||||
cpreg.bboxleft = 0;
|
||||
cpreg.bboxtop = 0;
|
||||
cpreg.bboxright = 0;
|
||||
cpreg.bboxbottom = 0;
|
||||
|
||||
cpreg.token = 0;
|
||||
|
||||
et_UpdateInterrupts = g_VideoInitialize.pRegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||
|
||||
// internal buffer position
|
||||
readPos = 0;
|
||||
writePos = 0;
|
||||
|
||||
g_pVideoData = 0;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// delete fifo.sync;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
||||
|
||||
u32 regAddr = (_Address & 0xFFF) >> 1;
|
||||
if (regAddr < 0x20)
|
||||
_rReturnValue = ((u16*)&cpreg)[regAddr];
|
||||
else
|
||||
_rReturnValue = 0;
|
||||
}
|
||||
|
||||
void RunGpu()
|
||||
{
|
||||
if (!g_VideoInitialize.bUseDualCore)
|
||||
{
|
||||
// We are going to do FP math on the main thread so have to save the current state
|
||||
SaveSSEState();
|
||||
LoadDefaultSSEState();
|
||||
|
||||
// run the opcode decoder
|
||||
RunBuffer();
|
||||
|
||||
LoadSSEState();
|
||||
}
|
||||
}
|
||||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address);
|
||||
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER:
|
||||
{
|
||||
UCPStatusReg tmpStatus(_Value);
|
||||
|
||||
if (cpreg.status.Breakpoint != tmpStatus.Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR,"Set breakpoint status by writing to STATUS_REGISTER");
|
||||
|
||||
cpreg.status.Hex = _Value;
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t write to STATUS_REGISTER : %04x", _Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CTRL_REGISTER:
|
||||
{
|
||||
cpreg.ctrl.Hex = _Value;
|
||||
|
||||
// clear breakpoint if BPEnable and CPIntEnable are 0
|
||||
if (!cpreg.ctrl.BPEnable) {
|
||||
if (!cpreg.ctrl.CPIntEnable) {
|
||||
cpreg.status.Breakpoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || CPIntEnable %s | OvF %s | UndF %s"
|
||||
, cpreg.ctrl.GPReadEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.GPLinkEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.BPEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.CPIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoOverflowIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoUnderflowIntEnable ? "ON" : "OFF"
|
||||
);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case CLEAR_REGISTER:
|
||||
{
|
||||
UCPClearReg tmpClear(_Value);
|
||||
|
||||
if (tmpClear.ClearFifoOverflow)
|
||||
cpreg.status.OverflowHiWatermark = 0;
|
||||
if (tmpClear.ClearFifoUnderflow)
|
||||
cpreg.status.UnderflowLoWatermark = 0;
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x",_Value);
|
||||
}
|
||||
break;
|
||||
|
||||
// Fifo Registers
|
||||
case FIFO_TOKEN_REGISTER:
|
||||
cpreg.token = _Value;
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_TOKEN_REGISTER : %04x", _Value);
|
||||
break;
|
||||
|
||||
case FIFO_BASE_LO:
|
||||
WriteLow ((u32 &)cpreg.fifobase, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_LO. FIFO base is : %08x", cpreg.fifobase);
|
||||
break;
|
||||
case FIFO_BASE_HI:
|
||||
WriteHigh((u32 &)cpreg.fifobase, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_HI. FIFO base is : %08x", cpreg.fifobase);
|
||||
break;
|
||||
case FIFO_END_LO:
|
||||
WriteLow ((u32 &)cpreg.fifoend, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_LO. FIFO end is : %08x", cpreg.fifoend);
|
||||
break;
|
||||
case FIFO_END_HI:
|
||||
WriteHigh((u32 &)cpreg.fifoend, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_HI. FIFO end is : %08x", cpreg.fifoend);
|
||||
break;
|
||||
|
||||
case FIFO_WRITE_POINTER_LO:
|
||||
WriteLow ((u32 &)cpreg.writeptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_LO. write ptr is : %08x", cpreg.writeptr);
|
||||
break;
|
||||
case FIFO_WRITE_POINTER_HI:
|
||||
WriteHigh ((u32 &)cpreg.writeptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_HI. write ptr is : %08x", cpreg.writeptr);
|
||||
break;
|
||||
case FIFO_READ_POINTER_LO:
|
||||
WriteLow ((u32 &)cpreg.readptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_LO. read ptr is : %08x", cpreg.readptr);
|
||||
break;
|
||||
case FIFO_READ_POINTER_HI:
|
||||
WriteHigh ((u32 &)cpreg.readptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI. read ptr is : %08x", cpreg.readptr);
|
||||
break;
|
||||
|
||||
case FIFO_HI_WATERMARK_LO:
|
||||
WriteLow ((u32 &)cpreg.hiwatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_LO. hiwatermark is : %08x", cpreg.hiwatermark);
|
||||
break;
|
||||
case FIFO_HI_WATERMARK_HI:
|
||||
WriteHigh ((u32 &)cpreg.hiwatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_HI. hiwatermark is : %08x", cpreg.hiwatermark);
|
||||
break;
|
||||
case FIFO_LO_WATERMARK_LO:
|
||||
WriteLow ((u32 &)cpreg.lowatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_LO. lowatermark is : %08x", cpreg.lowatermark);
|
||||
break;
|
||||
case FIFO_LO_WATERMARK_HI:
|
||||
WriteHigh ((u32 &)cpreg.lowatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_HI. lowatermark is : %08x", cpreg.lowatermark);
|
||||
break;
|
||||
|
||||
case FIFO_BP_LO:
|
||||
WriteLow ((u32 &)cpreg.breakpt, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_LO. breakpt is : %08x", cpreg.breakpt);
|
||||
break;
|
||||
case FIFO_BP_HI:
|
||||
WriteHigh ((u32 &)cpreg.breakpt, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_HI. breakpt is : %08x", cpreg.breakpt);
|
||||
break;
|
||||
|
||||
// Super monkey try to overwrite CPReadWriteDistance by an old saved RWD value. Which is lame for us.
|
||||
// hack: We have to force CPU to think fifo is alway empty and on idle.
|
||||
// When we fall here CPReadWriteDistance should be always null and the game should always want to overwrite it by 0.
|
||||
// So, we can skip it.
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
WriteLow ((u32 &)cpreg.rwdistance, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_LO. rwdistance is : %08x", cpreg.rwdistance);
|
||||
break;
|
||||
case FIFO_RW_DISTANCE_HI:
|
||||
WriteHigh ((u32 &)cpreg.rwdistance, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_HI. rwdistance is : %08x", cpreg.rwdistance);
|
||||
break;
|
||||
}
|
||||
|
||||
RunGpu();
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
_rReturnValue = 0;
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Read32 from CommandProccessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void Write32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Write32 at CommandProccessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void STACKALIGN GatherPipeBursted()
|
||||
{
|
||||
if (cpreg.ctrl.GPLinkEnable)
|
||||
{
|
||||
cpreg.writeptr += GATHER_PIPE_SIZE;
|
||||
if (cpreg.writeptr >= (cpreg.fifoend & 0xFFFFFFE0))
|
||||
cpreg.writeptr = cpreg.fifobase;
|
||||
|
||||
// the read/write pointers will be managed in RunGpu which will read the current fifo and
|
||||
// send as much data as is available and the plugin can take
|
||||
// this will have the cost of copying data to the plugin fifo buffer in the main thread
|
||||
}
|
||||
|
||||
RunGpu();
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BPEnable;
|
||||
bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable;
|
||||
bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable;
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\tUpdate Interrupts");
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\tCPIntEnable %s | BP %s | OvF %s | UndF %s"
|
||||
, cpreg.ctrl.CPIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.BPEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoOverflowIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoUnderflowIntEnable ? "ON" : "OFF"
|
||||
);
|
||||
|
||||
if (cpreg.ctrl.CPIntEnable && (bpInt || ovfInt || undfInt))
|
||||
{
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"Interrupt cleared");
|
||||
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, false);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterruptsFromVideoPlugin()
|
||||
{
|
||||
g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0);
|
||||
}
|
||||
|
||||
void ReadFifo()
|
||||
{
|
||||
bool updateInterrupts = false;
|
||||
|
||||
cpreg.status.ReadIdle = 0;
|
||||
|
||||
// update rwdistance
|
||||
u32 writePtr = cpreg.writeptr;
|
||||
if (cpreg.readptr <= writePtr)
|
||||
cpreg.rwdistance = writePtr - cpreg.readptr;
|
||||
else
|
||||
cpreg.rwdistance = ((cpreg.fifoend & 0xFFFFFFE0) - cpreg.fifobase) - (cpreg.readptr - writePtr);
|
||||
|
||||
// overflow check
|
||||
cpreg.status.OverflowHiWatermark = cpreg.rwdistance < cpreg.hiwatermark?0:1;
|
||||
updateInterrupts |= cpreg.ctrl.FifoOverflowIntEnable && cpreg.status.OverflowHiWatermark;
|
||||
|
||||
// read from fifo
|
||||
u8 *ptr = g_VideoInitialize.pGetMemoryPointer(cpreg.readptr);
|
||||
|
||||
u32 readptr = cpreg.readptr;
|
||||
u32 distance = cpreg.rwdistance;
|
||||
|
||||
while (distance >= commandBufferCopySize && !cpreg.status.Breakpoint && writePos < maxCommandBufferWrite)
|
||||
{
|
||||
// check for breakpoint
|
||||
// todo - check if this is precise enough
|
||||
if (cpreg.ctrl.BPEnable && (cpreg.breakpt & 0xFFFFFFE0) == (readptr & 0xFFFFFFE0))
|
||||
{
|
||||
cpreg.status.Breakpoint = 1;
|
||||
DEBUG_LOG(VIDEO,"Hit breakpoint at %x", readptr);
|
||||
if (cpreg.ctrl.CPIntEnable)
|
||||
updateInterrupts = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy to buffer
|
||||
memcpy(&commandBuffer[writePos], ptr, commandBufferCopySize);
|
||||
writePos += commandBufferCopySize;
|
||||
ptr += commandBufferCopySize;
|
||||
readptr += commandBufferCopySize;
|
||||
distance -= commandBufferCopySize;
|
||||
}
|
||||
|
||||
if (readptr >= (cpreg.fifoend & 0xFFFFFFE0))
|
||||
{
|
||||
readptr = cpreg.fifobase;
|
||||
ptr = g_VideoInitialize.pGetMemoryPointer(readptr);
|
||||
}
|
||||
}
|
||||
|
||||
// lock read pointer until rw distance is updated?
|
||||
cpreg.readptr = readptr;
|
||||
cpreg.rwdistance = distance;
|
||||
|
||||
// underflow check
|
||||
cpreg.status.UnderflowLoWatermark = cpreg.rwdistance > cpreg.lowatermark?0:1;
|
||||
updateInterrupts |= cpreg.ctrl.FifoUnderflowIntEnable && cpreg.status.UnderflowLoWatermark;
|
||||
|
||||
cpreg.status.ReadIdle = 1;
|
||||
|
||||
if (updateInterrupts)
|
||||
UpdateInterruptsFromVideoPlugin();
|
||||
}
|
||||
|
||||
bool RunBuffer()
|
||||
{
|
||||
// fifo is read 32 bytes at a time
|
||||
// read fifo data to internal buffer
|
||||
if (cpreg.ctrl.GPReadEnable)
|
||||
ReadFifo();
|
||||
|
||||
g_pVideoData = &commandBuffer[readPos];
|
||||
|
||||
u32 availableBytes = writePos - readPos;
|
||||
_dbg_assert_(VIDEO, writePos >= readPos);
|
||||
|
||||
while (OpcodeDecoder::CommandRunnable(availableBytes))
|
||||
{
|
||||
cpreg.status.CommandIdle = 0;
|
||||
|
||||
OpcodeDecoder::Run(availableBytes);
|
||||
|
||||
// if data was read by the opcode decoder then the video data pointer changed
|
||||
readPos = g_pVideoData - &commandBuffer[0];
|
||||
_dbg_assert_(VIDEO, writePos >= readPos);
|
||||
availableBytes = writePos - readPos;
|
||||
}
|
||||
|
||||
cpreg.status.CommandIdle = 1;
|
||||
|
||||
_dbg_assert_(VIDEO, writePos >= readPos);
|
||||
|
||||
bool ranDecoder = false;
|
||||
|
||||
// move data remaing in command buffer
|
||||
if (readPos > 0)
|
||||
{
|
||||
memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes);
|
||||
writePos -= readPos;
|
||||
readPos = 0;
|
||||
|
||||
ranDecoder = true;
|
||||
}
|
||||
|
||||
return ranDecoder;
|
||||
}
|
||||
|
||||
} // end of namespace CommandProcessor
|
|
@ -0,0 +1,153 @@
|
|||
// 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;
|
||||
|
||||
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 CPIntEnable : 1;
|
||||
unsigned FifoOverflowIntEnable : 1;
|
||||
unsigned FifoUnderflowIntEnable : 1;
|
||||
unsigned GPLinkEnable : 1;
|
||||
unsigned BPEnable : 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();
|
||||
|
||||
// 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();
|
||||
void UpdateInterruptsFromVideoPlugin();
|
||||
|
||||
|
||||
} // end of namespace CommandProcessor
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,177 @@
|
|||
// 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 "../../../Core/VideoCommon/Src/ImageWrite.h"
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
|
||||
u32 skipFrames = 0;
|
||||
|
||||
bool SaveTexture(const char* filename, u32 texmap, int width, int height)
|
||||
{
|
||||
u8 *data = new u8[width * height * 4];
|
||||
|
||||
GetTextureBGRA(data, texmap, width, height);
|
||||
|
||||
bool result = SaveTGA(filename, width, height, data);
|
||||
|
||||
delete []data;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SaveTexture(const char* filename, u32 texmap)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
|
||||
SaveTexture(filename, texmap, ti0.width, ti0.height);
|
||||
}
|
||||
|
||||
void GetTextureBGRA(u8 *dst, u32 texmap, int width, int height)
|
||||
{
|
||||
u8 sample[4];
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++) {
|
||||
TextureSampler::Sample((float)x, (float)y, 0, texmap, sample);
|
||||
// rgba to bgra
|
||||
*(dst++) = sample[2];
|
||||
*(dst++) = sample[1];
|
||||
*(dst++) = sample[0];
|
||||
*(dst++) = sample[3];
|
||||
}
|
||||
}
|
||||
|
||||
void DumpActiveTextures()
|
||||
{
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
SaveTexture(StringFromFormat("%s/tar%i_ind%i_map%i.tga", FULL_DUMP_TEXTURES_DIR, stats.thisFrame.numDrawnObjects, stageNum, texmap).c_str(), texmap);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
SaveTexture(StringFromFormat("%s/tar%i_stage%i_map%i.tga", FULL_DUMP_TEXTURES_DIR, stats.thisFrame.numDrawnObjects, stageNum, texmap).c_str(), texmap);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
bool result = 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;
|
||||
}
|
||||
|
||||
bool result = SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
|
||||
|
||||
delete []data;
|
||||
}
|
||||
|
||||
void OnObjectBegin()
|
||||
{
|
||||
if (!g_SkipFrame)
|
||||
{
|
||||
if (g_Config.bDumpTextures)
|
||||
DumpActiveTextures();
|
||||
|
||||
if (g_Config.bHwRasterizer)
|
||||
HwRasterizer::BeginTriangles();
|
||||
}
|
||||
}
|
||||
|
||||
void OnObjectEnd()
|
||||
{
|
||||
if (!g_SkipFrame)
|
||||
{
|
||||
if (g_Config.bDumpObjects)
|
||||
DumpEfb(StringFromFormat("%s/object%i.tga", FULL_FRAMES_DIR, stats.thisFrame.numDrawnObjects).c_str());
|
||||
|
||||
if (g_Config.bHwRasterizer)
|
||||
HwRasterizer::EndTriangles();
|
||||
|
||||
stats.thisFrame.numDrawnObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
void OnFrameEnd()
|
||||
{
|
||||
if (!g_SkipFrame)
|
||||
{
|
||||
if (g_Config.bDumpFrames)
|
||||
{
|
||||
DumpEfb(StringFromFormat("%s/frame%i_color.tga", FULL_FRAMES_DIR, stats.frameCount).c_str());
|
||||
DumpDepth(StringFromFormat("%s/frame%i_depth.tga", FULL_FRAMES_DIR, stats.frameCount).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
g_SkipFrame = skipFrames > 0;
|
||||
skipFrames = g_SkipFrame?(skipFrames-1):g_Config.nFrameSkip;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// 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 _DEBUGUTIL_H
|
||||
#define _DEBUGUTIL_H
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
void GetTextureBGRA(u8 *dst, u32 texmap, int width, int height);
|
||||
|
||||
void DumpActiveTextures();
|
||||
|
||||
void OnObjectBegin();
|
||||
void OnObjectEnd();
|
||||
|
||||
void OnFrameEnd();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,99 @@
|
|||
// 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"
|
||||
|
||||
|
||||
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_SkipFrame)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// 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_COPY_H_
|
||||
#define _EFB_COPY_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace EfbCopy
|
||||
{
|
||||
// Copy the EFB to RAM as a texture format or XFB
|
||||
// Clear the EFB if needed
|
||||
void CopyEfb();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,545 @@
|
|||
// 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 "EfbInterface.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "../../../Core/VideoCommon/Src/LookUpTables.h"
|
||||
#include "PixelEngine.h"
|
||||
|
||||
|
||||
u8 efb[EFB_WIDTH*EFB_HEIGHT*6];
|
||||
|
||||
|
||||
namespace EfbInterface
|
||||
{
|
||||
u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4];
|
||||
|
||||
inline u32 GetColorOffset(u16 x, u16 y)
|
||||
{
|
||||
return (x + y * EFB_WIDTH) * 3;
|
||||
}
|
||||
|
||||
inline u32 GetDepthOffset(u16 x, u16 y)
|
||||
{
|
||||
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
|
||||
}
|
||||
|
||||
void SetPixelAlphaOnly(u32 offset, u8 a)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
// do nothing
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 a32 = a;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff03ffff;
|
||||
val |= (a32 << 16) & 0xfc0000;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColorOnly(u32 offset, u8 *rgb)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xfffc0000;
|
||||
val |= (src >> 2) & 0x3f;
|
||||
val |= (src >> 4) & 0xfc0;
|
||||
val |= (src >> 6) & 0x3f000;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelAlphaColor(u32 offset, u8 *color)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= (src >> 2) & 0x3f;
|
||||
val |= (src >> 4) & 0xfc0;
|
||||
val |= (src >> 6) & 0x3f000;
|
||||
val |= (src >> 8) & 0xfc0000;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void GetPixelColor(u32 offset, u8 *color)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
u32 *dst = (u32*)color;
|
||||
u32 val = 0xff000000 | (src & 0x00ffffff);
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
color[0] = Convert6To8(src & 0x3f);
|
||||
color[1] = Convert6To8((src >> 6) & 0x3f);
|
||||
color[2] = Convert6To8((src >> 12) & 0x3f);
|
||||
color[3] = Convert6To8((src >> 18) & 0x3f);
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
u32 *dst = (u32*)color;
|
||||
u32 val = 0xff000000 | (src & 0x00ffffff);
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelDepth(u32 offset, u32 depth)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= depth & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= depth & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetPixelDepth(u32 offset)
|
||||
{
|
||||
u32 depth = 0;
|
||||
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
depth = (*(u32*)&efb[offset]) & 0x00ffffff;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
depth = (*(u32*)&efb[offset]) & 0x00ffffff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
u32 GetSourceFactor(u8 *srcClr, u8 *dstClr, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case 0: // zero
|
||||
return 0;
|
||||
case 1: // one
|
||||
return 0xffffffff;
|
||||
case 2: // dstclr
|
||||
return *(u32*)dstClr;
|
||||
case 3: // invdstclr
|
||||
return 0xffffffff - *(u32*)dstClr;
|
||||
case 4: // srcalpha
|
||||
{
|
||||
u8 alpha = srcClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 5: // invsrcalpha
|
||||
{
|
||||
u8 alpha = 0xff - srcClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 6: // dstalpha
|
||||
{
|
||||
u8 alpha = dstClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 7: // invdstalpha
|
||||
{
|
||||
u8 alpha = 0xff - dstClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetDestinationFactor(u8 *srcClr, u8 *dstClr, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case 0: // zero
|
||||
return 0;
|
||||
case 1: // one
|
||||
return 0xffffffff;
|
||||
case 2: // srcclr
|
||||
return *(u32*)srcClr;
|
||||
case 3: // invsrcclr
|
||||
return 0xffffffff - *(u32*)srcClr;
|
||||
case 4: // srcalpha
|
||||
{
|
||||
u8 alpha = srcClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 5: // invsrcalpha
|
||||
{
|
||||
u8 alpha = 0xff - srcClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 6: // dstalpha
|
||||
{
|
||||
u8 alpha = dstClr[3] & 0xff;
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 7: // invdstalpha
|
||||
{
|
||||
u8 alpha = 0xff - dstClr[3];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlendColor(u8 *srcClr, u8 *dstClr)
|
||||
{
|
||||
u32 srcFactor = GetSourceFactor(srcClr, dstClr, bpmem.blendmode.srcfactor);
|
||||
u32 dstFactor = GetDestinationFactor(srcClr, dstClr, bpmem.blendmode.dstfactor);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// add MSB of factors to make their range 0 -> 256
|
||||
u32 sf = (srcFactor & 0xff);
|
||||
sf += sf >> 7;
|
||||
|
||||
u32 df = (dstFactor & 0xff);
|
||||
df += df >> 7;
|
||||
|
||||
u32 color = (srcClr[i] * sf + dstClr[i] * df) >> 8;
|
||||
dstClr[i] = (color>255)?255:color;
|
||||
|
||||
dstFactor >>= 8;
|
||||
srcFactor >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void LogicBlend(u32 srcClr, u32 &dstClr, int op)
|
||||
{
|
||||
switch (op) {
|
||||
case 0: // clear
|
||||
dstClr = 0;
|
||||
break;
|
||||
case 1: // and
|
||||
dstClr = srcClr & dstClr;
|
||||
break;
|
||||
case 2: // revand
|
||||
dstClr = srcClr & (~dstClr);
|
||||
break;
|
||||
case 3: // copy
|
||||
dstClr = srcClr;
|
||||
break;
|
||||
case 4: // invand
|
||||
dstClr = (~srcClr) & dstClr;
|
||||
break;
|
||||
case 5: // noop
|
||||
dstClr = dstClr;
|
||||
break;
|
||||
case 6: // xor
|
||||
dstClr = srcClr ^ dstClr;
|
||||
break;
|
||||
case 7: // or
|
||||
dstClr = srcClr | dstClr;
|
||||
break;
|
||||
case 8: // nor
|
||||
dstClr = ~(srcClr | dstClr);
|
||||
break;
|
||||
case 9: // equiv
|
||||
dstClr = ~(srcClr ^ dstClr);
|
||||
break;
|
||||
case 10: // inv
|
||||
dstClr = ~dstClr;
|
||||
break;
|
||||
case 11: // revor
|
||||
dstClr = srcClr | (~dstClr);
|
||||
break;
|
||||
case 12: // invcopy
|
||||
dstClr = ~srcClr;
|
||||
break;
|
||||
case 13: // invor
|
||||
dstClr = (~srcClr) | dstClr;
|
||||
break;
|
||||
case 14: // nand
|
||||
dstClr = ~(srcClr & dstClr);
|
||||
break;
|
||||
case 15: // set
|
||||
dstClr = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SubtractBlend(u8 *srcClr, u8 *dstClr)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int c = (int)dstClr[i] - (int)srcClr[i];
|
||||
dstClr[i] = (c < 0)?0:c;
|
||||
}
|
||||
}
|
||||
|
||||
void BlendTev(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 dstClr;
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
|
||||
u8 *dstClrPtr = (u8*)&dstClr;
|
||||
|
||||
GetPixelColor(offset, dstClrPtr);
|
||||
|
||||
if (bpmem.blendmode.blendenable)
|
||||
{
|
||||
if (bpmem.blendmode.subtract)
|
||||
SubtractBlend(color, dstClrPtr);
|
||||
else
|
||||
BlendColor(color, dstClrPtr);
|
||||
}
|
||||
else if (bpmem.blendmode.logicopenable)
|
||||
LogicBlend(*((u32*)color), dstClr, bpmem.blendmode.logicmode);
|
||||
else
|
||||
dstClrPtr = color;
|
||||
|
||||
if (bpmem.dstalpha.enable)
|
||||
dstClrPtr[3] = bpmem.dstalpha.alpha;
|
||||
|
||||
if (bpmem.blendmode.colorupdate)
|
||||
{
|
||||
if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaColor(offset, dstClrPtr);
|
||||
else
|
||||
SetPixelColorOnly(offset, dstClrPtr);
|
||||
}
|
||||
else if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaOnly(offset, dstClrPtr[3]);
|
||||
|
||||
// branchless bounding box update
|
||||
PixelEngine::pereg.boxLeft = PixelEngine::pereg.boxLeft>x?x:PixelEngine::pereg.boxLeft;
|
||||
PixelEngine::pereg.boxRight = PixelEngine::pereg.boxRight<x?x:PixelEngine::pereg.boxRight;
|
||||
PixelEngine::pereg.boxTop = PixelEngine::pereg.boxTop>y?y:PixelEngine::pereg.boxTop;
|
||||
PixelEngine::pereg.boxBottom = PixelEngine::pereg.boxBottom<y?y:PixelEngine::pereg.boxBottom;
|
||||
}
|
||||
|
||||
void SetColor(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
if (bpmem.blendmode.colorupdate)
|
||||
{
|
||||
if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaColor(offset, color);
|
||||
else
|
||||
SetPixelColorOnly(offset, color);
|
||||
}
|
||||
else if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaOnly(offset, color[3]);
|
||||
}
|
||||
|
||||
void SetDepth(u16 x, u16 y, u32 depth)
|
||||
{
|
||||
SetPixelDepth(GetDepthOffset(x, y), depth);
|
||||
}
|
||||
|
||||
void GetColor(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
GetPixelColor(offset, color);
|
||||
}
|
||||
|
||||
u32 GetDepth(u16 x, u16 y)
|
||||
{
|
||||
u32 offset = GetDepthOffset(x, y);
|
||||
return GetPixelDepth(offset);
|
||||
}
|
||||
|
||||
u8 *GetPixelPointer(u16 x, u16 y, bool depth)
|
||||
{
|
||||
if (depth)
|
||||
return &efb[GetDepthOffset(x, y)];
|
||||
return &efb[GetColorOffset(x, y)];
|
||||
}
|
||||
|
||||
void UpdateColorTexture()
|
||||
{
|
||||
u32 color;
|
||||
u8* colorPtr = (u8*)&color;
|
||||
u32* texturePtr = (u32*)efbColorTexture;
|
||||
u32 textureAddress = 0;
|
||||
u32 efbOffset = 0;
|
||||
|
||||
for (u16 y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (u16 x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
GetPixelColor(efbOffset, colorPtr);
|
||||
efbOffset += 3;
|
||||
texturePtr[textureAddress++] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ZCompare(u16 x, u16 y, u32 z)
|
||||
{
|
||||
u32 offset = GetDepthOffset(x, y);
|
||||
u32 depth = GetPixelDepth(offset);
|
||||
|
||||
bool pass;
|
||||
|
||||
switch (bpmem.zmode.func)
|
||||
{
|
||||
case COMPARE_NEVER:
|
||||
pass = false;
|
||||
break;
|
||||
case COMPARE_LESS:
|
||||
pass = z < depth;
|
||||
break;
|
||||
case COMPARE_EQUAL:
|
||||
pass = z == depth;
|
||||
break;
|
||||
case COMPARE_LEQUAL:
|
||||
pass = z <= depth;
|
||||
break;
|
||||
case COMPARE_GREATER:
|
||||
pass = z > depth;
|
||||
break;
|
||||
case COMPARE_NEQUAL:
|
||||
pass = z != depth;
|
||||
break;
|
||||
case COMPARE_GEQUAL:
|
||||
pass = z >= depth;
|
||||
break;
|
||||
case COMPARE_ALWAYS:
|
||||
pass = true;
|
||||
break;
|
||||
default:
|
||||
pass = false;
|
||||
ERROR_LOG(VIDEO, "Bad Z compare mode %i", bpmem.zmode.func);
|
||||
}
|
||||
|
||||
if (pass && bpmem.zmode.updateenable)
|
||||
{
|
||||
SetPixelDepth(offset, z);
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
}
|
|
@ -0,0 +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
|
|
@ -0,0 +1,754 @@
|
|||
// 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 "VideoConfig.h"
|
||||
#include "IniFile.h"
|
||||
#include "svnrev.h"
|
||||
#include "Setup.h"
|
||||
|
||||
//#include "Render.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "Win32.h"
|
||||
#else
|
||||
struct RECT
|
||||
{
|
||||
int left, top;
|
||||
int right, bottom;
|
||||
};
|
||||
#endif
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
// Handles OpenGL and the window
|
||||
|
||||
// Window dimensions.
|
||||
static int s_backbuffer_width;
|
||||
static int s_backbuffer_height;
|
||||
|
||||
#ifndef _WIN32
|
||||
GLWindow GLWin;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
static HDC hDC = NULL; // Private GDI Device Context
|
||||
static HGLRC hRC = NULL; // Permanent Rendering Context
|
||||
extern HINSTANCE g_hInstance;
|
||||
#endif
|
||||
|
||||
void OpenGL_SwapBuffers()
|
||||
{
|
||||
#if USE_SDL
|
||||
SDL_GL_SwapBuffers();
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
cocoaGLSwap(GLWin.cocoaCtx,GLWin.cocoaWin);
|
||||
#elif defined(_WIN32)
|
||||
SwapBuffers(hDC);
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
GLWin.glCanvas->SwapBuffers();
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
glXSwapBuffers(GLWin.dpy, GLWin.win);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 OpenGL_GetBackbufferWidth()
|
||||
{
|
||||
return s_backbuffer_width;
|
||||
}
|
||||
|
||||
u32 OpenGL_GetBackbufferHeight()
|
||||
{
|
||||
return s_backbuffer_height;
|
||||
}
|
||||
|
||||
void OpenGL_SetWindowText(const char *text)
|
||||
{
|
||||
#if USE_SDL
|
||||
SDL_WM_SetCaption(text, NULL);
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
cocoaGLSetTitle(GLWin.cocoaWin, text);
|
||||
#elif defined(_WIN32)
|
||||
// TODO convert text to unicode and change SetWindowTextA to SetWindowText
|
||||
SetWindowTextA(EmuWindow::GetWnd(), text);
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
GLWin.frame->SetTitle(wxString::FromAscii(text));
|
||||
#elif defined(HAVE_X11) && HAVE_X11 // GLX
|
||||
/**
|
||||
* Tell X to ask the window manager to set the window title. (X
|
||||
* itself doesn't provide window title functionality.)
|
||||
*/
|
||||
XStoreName(GLWin.dpy, GLWin.win, text);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Draw messages on top of the screen
|
||||
// ------------------
|
||||
unsigned int Callback_PeekMessages()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: peekmessage
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
void UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
char temp[512];
|
||||
sprintf(temp, "SVN R%s: SW: %s", SVN_REV_STR, text);
|
||||
OpenGL_SetWindowText(temp);
|
||||
}
|
||||
// =========================
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
// ------------------
|
||||
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _twidth, int _theight)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
EmuWindow::SetSize(_twidth, _theight);
|
||||
#endif
|
||||
// ----------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Control window size and picture scaling
|
||||
// ------------------
|
||||
s_backbuffer_width = _twidth;
|
||||
s_backbuffer_height = _theight;
|
||||
|
||||
g_VideoInitialize.pPeekMessages = &Callback_PeekMessages;
|
||||
g_VideoInitialize.pUpdateFPSDisplay = &UpdateFPSDisplay;
|
||||
|
||||
#if USE_SDL
|
||||
//init sdl video
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
//TODO : Display an error message
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
|
||||
//setup ogl to use double buffering
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
GLWin.width = s_backbuffer_width;
|
||||
GLWin.height = s_backbuffer_height;
|
||||
GLWin.cocoaWin = cocoaGLCreateWindow(GLWin.width, GLWin.height);
|
||||
GLWin.cocoaCtx = cocoaGLInit(g_Config.iMultisampleMode);
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
|
||||
|
||||
wxSize size(_iwidth, _iheight);
|
||||
if (!g_Config.renderToMainframe ||
|
||||
g_VideoInitialize.pWindowHandle == NULL) {
|
||||
GLWin.frame = new wxFrame((wxWindow *)g_VideoInitialize.pWindowHandle,
|
||||
-1, _("Dolphin"), wxPoint(50,50), size);
|
||||
} else {
|
||||
GLWin.frame = new wxFrame((wxWindow *)NULL,
|
||||
-1, _("Dolphin"), wxPoint(50,50), size);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
GLWin.glCanvas = new wxGLCanvas(GLWin.frame, wxID_ANY, wxPoint(0,0), size, 0, wxT("Dolphin"), args, wxNullPalette);
|
||||
#else
|
||||
GLWin.glCanvas = new wxGLCanvas(GLWin.frame, wxID_ANY, args,
|
||||
wxPoint(0,0), size, wxSUNKEN_BORDER);
|
||||
GLWin.glCtxt = new wxGLContext(GLWin.glCanvas);
|
||||
#endif
|
||||
|
||||
GLWin.frame->Show(TRUE);
|
||||
GLWin.glCanvas->Show(TRUE);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
GLWin.glCanvas->SetCurrent();
|
||||
#else
|
||||
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
||||
// GLWin.glCtxt->SetCurrent(*GLWin.glCanvas);
|
||||
#endif
|
||||
|
||||
|
||||
#elif defined(_WIN32)
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Create rendering window in Windows
|
||||
// ----------------------
|
||||
|
||||
// Create a separate window
|
||||
if (!g_Config.renderToMainframe || g_VideoInitialize.pWindowHandle == NULL)
|
||||
g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create(NULL, g_hInstance, _T("Please wait..."));
|
||||
// Create a child window
|
||||
else
|
||||
g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create((HWND)g_VideoInitialize.pWindowHandle, g_hInstance, _T("Please wait..."));
|
||||
|
||||
// Show the window
|
||||
EmuWindow::Show();
|
||||
|
||||
if (g_VideoInitialize.pWindowHandle == NULL)
|
||||
{
|
||||
g_VideoInitialize.pSysMessage("failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint PixelFormat; // Holds The Results After Searching For A Match
|
||||
DWORD dwExStyle; // Window Extended Style
|
||||
DWORD dwStyle; // Window Style
|
||||
|
||||
RECT rcdesktop;
|
||||
GetWindowRect(GetDesktopWindow(), &rcdesktop);
|
||||
|
||||
if (g_Config.bFullscreen) {
|
||||
//s_backbuffer_width = rcdesktop.right - rcdesktop.left;
|
||||
//s_backbuffer_height = rcdesktop.bottom - rcdesktop.top;
|
||||
|
||||
DEVMODE dmScreenSettings;
|
||||
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
|
||||
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
|
||||
dmScreenSettings.dmPelsWidth = s_backbuffer_width;
|
||||
dmScreenSettings.dmPelsHeight = s_backbuffer_height;
|
||||
dmScreenSettings.dmBitsPerPel = 32;
|
||||
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
|
||||
|
||||
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
|
||||
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
|
||||
{
|
||||
if (MessageBox(NULL,_T("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),_T("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
|
||||
g_Config.bFullscreen = false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change to default resolution
|
||||
ChangeDisplaySettings(NULL, 0);
|
||||
}
|
||||
|
||||
if (g_Config.bFullscreen && !g_Config.renderToMainframe)
|
||||
{
|
||||
// Hide the cursor
|
||||
ShowCursor(FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||
dwStyle = WS_OVERLAPPEDWINDOW;
|
||||
}
|
||||
|
||||
RECT rc = {0, 0, s_backbuffer_width, s_backbuffer_height};
|
||||
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
|
||||
|
||||
int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
|
||||
int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
|
||||
|
||||
// EmuWindow::GetWnd() is either the new child window or the new separate window
|
||||
if (g_Config.bFullscreen)
|
||||
// We put the window at the upper left corner of the screen, so x = y = 0
|
||||
SetWindowPos(EmuWindow::GetWnd(), NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION | SWP_NOZORDER);
|
||||
else
|
||||
SetWindowPos(EmuWindow::GetWnd(), NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION | SWP_NOZORDER);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
||||
1, // Version Number
|
||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
||||
32, // Select Our Color Depth
|
||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
||||
0, // 8bit Alpha Buffer
|
||||
0, // Shift Bit Ignored
|
||||
0, // No Accumulation Buffer
|
||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
||||
24, // 24Bit Z-Buffer (Depth Buffer)
|
||||
8, // 8bit Stencil Buffer
|
||||
0, // No Auxiliary Buffer
|
||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
||||
0, // Reserved
|
||||
0, 0, 0 // Layer Masks Ignored
|
||||
};
|
||||
|
||||
if (!(hDC=GetDC(EmuWindow::GetWnd()))) {
|
||||
PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) {
|
||||
PanicAlert("(2) Can't find a suitable PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {
|
||||
PanicAlert("(3) Can't set the PixelFormat.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(hRC = wglCreateContext(hDC))) {
|
||||
PanicAlert("(4) Can't create an OpenGL rendering context.");
|
||||
return false;
|
||||
}
|
||||
// --------------------------------------
|
||||
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
XVisualInfo *vi;
|
||||
Colormap cmap;
|
||||
int dpyWidth, dpyHeight;
|
||||
int glxMajorVersion, glxMinorVersion;
|
||||
int vidModeMajorVersion, vidModeMinorVersion;
|
||||
Atom wmDelete;
|
||||
|
||||
// attributes for a single buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
None};
|
||||
|
||||
// attributes for a double buffered visual in RGBA format with at least
|
||||
// 8 bits per color and a 24 bit depth buffer
|
||||
int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 8,
|
||||
GLX_GREEN_SIZE, 8,
|
||||
GLX_BLUE_SIZE, 8,
|
||||
GLX_DEPTH_SIZE, 24,
|
||||
GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode, GLX_SAMPLES_ARB, 1, None };
|
||||
GLWin.dpy = XOpenDisplay(0);
|
||||
g_VideoInitialize.pWindowHandle = (HWND)GLWin.dpy;
|
||||
GLWin.screen = DefaultScreen(GLWin.dpy);
|
||||
|
||||
// Fullscreen option.
|
||||
GLWin.fs = g_Config.bFullscreen; //Set to setting in Options
|
||||
|
||||
/* get an appropriate visual */
|
||||
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
|
||||
if (vi == NULL) {
|
||||
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
|
||||
GLWin.doubleBuffered = False;
|
||||
ERROR_LOG(VIDEO, "Only Singlebuffered Visual!");
|
||||
}
|
||||
else {
|
||||
GLWin.doubleBuffered = True;
|
||||
NOTICE_LOG(VIDEO, "Got Doublebuffered Visual!");
|
||||
}
|
||||
|
||||
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
|
||||
NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
|
||||
// Create a GLX context.
|
||||
GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE);
|
||||
if(!GLWin.ctx)
|
||||
{
|
||||
PanicAlert("Couldn't Create GLX context.Quit");
|
||||
exit(0); // TODO: Don't bring down entire Emu
|
||||
}
|
||||
// Create a color map.
|
||||
cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), vi->visual, AllocNone);
|
||||
GLWin.attr.colormap = cmap;
|
||||
GLWin.attr.border_pixel = 0;
|
||||
XkbSetDetectableAutoRepeat(GLWin.dpy, True, NULL);
|
||||
|
||||
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
|
||||
// get a connection
|
||||
XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion);
|
||||
|
||||
if (GLWin.fs) {
|
||||
|
||||
XF86VidModeModeInfo **modes = NULL;
|
||||
int modeNum = 0;
|
||||
int bestMode = 0;
|
||||
|
||||
// set best mode to current
|
||||
bestMode = 0;
|
||||
NOTICE_LOG(VIDEO, "XF86VidModeExtension-Version %d.%d", vidModeMajorVersion, vidModeMinorVersion);
|
||||
XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes);
|
||||
|
||||
if (modeNum > 0 && modes != NULL) {
|
||||
/* save desktop-resolution before switching modes */
|
||||
GLWin.deskMode = *modes[0];
|
||||
/* look for mode with requested resolution */
|
||||
for (int i = 0; i < modeNum; i++) {
|
||||
if ((modes[i]->hdisplay == _twidth) && (modes[i]->vdisplay == _theight)) {
|
||||
bestMode = i;
|
||||
}
|
||||
}
|
||||
|
||||
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]);
|
||||
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
|
||||
dpyWidth = modes[bestMode]->hdisplay;
|
||||
dpyHeight = modes[bestMode]->vdisplay;
|
||||
NOTICE_LOG(VIDEO, "Resolution %dx%d", dpyWidth, dpyHeight);
|
||||
XFree(modes);
|
||||
|
||||
/* create a fullscreen window */
|
||||
GLWin.attr.override_redirect = True;
|
||||
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask;
|
||||
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
|
||||
0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
|
||||
&GLWin.attr);
|
||||
XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0);
|
||||
XMapRaised(GLWin.dpy, GLWin.win);
|
||||
XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask,
|
||||
GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
|
||||
}
|
||||
else {
|
||||
ERROR_LOG(VIDEO, "Failed to start fullscreen. If you received the "
|
||||
"\"XFree86-VidModeExtension\" extension is missing, add\n"
|
||||
"Load \"extmod\"\n"
|
||||
"to your X configuration file (under the Module Section)\n");
|
||||
GLWin.fs = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!GLWin.fs) {
|
||||
|
||||
//XRootWindow(dpy,screen)
|
||||
//int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
|
||||
//int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
|
||||
|
||||
// create a window in window mode
|
||||
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask |
|
||||
StructureNotifyMask | ResizeRedirectMask;
|
||||
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
|
||||
0, 0, _twidth, _theight, 0, vi->depth, InputOutput, vi->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr);
|
||||
// only set window title and handle wm_delete_events if in windowed mode
|
||||
wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
|
||||
XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1);
|
||||
XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU",
|
||||
"GPU", None, NULL, 0, NULL);
|
||||
XMapRaised(GLWin.dpy, GLWin.win);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGL_MakeCurrent()
|
||||
{
|
||||
#if USE_SDL
|
||||
// Note: The reason for having the call to SDL_SetVideoMode in here instead
|
||||
// of in OpenGL_Create() is that "make current" is part of the video
|
||||
// mode setting and is not available as a separate call in SDL. We
|
||||
// have to do "make current" here because this method runs in the CPU
|
||||
// thread while OpenGL_Create() runs in a diferent thread and "make
|
||||
// current" has to be done in the same thread that will be making
|
||||
// calls to OpenGL.
|
||||
|
||||
// Fetch video info.
|
||||
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
|
||||
if (!videoInfo) {
|
||||
// TODO: Display an error message.
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
// Compute video mode flags.
|
||||
const int videoFlags = SDL_OPENGL
|
||||
| ( videoInfo->hw_available ? SDL_HWSURFACE : SDL_SWSURFACE )
|
||||
| ( g_Config.bFullscreen ? SDL_FULLSCREEN : 0);
|
||||
// Set vide mode.
|
||||
// TODO: Can we use this field or is a separate field needed?
|
||||
int _twidth = s_backbuffer_width;
|
||||
int _theight = s_backbuffer_height;
|
||||
SDL_Surface *screen = SDL_SetVideoMode(_twidth, _theight, 0, videoFlags);
|
||||
if (!screen) {
|
||||
//TODO : Display an error message
|
||||
SDL_Quit();
|
||||
return false;
|
||||
}
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
cocoaGLMakeCurrent(GLWin.cocoaCtx,GLWin.cocoaWin);
|
||||
#elif defined(_WIN32)
|
||||
if (!wglMakeCurrent(hDC,hRC)) {
|
||||
PanicAlert("(5) Can't Activate The GL Rendering Context.");
|
||||
return false;
|
||||
}
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
#if defined(__APPLE__)
|
||||
GLWin.glCanvas->SetCurrent();
|
||||
#else
|
||||
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
||||
#endif
|
||||
return true;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
Window winDummy;
|
||||
unsigned int borderDummy;
|
||||
// connect the glx-context to the window
|
||||
glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
|
||||
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
|
||||
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
|
||||
NOTICE_LOG(VIDEO, "GLWin Depth %d", GLWin.depth)
|
||||
if (glXIsDirect(GLWin.dpy, GLWin.ctx)) {
|
||||
NOTICE_LOG(VIDEO, "detected direct rendering");
|
||||
} else {
|
||||
ERROR_LOG(VIDEO, "no Direct Rendering possible!");
|
||||
}
|
||||
|
||||
// better for pad plugin key input (thc)
|
||||
XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask |
|
||||
FocusChangeMask );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
// ----------------
|
||||
void OpenGL_Update()
|
||||
{
|
||||
#if USE_SDL
|
||||
SDL_Surface *surface = SDL_GetVideoSurface();
|
||||
RECT rcWindow = {0};
|
||||
if (!surface)
|
||||
return;
|
||||
s_backbuffer_width = surface->w;
|
||||
s_backbuffer_height = surface->h;
|
||||
|
||||
rcWindow.right = surface->w;
|
||||
rcWindow.bottom = surface->h;
|
||||
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
RECT rcWindow = {0};
|
||||
rcWindow.right = GLWin.width;
|
||||
rcWindow.bottom = GLWin.height;
|
||||
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
RECT rcWindow = {0};
|
||||
rcWindow.right = GLWin.width;
|
||||
rcWindow.bottom = GLWin.height;
|
||||
|
||||
// TODO fill in
|
||||
#elif defined(_WIN32)
|
||||
RECT rcWindow;
|
||||
if (!EmuWindow::GetParentWnd())
|
||||
{
|
||||
// We are not rendering to a child window - use client size.
|
||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are rendering to a child window - use parent size.
|
||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Get the new window width and height
|
||||
// ------------------
|
||||
// See below for documentation
|
||||
// ------------------
|
||||
int width = rcWindow.right - rcWindow.left;
|
||||
int height = rcWindow.bottom - rcWindow.top;
|
||||
|
||||
// If we are rendering to a child window
|
||||
if (EmuWindow::GetParentWnd() != 0)
|
||||
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
||||
|
||||
s_backbuffer_width = width;
|
||||
s_backbuffer_height = height;
|
||||
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
// We just check all of our events here
|
||||
XEvent event;
|
||||
KeySym key;
|
||||
static RECT rcWindow;
|
||||
static bool ShiftPressed = false;
|
||||
static bool ControlPressed = false;
|
||||
static int FKeyPressed = -1;
|
||||
int num_events;
|
||||
for (num_events = XPending(GLWin.dpy);num_events > 0;num_events--) {
|
||||
XNextEvent(GLWin.dpy, &event);
|
||||
switch(event.type) {
|
||||
case KeyRelease:
|
||||
key = XLookupKeysym((XKeyEvent*)&event, 0);
|
||||
if(key >= XK_F1 && key <= XK_F9) {
|
||||
g_VideoInitialize.pKeyPress(FKeyPressed, ShiftPressed, ControlPressed);
|
||||
FKeyPressed = -1;
|
||||
} else {
|
||||
if(key == XK_Shift_L || key == XK_Shift_R)
|
||||
ShiftPressed = false;
|
||||
else if(key == XK_Control_L || key == XK_Control_R)
|
||||
ControlPressed = false;
|
||||
else
|
||||
XPutBackEvent(GLWin.dpy, &event);
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
key = XLookupKeysym((XKeyEvent*)&event, 0);
|
||||
if(key >= XK_F1 && key <= XK_F9)
|
||||
FKeyPressed = key - 0xff4e;
|
||||
else {
|
||||
if(key == XK_Shift_L || key == XK_Shift_R)
|
||||
ShiftPressed = true;
|
||||
else if(key == XK_Control_L || key == XK_Control_R)
|
||||
ControlPressed = true;
|
||||
else
|
||||
XPutBackEvent(GLWin.dpy, &event);
|
||||
}
|
||||
break;
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
XPutBackEvent(GLWin.dpy, &event);
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
Window winDummy;
|
||||
unsigned int borderDummy;
|
||||
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
|
||||
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
|
||||
s_backbuffer_width = GLWin.width;
|
||||
s_backbuffer_height = GLWin.height;
|
||||
rcWindow.left = 0;
|
||||
rcWindow.top = 0;
|
||||
rcWindow.right = GLWin.width;
|
||||
rcWindow.bottom = GLWin.height;
|
||||
break;
|
||||
case ClientMessage: //TODO: We aren't reading this correctly, It could be anything, highest chance is that it's a close event though
|
||||
Shutdown(); // Calling from here since returning false does nothing
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
//TODO: Should we put the event back if we don't handle it?
|
||||
// I think we handle all the needed ones, the rest shouldn't matter
|
||||
// But to be safe, let's but them back anyway
|
||||
//XPutBackEvent(GLWin.dpy, &event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
// Close plugin
|
||||
// ----------------
|
||||
void OpenGL_Shutdown()
|
||||
{
|
||||
#if USE_SDL
|
||||
SDL_Quit();
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
cocoaGLDelete(GLWin.cocoaCtx);
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
delete GLWin.glCanvas;
|
||||
delete GLWin.frame;
|
||||
#elif defined(_WIN32)
|
||||
if (hRC) // Do We Have A Rendering Context?
|
||||
{
|
||||
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
|
||||
{
|
||||
// [F|RES]: if this fails i dont see the message box and
|
||||
// cant get out of the modal state so i disable it.
|
||||
// This function fails only if i render to main window
|
||||
// MessageBox(NULL,"Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
|
||||
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Release Rendering Context Failed.");
|
||||
}
|
||||
hRC = NULL; // Set RC To NULL
|
||||
}
|
||||
|
||||
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC
|
||||
{
|
||||
#ifndef SETUP_TIMER_WAITING // This fails
|
||||
ERROR_LOG(VIDEO, "Release Device Context Failed.");
|
||||
#endif
|
||||
hDC = NULL; // Set DC To NULL
|
||||
}
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
if (GLWin.ctx)
|
||||
{
|
||||
if (!glXMakeCurrent(GLWin.dpy, None, NULL))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Could not release drawing context.\n");
|
||||
}
|
||||
XUnmapWindow(GLWin.dpy, GLWin.win);
|
||||
glXDestroyContext(GLWin.dpy, GLWin.ctx);
|
||||
XCloseDisplay(GLWin.dpy);
|
||||
GLWin.ctx = NULL;
|
||||
}
|
||||
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
|
||||
/* switch back to original desktop resolution if we were in fs */
|
||||
if (GLWin.dpy != NULL) {
|
||||
if (GLWin.fs) {
|
||||
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
|
||||
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line)
|
||||
{
|
||||
GLint err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n", file, line, function, err, gluErrorString(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void OpenGL_ReportARBProgramError()
|
||||
{
|
||||
const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
if (pstr != NULL && pstr[0] != 0)
|
||||
{
|
||||
GLint loc = 0;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
|
||||
ERROR_LOG(VIDEO, "program error at %d: ", loc);
|
||||
ERROR_LOG(VIDEO, (char*)pstr);
|
||||
ERROR_LOG(VIDEO, "");
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
||||
{
|
||||
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
const char *error = "-";
|
||||
switch (fbo_status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error = "INCOMPLETE_ATTACHMENT_EXT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error = "INCOMPLETE_MISSING_ATTACHMENT_EXT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error = "INCOMPLETE_DIMENSIONS_EXT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error = "INCOMPLETE_FORMATS_EXT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error = "INCOMPLETE_DRAW_BUFFER_EXT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error = "INCOMPLETE_READ_BUFFER_EXT"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error = "UNSUPPORTED_EXT"; break;
|
||||
}
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n", file, line, function, error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +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 _GLINIT_H_
|
||||
#define _GLINIT_H_
|
||||
|
||||
#if defined GLTEST && GLTEST
|
||||
#include "nGLUtil.h"
|
||||
#else
|
||||
#include "Common.h"
|
||||
#include <string>
|
||||
#include "VideoConfig.h"
|
||||
#include "pluginspecs_video.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define GLEW_STATIC
|
||||
|
||||
#include <GLew/glew.h>
|
||||
#include <GLew/wglew.h>
|
||||
#include <GLew/gl.h>
|
||||
#include <GLew/glext.h>
|
||||
|
||||
#else // linux basic definitions
|
||||
|
||||
#if defined(USE_WX) && USE_WX
|
||||
#include <GL/glew.h>
|
||||
#include "wx/wx.h"
|
||||
#include "wx/glcanvas.h"
|
||||
#undef HAVE_X11
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#define I_NEED_OS2_H // HAXXOR
|
||||
#include <GL/glxew.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#elif defined(USE_SDL) && USE_SDL
|
||||
#include <GL/glew.h>
|
||||
#include <SDL.h>
|
||||
#elif defined(HAVE_COCOA) && HAVE_COCOA
|
||||
#include <GL/glew.h>
|
||||
#include "cocoaGL.h"
|
||||
#endif // end USE_WX
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#endif // linux basic definitions
|
||||
|
||||
#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils
|
||||
#define GL_DEPTH_STENCIL_EXT 0x84F9
|
||||
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
|
||||
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
|
||||
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#if defined(HAVE_X11) && HAVE_X11
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
|
||||
#include <X11/extensions/xf86vmode.h>
|
||||
#endif // XXF86VM
|
||||
#endif // X11
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
int screen;
|
||||
#if defined(HAVE_COCOA) && HAVE_COCOA
|
||||
NSWindow *cocoaWin;
|
||||
NSOpenGLContext *cocoaCtx;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
Window win;
|
||||
Display *dpy;
|
||||
GLXContext ctx;
|
||||
XSetWindowAttributes attr;
|
||||
Bool fs;
|
||||
Bool doubleBuffered;
|
||||
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
|
||||
XF86VidModeModeInfo deskMode;
|
||||
#endif // XXF86VM
|
||||
#endif // X11
|
||||
#if defined(USE_WX) && USE_WX
|
||||
wxGLCanvas *glCanvas;
|
||||
wxFrame *frame;
|
||||
wxGLContext *glCtxt;
|
||||
#endif
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
unsigned int depth;
|
||||
} GLWindow;
|
||||
|
||||
extern GLWindow GLWin;
|
||||
|
||||
#endif
|
||||
|
||||
// Public OpenGL util
|
||||
|
||||
// Initialization / upkeep
|
||||
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height);
|
||||
void OpenGL_Shutdown();
|
||||
void OpenGL_Update();
|
||||
bool OpenGL_MakeCurrent();
|
||||
void OpenGL_SwapBuffers();
|
||||
|
||||
// Get status
|
||||
u32 OpenGL_GetBackbufferWidth();
|
||||
u32 OpenGL_GetBackbufferHeight();
|
||||
|
||||
// Set things
|
||||
void OpenGL_SetWindowText(const char *text);
|
||||
|
||||
// Error reporting - use the convenient macros.
|
||||
void OpenGL_ReportARBProgramError();
|
||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line);
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line);
|
||||
|
||||
#if 1
|
||||
#define GL_REPORT_ERROR() OpenGL_ReportGLError (__FUNCTION__, __FILE__, __LINE__)
|
||||
#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError()
|
||||
#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError (__FUNCTION__, __FILE__, __LINE__)
|
||||
#else
|
||||
#define GL_REPORT_ERROR() GL_NO_ERROR
|
||||
#define GL_REPORT_PROGRAM_ERROR()
|
||||
#define GL_REPORT_FBO_ERROR()
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__)
|
||||
#else
|
||||
#define GL_REPORT_ERRORD() GL_NO_ERROR
|
||||
#endif
|
||||
|
||||
#endif // GLTEST ??
|
||||
|
||||
#endif // _GLINIT_H_
|
|
@ -0,0 +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[0] / efbHalfWidth - 1.0f, 1.0f - v->screenPosition[1] / efbHalfHeight, v->screenPosition[2]);
|
||||
}
|
||||
|
||||
void DrawTextureVertex(OutputVertexData *v)
|
||||
{
|
||||
glTexCoord2f(v->texCoords[0][0] * texWidth, v->texCoords[0][1] * texHeight);
|
||||
glVertex3f(v->screenPosition[0] / efbHalfWidth - 1.0f, 1.0f - v->screenPosition[1] / efbHalfHeight, v->screenPosition[2]);
|
||||
}
|
||||
|
||||
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, 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +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
|
|
@ -0,0 +1,83 @@
|
|||
// 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
|
||||
|
||||
|
||||
#define LOADERDECL __cdecl
|
||||
typedef void (LOADERDECL *TPipelineFunction)();
|
||||
|
||||
struct InputVertexData
|
||||
{
|
||||
u8 posMtx;
|
||||
u8 texMtx[8];
|
||||
|
||||
float position[4];
|
||||
float normal[3][3];
|
||||
u8 color[2][4];
|
||||
float texCoords[8][2];
|
||||
};
|
||||
|
||||
struct OutputVertexData
|
||||
{
|
||||
float mvPosition[3];
|
||||
float projectedPosition[4];
|
||||
float screenPosition[3];
|
||||
float normal[3][3];
|
||||
u8 color[2][4];
|
||||
float texCoords[8][3];
|
||||
|
||||
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)
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
mvPosition[i] = LINTERP(t, a->mvPosition[i], b->mvPosition[i]);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
projectedPosition[i] = LINTERP(t, a->projectedPosition[i], b->projectedPosition[i]);
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
normal[i][0] = LINTERP(t, a->normal[i][0], b->normal[i][0]);
|
||||
normal[i][1] = LINTERP(t, a->normal[i][1], b->normal[i][1]);
|
||||
normal[i][2] = LINTERP(t, a->normal[i][2], b->normal[i][2]);
|
||||
}
|
||||
|
||||
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][0] = LINTERP(t, a->texCoords[i][0], b->texCoords[i][0]);
|
||||
texCoords[i][1] = LINTERP(t, a->texCoords[i][1], b->texCoords[i][1]);
|
||||
texCoords[i][2] = LINTERP(t, a->texCoords[i][2], b->texCoords[i][2]);
|
||||
}
|
||||
|
||||
#undef LINTERP
|
||||
#undef LINTERP_INT
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +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
|
|
@ -0,0 +1,296 @@
|
|||
// 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"
|
||||
|
||||
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_SkipFrame)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +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
|
|
@ -0,0 +1,176 @@
|
|||
// 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 PixelEngine::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.bUseDualCore || (!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;
|
||||
//_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" );
|
||||
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));
|
||||
}
|
||||
else // set token value
|
||||
{
|
||||
ERROR_LOG(PIXELENGINE, "VIDEO plugin should set the token directly");
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
|
@ -0,0 +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
|
||||
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
// 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 8
|
||||
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
|
||||
s32 scissorLeft = 0;
|
||||
s32 scissorTop = 0;
|
||||
s32 scissorRight = 0;
|
||||
s32 scissorBottom = 0;
|
||||
|
||||
Tev tev;
|
||||
|
||||
void Init()
|
||||
{
|
||||
tev.Init();
|
||||
}
|
||||
|
||||
inline int iround(float x)
|
||||
{
|
||||
int t;
|
||||
|
||||
__asm
|
||||
{
|
||||
fld x
|
||||
fistp t
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
INCSTAT(stats.thisFrame.rasterizedPixels);
|
||||
|
||||
float zFloat = 1.0f + ZSlope.GetValue(x, y);
|
||||
if(zFloat < 0|| zFloat > 1)
|
||||
return;
|
||||
|
||||
u32 z = (u32)(zFloat * 0x00ffffff);
|
||||
|
||||
if (bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
|
||||
{
|
||||
// early z
|
||||
if (!EfbInterface::ZCompare(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
float invW = 1.0f / WSlope.GetValue(x, y);
|
||||
|
||||
tev.Position[0] = x;
|
||||
tev.Position[1] = y;
|
||||
tev.Position[2] = z;
|
||||
|
||||
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(x, y);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
if (xfregs.texMtxInfo[i].projection)
|
||||
{
|
||||
float q = TexSlopes[i][2].GetValue(x, y) * invW;
|
||||
float invQ = invW / q;
|
||||
tev.Uv[i][0] = TexSlopes[i][0].GetValue(x, y) * invQ * (bpmem.texcoords[i].s.scale_minus_1 + 1);
|
||||
tev.Uv[i][1] = TexSlopes[i][1].GetValue(x, y) * invQ * (bpmem.texcoords[i].t.scale_minus_1 + 1);
|
||||
tev.Lod[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tev.Uv[i][0] = TexSlopes[i][0].GetValue(x, y) * invW * (bpmem.texcoords[i].s.scale_minus_1 + 1);
|
||||
tev.Uv[i][1] = TexSlopes[i][1].GetValue(x, y) * invW * (bpmem.texcoords[i].t.scale_minus_1 + 1);
|
||||
tev.Lod[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tev.Draw();
|
||||
}
|
||||
|
||||
void InitSlope(Slope *slope, float f1, float f2, float f3, float DX31, float DX12, float DY12, float DY31, float X1, float Y1)
|
||||
{
|
||||
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;
|
||||
slope->x0 = X1;
|
||||
slope->y0 = Y1;
|
||||
}
|
||||
|
||||
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
|
||||
const s32 Y1 = iround(16.0f * v0->screenPosition[1]);
|
||||
const s32 Y2 = iround(16.0f * v1->screenPosition[1]);
|
||||
const s32 Y3 = iround(16.0f * v2->screenPosition[1]);
|
||||
|
||||
const s32 X1 = iround(16.0f * v0->screenPosition[0]);
|
||||
const s32 X2 = iround(16.0f * v1->screenPosition[0]);
|
||||
const s32 X3 = iround(16.0f * v2->screenPosition[0]);
|
||||
|
||||
// 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[0];
|
||||
float flty1 = v0->screenPosition[1];
|
||||
float fltdx31 = v2->screenPosition[0] - fltx1;
|
||||
float fltdx12 = fltx1 - v1->screenPosition[0];
|
||||
float fltdy12 = flty1 - v1->screenPosition[1];
|
||||
float fltdy31 = v2->screenPosition[1] - flty1;
|
||||
|
||||
float w[3] = { 1.0f / v0->projectedPosition[3], 1.0f / v1->projectedPosition[3], 1.0f / v2->projectedPosition[3] };
|
||||
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
|
||||
|
||||
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
|
||||
|
||||
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, fltx1, flty1);
|
||||
}
|
||||
|
||||
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, fltx1, flty1);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Accept whole block when totally covered
|
||||
if(a == 0xF && b == 0xF && c == 0xF)
|
||||
{
|
||||
for(s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
for(s32 ix = x; ix < x + BLOCK_SIZE; ix++)
|
||||
{
|
||||
Draw(ix, iy + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = y; iy < y + BLOCK_SIZE; iy++)
|
||||
{
|
||||
s32 CX1 = CY1;
|
||||
s32 CX2 = CY2;
|
||||
s32 CX3 = CY3;
|
||||
|
||||
for(s32 ix = x; ix < x + BLOCK_SIZE; ix++)
|
||||
{
|
||||
if(CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||
{
|
||||
Draw(ix, iy);
|
||||
}
|
||||
|
||||
CX1 -= FDY12;
|
||||
CX2 -= FDY23;
|
||||
CX3 -= FDY31;
|
||||
}
|
||||
|
||||
CY1 += FDX12;
|
||||
CY2 += FDX23;
|
||||
CY3 += FDX31;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// 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 x0;
|
||||
float y0;
|
||||
float GetValue(s32 x, s32 y) { return f0 + (dfdx * (x - x0)) + (dfdy * (y - y0)); }
|
||||
};
|
||||
|
||||
static Slope ZSlope;
|
||||
static Slope WSlope;
|
||||
static Slope ColorSlopes[2][4];
|
||||
static Slope TexSlopes[8][3];
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
// 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 "../../Plugin_VideoOGL/Src/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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +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
|
|
@ -0,0 +1,143 @@
|
|||
// 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()
|
||||
{}
|
||||
|
||||
void SetupUnit::SetupLineStrip()
|
||||
{}
|
||||
|
||||
void SetupUnit::SetupPoint()
|
||||
{}
|
|
@ -0,0 +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 _SETUPUNIT_H_
|
||||
#define _SETUPUNIT_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
class SetupUnit
|
||||
{
|
||||
u8 m_PrimType;
|
||||
int m_VertexCounter;
|
||||
|
||||
OutputVertexData m_Vertices[3];
|
||||
OutputVertexData *m_VertPointer[3];
|
||||
OutputVertexData *m_VertWritePointer;
|
||||
|
||||
void SetupQuad();
|
||||
void SetupTriangle();
|
||||
void SetupTriStrip();
|
||||
void SetupTriFan();
|
||||
void SetupLine();
|
||||
void SetupLineStrip();
|
||||
void SetupPoint();
|
||||
|
||||
public:
|
||||
void Init(u8 primitiveType);
|
||||
|
||||
OutputVertexData* GetVertex() { return m_VertWritePointer; }
|
||||
|
||||
void SetupVertex();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +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));
|
||||
}
|
|
@ -0,0 +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
|
|
@ -0,0 +1,722 @@
|
|||
// 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 "Tev.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "TextureSampler.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void Tev::Init()
|
||||
{
|
||||
FixedConstants[0] = 0;
|
||||
FixedConstants[1] = 31;
|
||||
FixedConstants[2] = 63;
|
||||
FixedConstants[3] = 95;
|
||||
FixedConstants[4] = 127;
|
||||
FixedConstants[5] = 159;
|
||||
FixedConstants[6] = 191;
|
||||
FixedConstants[7] = 223;
|
||||
FixedConstants[8] = 255;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
Zero16[i] = 0;
|
||||
|
||||
m_ColorInputLUT[0][0] = &Reg[0][RED_C]; m_ColorInputLUT[0][1] = &Reg[0][GRN_C]; m_ColorInputLUT[0][2] = &Reg[0][BLU_C]; // prev.rgb
|
||||
m_ColorInputLUT[1][0] = &Reg[0][ALP_C]; m_ColorInputLUT[1][1] = &Reg[0][ALP_C]; m_ColorInputLUT[1][2] = &Reg[0][ALP_C]; // prev.aaa
|
||||
m_ColorInputLUT[2][0] = &Reg[1][RED_C]; m_ColorInputLUT[2][1] = &Reg[1][GRN_C]; m_ColorInputLUT[2][2] = &Reg[1][BLU_C]; // c0.rgb
|
||||
m_ColorInputLUT[3][0] = &Reg[1][ALP_C]; m_ColorInputLUT[3][1] = &Reg[1][ALP_C]; m_ColorInputLUT[3][2] = &Reg[1][ALP_C]; // c0.aaa
|
||||
m_ColorInputLUT[4][0] = &Reg[2][RED_C]; m_ColorInputLUT[4][1] = &Reg[2][GRN_C]; m_ColorInputLUT[4][2] = &Reg[2][BLU_C]; // c1.rgb
|
||||
m_ColorInputLUT[5][0] = &Reg[2][ALP_C]; m_ColorInputLUT[5][1] = &Reg[2][ALP_C]; m_ColorInputLUT[5][2] = &Reg[2][ALP_C]; // c1.aaa
|
||||
m_ColorInputLUT[6][0] = &Reg[3][RED_C]; m_ColorInputLUT[6][1] = &Reg[3][GRN_C]; m_ColorInputLUT[6][2] = &Reg[3][BLU_C]; // c2.rgb
|
||||
m_ColorInputLUT[7][0] = &Reg[3][ALP_C]; m_ColorInputLUT[7][1] = &Reg[3][ALP_C]; m_ColorInputLUT[7][2] = &Reg[3][ALP_C]; // c2.aaa
|
||||
m_ColorInputLUT[8][0] = &TexColor[RED_C]; m_ColorInputLUT[8][1] = &TexColor[GRN_C]; m_ColorInputLUT[8][2] = &TexColor[BLU_C]; // tex.rgb
|
||||
m_ColorInputLUT[9][0] = &TexColor[ALP_C]; m_ColorInputLUT[9][1] = &TexColor[ALP_C]; m_ColorInputLUT[9][2] = &TexColor[ALP_C]; // tex.aaa
|
||||
m_ColorInputLUT[10][0] = &RasColor[RED_C]; m_ColorInputLUT[10][1] = &RasColor[GRN_C]; m_ColorInputLUT[10][2] = &RasColor[BLU_C]; // ras.rgb
|
||||
m_ColorInputLUT[11][0] = &RasColor[ALP_C]; m_ColorInputLUT[11][1] = &RasColor[ALP_C]; m_ColorInputLUT[11][2] = &RasColor[ALP_C]; // ras.rgb
|
||||
m_ColorInputLUT[12][0] = &FixedConstants[8]; m_ColorInputLUT[12][1] = &FixedConstants[8]; m_ColorInputLUT[12][2] = &FixedConstants[8]; // one
|
||||
m_ColorInputLUT[13][0] = &FixedConstants[4]; m_ColorInputLUT[13][1] = &FixedConstants[4]; m_ColorInputLUT[13][2] = &FixedConstants[4]; // half
|
||||
m_ColorInputLUT[14][0] = &StageKonst[0]; m_ColorInputLUT[14][1] = &StageKonst[1]; m_ColorInputLUT[14][2] = &StageKonst[2]; // konst
|
||||
m_ColorInputLUT[15][0] = &FixedConstants[0]; m_ColorInputLUT[15][1] = &FixedConstants[0]; m_ColorInputLUT[15][2] = &FixedConstants[0]; // zero
|
||||
|
||||
m_AlphaInputLUT[0] = &Reg[0][ALP_C]; // prev.a
|
||||
m_AlphaInputLUT[1] = &Reg[1][ALP_C]; // c0.a
|
||||
m_AlphaInputLUT[2] = &Reg[2][ALP_C]; // c1.a
|
||||
m_AlphaInputLUT[3] = &Reg[3][ALP_C]; // c2.a
|
||||
m_AlphaInputLUT[4] = &TexColor[ALP_C]; // tex.a
|
||||
m_AlphaInputLUT[5] = &RasColor[ALP_C]; // ras.a
|
||||
m_AlphaInputLUT[6] = &StageKonst[ALP_C]; // konst.a
|
||||
m_AlphaInputLUT[7] = &Zero16[ALP_C]; // zero
|
||||
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
m_KonstLUT[0][comp] = &FixedConstants[8];
|
||||
m_KonstLUT[1][comp] = &FixedConstants[7];
|
||||
m_KonstLUT[2][comp] = &FixedConstants[6];
|
||||
m_KonstLUT[3][comp] = &FixedConstants[5];
|
||||
m_KonstLUT[4][comp] = &FixedConstants[4];
|
||||
m_KonstLUT[5][comp] = &FixedConstants[3];
|
||||
m_KonstLUT[6][comp] = &FixedConstants[2];
|
||||
m_KonstLUT[7][comp] = &FixedConstants[1];
|
||||
|
||||
m_KonstLUT[12][comp] = &KonstantColors[0][comp];
|
||||
m_KonstLUT[13][comp] = &KonstantColors[1][comp];
|
||||
m_KonstLUT[14][comp] = &KonstantColors[2][comp];
|
||||
m_KonstLUT[15][comp] = &KonstantColors[3][comp];
|
||||
|
||||
m_KonstLUT[16][comp] = &KonstantColors[0][RED_C];
|
||||
m_KonstLUT[17][comp] = &KonstantColors[1][RED_C];
|
||||
m_KonstLUT[18][comp] = &KonstantColors[2][RED_C];
|
||||
m_KonstLUT[19][comp] = &KonstantColors[3][RED_C];
|
||||
m_KonstLUT[20][comp] = &KonstantColors[0][GRN_C];
|
||||
m_KonstLUT[21][comp] = &KonstantColors[1][GRN_C];
|
||||
m_KonstLUT[22][comp] = &KonstantColors[2][GRN_C];
|
||||
m_KonstLUT[23][comp] = &KonstantColors[3][GRN_C];
|
||||
m_KonstLUT[24][comp] = &KonstantColors[0][BLU_C];
|
||||
m_KonstLUT[25][comp] = &KonstantColors[1][BLU_C];
|
||||
m_KonstLUT[26][comp] = &KonstantColors[2][BLU_C];
|
||||
m_KonstLUT[27][comp] = &KonstantColors[3][BLU_C];
|
||||
m_KonstLUT[28][comp] = &KonstantColors[0][ALP_C];
|
||||
m_KonstLUT[29][comp] = &KonstantColors[1][ALP_C];
|
||||
m_KonstLUT[30][comp] = &KonstantColors[2][ALP_C];
|
||||
m_KonstLUT[31][comp] = &KonstantColors[3][ALP_C];
|
||||
}
|
||||
|
||||
m_BiasLUT[0] = 0;
|
||||
m_BiasLUT[1] = 128;
|
||||
m_BiasLUT[2] = -128;
|
||||
m_BiasLUT[3] = 0;
|
||||
|
||||
m_ScaleLShiftLUT[0] = 0;
|
||||
m_ScaleLShiftLUT[1] = 1;
|
||||
m_ScaleLShiftLUT[2] = 2;
|
||||
m_ScaleLShiftLUT[3] = 0;
|
||||
|
||||
m_ScaleRShiftLUT[0] = 0;
|
||||
m_ScaleRShiftLUT[1] = 0;
|
||||
m_ScaleRShiftLUT[2] = 0;
|
||||
m_ScaleRShiftLUT[3] = 1;
|
||||
}
|
||||
|
||||
inline s16 Clamp255(s16 in)
|
||||
{
|
||||
return in>255?255:(in<0?0:in);
|
||||
}
|
||||
|
||||
inline void Tev::SetRasColor(int colorChan, int swaptable)
|
||||
{
|
||||
switch(colorChan)
|
||||
{
|
||||
case 0: // Color0
|
||||
{
|
||||
u8 *color = Color[0];
|
||||
RasColor[0] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[1] = color[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
RasColor[2] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[3] = color[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
break;
|
||||
case 1: // Color1
|
||||
{
|
||||
u8 *color = Color[1];
|
||||
RasColor[0] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[1] = color[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
RasColor[2] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[3] = color[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
break;
|
||||
case 5: // alpha bump
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = AlphaBump;
|
||||
}
|
||||
break;
|
||||
case 6: // alpha bump normalized
|
||||
{
|
||||
u8 normalized = AlphaBump | AlphaBump >> 5;
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = normalized;
|
||||
}
|
||||
break;
|
||||
default: // zero
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawColorRegular(TevStageCombiner::ColorCombiner &cc)
|
||||
{
|
||||
struct {
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
} InputReg;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
|
||||
u16 c = InputReg.c + (InputReg.c >> 7);
|
||||
|
||||
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
||||
temp = cc.op?(-temp >> 8):(temp >> 8);
|
||||
|
||||
s32 result = InputReg.d + temp + m_BiasLUT[cc.bias];
|
||||
result = result << m_ScaleLShiftLUT[cc.shift];
|
||||
result = result >> m_ScaleRShiftLUT[cc.shift];
|
||||
|
||||
Reg[cc.dest][RED_C + i] = result;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawColorCompare(TevStageCombiner::ColorCombiner &cc)
|
||||
{
|
||||
int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here
|
||||
|
||||
u32 a;
|
||||
u32 b;
|
||||
|
||||
struct {
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
} InputReg;
|
||||
|
||||
switch(cmp) {
|
||||
case TEVCMP_R8_GT:
|
||||
{
|
||||
a = *m_ColorInputLUT[cc.a][RED_C] & 0xff;
|
||||
b = *m_ColorInputLUT[cc.b][RED_C] & 0xff;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TEVCMP_R8_EQ:
|
||||
{
|
||||
a = *m_ColorInputLUT[cc.a][RED_C] & 0xff;
|
||||
b = *m_ColorInputLUT[cc.b][RED_C] & 0xff;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_GT:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_EQ:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_GT:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_EQ:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_RGB8_GT:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_RGB8_EQ:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][RED_C + i] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac)
|
||||
{
|
||||
struct {
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
} InputReg;
|
||||
|
||||
|
||||
InputReg.a = *m_AlphaInputLUT[ac.a];
|
||||
InputReg.b = *m_AlphaInputLUT[ac.b];
|
||||
InputReg.c = *m_AlphaInputLUT[ac.c];
|
||||
InputReg.d = *m_AlphaInputLUT[ac.d];
|
||||
|
||||
u16 c = InputReg.c + (InputReg.c >> 7);
|
||||
|
||||
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
||||
temp = ac.op?(-temp >> 8):(temp >> 8);
|
||||
|
||||
s32 result = InputReg.d + temp + m_BiasLUT[ac.bias];
|
||||
result = result << m_ScaleLShiftLUT[ac.shift];
|
||||
result = result >> m_ScaleRShiftLUT[ac.shift];
|
||||
|
||||
Reg[ac.dest][ALP_C] = result;
|
||||
}
|
||||
|
||||
void Tev::DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac)
|
||||
{
|
||||
int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here
|
||||
|
||||
u32 a;
|
||||
u32 b;
|
||||
|
||||
struct {
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
} InputReg;
|
||||
|
||||
switch(cmp) {
|
||||
case TEVCMP_R8_GT:
|
||||
{
|
||||
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
|
||||
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case TEVCMP_R8_EQ:
|
||||
{
|
||||
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
|
||||
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_GT:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_EQ:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_GT:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_EQ:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_A8_GT:
|
||||
{
|
||||
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
|
||||
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_A8_EQ:
|
||||
{
|
||||
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
|
||||
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool AlphaCompare(int alpha, int ref, int comp)
|
||||
{
|
||||
switch(comp) {
|
||||
case ALPHACMP_ALWAYS: return true;
|
||||
case ALPHACMP_NEVER: return false;
|
||||
case ALPHACMP_LEQUAL: return alpha <= ref;
|
||||
case ALPHACMP_LESS: return alpha < ref;
|
||||
case ALPHACMP_GEQUAL: return alpha >= ref;
|
||||
case ALPHACMP_GREATER: return alpha > ref;
|
||||
case ALPHACMP_EQUAL: return alpha == ref;
|
||||
case ALPHACMP_NEQUAL: return alpha != ref;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AlphaTest(int alpha)
|
||||
{
|
||||
bool comp0 = AlphaCompare(alpha, bpmem.alphaFunc.ref0, bpmem.alphaFunc.comp0);
|
||||
bool comp1 = AlphaCompare(alpha, bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp1);
|
||||
|
||||
switch (bpmem.alphaFunc.logic) {
|
||||
case 0: return comp0 && comp1; // and
|
||||
case 1: return comp0 || comp1; // or
|
||||
case 2: return comp0 ^ comp1; // xor
|
||||
case 3: return !(comp0 ^ comp1); // xnor
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline float WrapIndirectCoord(float coord, int wrapMode)
|
||||
{
|
||||
switch (wrapMode) {
|
||||
case ITW_OFF:
|
||||
return coord;
|
||||
case ITW_256:
|
||||
return fmod(coord, 256);
|
||||
case ITW_128:
|
||||
return fmod(coord, 128);
|
||||
case ITW_64:
|
||||
return fmod(coord, 64);
|
||||
case ITW_32:
|
||||
return fmod(coord, 32);
|
||||
case ITW_16:
|
||||
return fmod(coord, 16);
|
||||
case ITW_0:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Tev::Indirect(unsigned int stageNum, float s, float t)
|
||||
{
|
||||
TevStageIndirect &indirect = bpmem.tevind[stageNum];
|
||||
u8 *indmap = IndirectTex[indirect.bt];
|
||||
|
||||
|
||||
float indcoord[3];
|
||||
|
||||
// alpha bump select
|
||||
switch (indirect.bs) {
|
||||
case ITBA_OFF:
|
||||
AlphaBump = 0;
|
||||
break;
|
||||
case ITBA_S:
|
||||
AlphaBump = indmap[ALP_C];
|
||||
break;
|
||||
case ITBA_T:
|
||||
AlphaBump = indmap[BLU_C];
|
||||
break;
|
||||
case ITBA_U:
|
||||
AlphaBump = indmap[GRN_C];
|
||||
break;
|
||||
}
|
||||
|
||||
// bias select
|
||||
s16 biasValue = indirect.fmt==ITF_8?-128:1;
|
||||
s16 bias[3];
|
||||
bias[0] = indirect.bias&1?biasValue:0;
|
||||
bias[1] = indirect.bias&2?biasValue:0;
|
||||
bias[2] = indirect.bias&4?biasValue:0;
|
||||
|
||||
// format
|
||||
switch(indirect.fmt) {
|
||||
case ITF_8:
|
||||
indcoord[0] = (float)indmap[ALP_C] + bias[0];
|
||||
indcoord[1] = (float)indmap[BLU_C] + bias[1];
|
||||
indcoord[2] = (float)indmap[GRN_C] + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf8;
|
||||
break;
|
||||
case ITF_5:
|
||||
indcoord[0] = (float)(indmap[ALP_C] & 0x1f) + bias[0];
|
||||
indcoord[1] = (float)(indmap[BLU_C] & 0x1f) + bias[1];
|
||||
indcoord[2] = (float)(indmap[GRN_C] & 0x1f) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xe0;
|
||||
break;
|
||||
case ITF_4:
|
||||
indcoord[0] = (float)(indmap[ALP_C] & 0x0f) + bias[0];
|
||||
indcoord[1] = (float)(indmap[BLU_C] & 0x0f) + bias[1];
|
||||
indcoord[2] = (float)(indmap[GRN_C] & 0x0f) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf0;
|
||||
break;
|
||||
case ITF_3:
|
||||
indcoord[0] = (float)(indmap[ALP_C] & 0x07) + bias[0];
|
||||
indcoord[1] = (float)(indmap[BLU_C] & 0x07) + bias[1];
|
||||
indcoord[2] = (float)(indmap[GRN_C] & 0x07) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf8;
|
||||
break;
|
||||
}
|
||||
|
||||
float indtevtrans[2] = { 0,0 };
|
||||
|
||||
// matrix multiply
|
||||
int indmtxid = indirect.mid & 3;
|
||||
if (indmtxid)
|
||||
{
|
||||
IND_MTX &indmtx = bpmem.indmtx[indmtxid - 1];
|
||||
int scale = ((u32)indmtx.col0.s0 << 0) |
|
||||
((u32)indmtx.col1.s1 << 2) |
|
||||
((u32)indmtx.col2.s2 << 4);
|
||||
float fscale = 0.0f;
|
||||
|
||||
switch (indirect.mid & 12) {
|
||||
case 0:
|
||||
fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f;
|
||||
indtevtrans[0] = indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] + indmtx.col2.me * indcoord[2];
|
||||
indtevtrans[1] = indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] + indmtx.col2.mf * indcoord[2];
|
||||
break;
|
||||
case 4: // s matrix
|
||||
fscale = powf(2.0f, (float)(scale - 17)) / 256;
|
||||
indtevtrans[0] = s * indcoord[0];
|
||||
indtevtrans[1] = t * indcoord[0];
|
||||
break;
|
||||
case 8: // t matrix
|
||||
fscale = powf(2.0f, (float)(scale - 17)) / 256;
|
||||
indtevtrans[0] = s * indcoord[1];
|
||||
indtevtrans[1] = t * indcoord[1];
|
||||
break;
|
||||
}
|
||||
|
||||
indtevtrans[0] *= fscale;
|
||||
indtevtrans[1] *= fscale;
|
||||
}
|
||||
|
||||
if (indirect.fb_addprev)
|
||||
{
|
||||
TexCoord[0] += WrapIndirectCoord(s, indirect.sw) + indtevtrans[0];
|
||||
TexCoord[1] += WrapIndirectCoord(t, indirect.tw) + indtevtrans[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
TexCoord[0] = WrapIndirectCoord(s, indirect.sw) + indtevtrans[0];
|
||||
TexCoord[1] = WrapIndirectCoord(t, indirect.tw) + indtevtrans[1];
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::Draw()
|
||||
{
|
||||
_assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH);
|
||||
_assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT);
|
||||
|
||||
INCSTAT(stats.thisFrame.tevPixelsIn);
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
|
||||
u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum);
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
float scaleS = bpmem.texscale[stageNum2].getScaleS(stageOdd);
|
||||
float scaleT = bpmem.texscale[stageNum2].getScaleT(stageOdd);
|
||||
|
||||
TextureSampler::Sample(Uv[texcoordSel][0] * scaleS, Uv[texcoordSel][1] * scaleT, Lod[texcoordSel], texmap, IndirectTex[stageNum]);
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
TwoTevStageOrders &order = bpmem.tevorders[stageNum2];
|
||||
TevKSel &kSel = bpmem.tevksel[stageNum2];
|
||||
|
||||
// stage combiners
|
||||
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[stageNum].colorC;
|
||||
TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[stageNum].alphaC;
|
||||
|
||||
int texcoordSel = order.getTexCoord(stageOdd);
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
|
||||
Indirect(stageNum, Uv[texcoordSel][0], Uv[texcoordSel][1]);
|
||||
|
||||
// sample texture
|
||||
if (order.getEnable(stageOdd))
|
||||
{
|
||||
u8 texel[4];
|
||||
|
||||
TextureSampler::Sample(TexCoord[0], TexCoord[1], Lod[texcoordSel], texmap, texel);
|
||||
|
||||
int swaptable = ac.tswap * 2;
|
||||
|
||||
TexColor[0] = texel[bpmem.tevksel[swaptable].swap1];
|
||||
TexColor[1] = texel[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
TexColor[2] = texel[bpmem.tevksel[swaptable].swap1];
|
||||
TexColor[3] = texel[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
|
||||
// set konst for this stage
|
||||
int kc = kSel.getKC(stageOdd);
|
||||
int ka = kSel.getKA(stageOdd);
|
||||
StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]);
|
||||
StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]);
|
||||
StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]);
|
||||
StageKonst[ALP_C] = *(m_KonstLUT[ka][ALP_C]);
|
||||
|
||||
// set color
|
||||
SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2);
|
||||
|
||||
// combine inputs
|
||||
if (cc.bias != 3)
|
||||
DrawColorRegular(cc);
|
||||
else
|
||||
DrawColorCompare(cc);
|
||||
|
||||
if (cc.clamp)
|
||||
{
|
||||
Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]);
|
||||
Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]);
|
||||
Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]);
|
||||
}
|
||||
|
||||
if (ac.bias != 3)
|
||||
DrawAlphaRegular(ac);
|
||||
else
|
||||
DrawAlphaCompare(ac);
|
||||
|
||||
if (ac.clamp)
|
||||
Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]);
|
||||
|
||||
}
|
||||
|
||||
// convert to 8 bits per component
|
||||
u8 output[4] = {(u8)Reg[0][0], (u8)Reg[0][1], (u8)Reg[0][2], (u8)Reg[0][3]};
|
||||
|
||||
if (!AlphaTest(output[ALP_C]))
|
||||
return;
|
||||
|
||||
// z texture
|
||||
if (bpmem.ztex2.op)
|
||||
{
|
||||
s32 ztex = bpmem.ztex1.bias;
|
||||
switch (bpmem.ztex2.type) {
|
||||
case 0: // 8 bit
|
||||
ztex += TexColor[RED_C];
|
||||
break;
|
||||
case 1: // 16 bit
|
||||
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
|
||||
break;
|
||||
case 2: // 24 bit
|
||||
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
|
||||
break;
|
||||
}
|
||||
|
||||
switch (bpmem.ztex2.op) {
|
||||
case ZTEXTURE_ADD:
|
||||
Position[2] += ztex;
|
||||
break;
|
||||
case ZTEXTURE_REPLACE:
|
||||
Position[2] = ztex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
|
||||
{
|
||||
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
|
||||
return;
|
||||
}
|
||||
|
||||
INCSTAT(stats.thisFrame.tevPixelsOut);
|
||||
|
||||
EfbInterface::BlendTev(Position[0], Position[1], output);
|
||||
}
|
||||
|
||||
void Tev::SetRegColor(int reg, int comp, bool konst, s16 color)
|
||||
{
|
||||
if (konst)
|
||||
{
|
||||
KonstantColors[reg][comp] = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
Reg[reg][comp] = color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// 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
|
||||
{
|
||||
// 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];
|
||||
float TexCoord[2];
|
||||
|
||||
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, float s, float t);
|
||||
|
||||
public:
|
||||
s32 Position[3];
|
||||
u8 Color[2][4];
|
||||
float Uv[8][2];
|
||||
float Lod[8];
|
||||
|
||||
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
|
@ -0,0 +1,29 @@
|
|||
// 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 "Common.h"
|
||||
|
||||
namespace TextureEncoder
|
||||
{
|
||||
void Encode(u8 *dest_ptr);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +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 "TextureSampler.h"
|
||||
#include "Main.h"
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
|
||||
inline int iround(float x)
|
||||
{
|
||||
int t;
|
||||
|
||||
__asm
|
||||
{
|
||||
fld x
|
||||
fistp t
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
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(float s, float t, float lod, 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);
|
||||
|
||||
bool linear = false;
|
||||
if (lod > 0 && tm0.min_filter > 4 || lod <= 0 && tm0.mag_filter)
|
||||
linear = true;
|
||||
|
||||
if (linear)
|
||||
{
|
||||
s32 s256 = s32((s - 0.5f) * 256);
|
||||
s32 t256 = s32((t- 0.5f) * 256);
|
||||
|
||||
int imageS = s256 >> 8;
|
||||
int imageSPlus1 = imageS + 1;
|
||||
u32 fractS = s256 & 0xff;
|
||||
fractS += fractS >> 7;
|
||||
|
||||
int imageT = t256 >> 8;
|
||||
int imageTPlus1 = imageT + 1;
|
||||
u32 fractT = t256 & 0xff;
|
||||
fractT += fractT >> 7;
|
||||
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
|
||||
WrapCoord(imageS, tm0.wrap_s, ti0.width);
|
||||
WrapCoord(imageT, tm0.wrap_t, ti0.height);
|
||||
WrapCoord(imageSPlus1, tm0.wrap_s, ti0.width);
|
||||
WrapCoord(imageTPlus1, tm0.wrap_t, ti0.height);
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
|
||||
SetTexel(sampledTex, texel, (256 - fractS) * (256 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (fractS) * (256 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (256 - fractS) * (fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
|
||||
sample[0] = (u8)(texel[0] >> 16);
|
||||
sample[1] = (u8)(texel[1] >> 16);
|
||||
sample[2] = (u8)(texel[2] >> 16);
|
||||
sample[3] = (u8)(texel[3] >> 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
int imageS = int(s);
|
||||
int imageT = int(t);
|
||||
|
||||
WrapCoord(imageS, tm0.wrap_s, ti0.width);
|
||||
WrapCoord(imageT, tm0.wrap_t, ti0.height);
|
||||
|
||||
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +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 _TEXTURESAMPLER_H_
|
||||
#define _TEXTURESAMPLER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
void Sample(float s, float t, float lod, u8 texmap, u8 *sample);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,486 @@
|
|||
// 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 <math.h>
|
||||
|
||||
#include "TransformUnit.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
#include "../../Plugin_VideoDX9/Src/Vec3.h"
|
||||
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
|
||||
void MultiplyVec2Mat24(const float *vec, const float *mat, float *result)
|
||||
{
|
||||
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] + mat[3];
|
||||
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] + mat[7];
|
||||
}
|
||||
|
||||
void MultiplyVec2Mat34(const float *vec, const float *mat, float *result)
|
||||
{
|
||||
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] + mat[3];
|
||||
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] + mat[7];
|
||||
result[2] = mat[8] * vec[0] + mat[9] * vec[1] + mat[10] + mat[11];
|
||||
}
|
||||
|
||||
void MultiplyVec3Mat33(const float *vec, const float *mat, float *result)
|
||||
{
|
||||
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] * vec[2];
|
||||
result[1] = mat[3] * vec[0] + mat[4] * vec[1] + mat[5] * vec[2];
|
||||
result[2] = mat[6] * vec[0] + mat[7] * vec[1] + mat[8] * vec[2];
|
||||
}
|
||||
|
||||
void MultiplyVec3Mat34(const float *vec, const float *mat, float *result)
|
||||
{
|
||||
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] * vec[2] + mat[3];
|
||||
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] * vec[2] + mat[7];
|
||||
result[2] = mat[8] * vec[0] + mat[9] * vec[1] + mat[10] * vec[2] + mat[11];
|
||||
}
|
||||
|
||||
void MultipleVec3Perspective(const float *vec, const float *proj, float *result)
|
||||
{
|
||||
result[0] = proj[0] * vec[0] + proj[1] * vec[2];
|
||||
result[1] = proj[2] * vec[1] + proj[3] * vec[2];
|
||||
//result[2] = (proj[4] * vec[2] + proj[5]);
|
||||
result[2] = (proj[4] * vec[2] + proj[5]) * (1.0f - (float)1e-7);
|
||||
result[3] = -vec[2];
|
||||
}
|
||||
|
||||
void MultipleVec3Ortho(const float *vec, const float *proj, float *result)
|
||||
{
|
||||
result[0] = proj[0] * vec[0] + proj[1];
|
||||
result[1] = proj[2] * vec[1] + proj[3];
|
||||
result[2] = proj[4] * vec[2] + proj[5];
|
||||
result[3] = 1;
|
||||
}
|
||||
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst)
|
||||
{
|
||||
const float* mat = (const float*)&xfregs.posMatrices[src->posMtx * 4];
|
||||
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
|
||||
|
||||
if (xfregs.projection[6] == 0)
|
||||
{
|
||||
MultipleVec3Perspective(dst->mvPosition, xfregs.projection, dst->projectedPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
MultipleVec3Ortho(dst->mvPosition, xfregs.projection, dst->projectedPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst)
|
||||
{
|
||||
const float* mat = (const float*)&xfregs.normalMatrices[(src->posMtx & 31) * 3];
|
||||
|
||||
if (nbt)
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]);
|
||||
MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]);
|
||||
Vec3 *norm0 = (Vec3*)dst->normal[0];
|
||||
norm0->normalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
Vec3 *norm0 = (Vec3*)dst->normal[0];
|
||||
norm0->normalize();
|
||||
}
|
||||
}
|
||||
|
||||
inline void TransformTexCoordRegular(const TexMtxInfo &texinfo, int coordNum, const InputVertexData *srcVertex, OutputVertexData *dstVertex)
|
||||
{
|
||||
const float *src;
|
||||
switch (texinfo.sourcerow)
|
||||
{
|
||||
case XF_SRCGEOM_INROW:
|
||||
src = srcVertex->position;
|
||||
break;
|
||||
case XF_SRCNORMAL_INROW:
|
||||
src = srcVertex->normal[0];
|
||||
break;
|
||||
case XF_SRCBINORMAL_T_INROW:
|
||||
src = srcVertex->normal[1];
|
||||
break;
|
||||
case XF_SRCBINORMAL_B_INROW:
|
||||
src = srcVertex->normal[2];
|
||||
break;
|
||||
default:
|
||||
_assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
|
||||
src = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW];
|
||||
break;
|
||||
}
|
||||
|
||||
const float *mat = (const float*)&xfregs.posMatrices[srcVertex->texMtx[coordNum] * 4];
|
||||
float *dst = dstVertex->texCoords[coordNum];
|
||||
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11)
|
||||
{
|
||||
MultiplyVec2Mat34(src, mat, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiplyVec3Mat34(src, mat, dst);
|
||||
}
|
||||
|
||||
if (xfregs.dualTexTrans)
|
||||
{
|
||||
float tempCoord[3];
|
||||
|
||||
// normalize
|
||||
const PostMtxInfo &postInfo = xfregs.postMtxInfo[coordNum];
|
||||
if (postInfo.normalize)
|
||||
{
|
||||
float length = sqrtf(dst[0] * dst[0] + dst[1] * dst[1] + dst[2] * dst[2]);
|
||||
float invL = 1.0f / length;
|
||||
tempCoord[0] = invL * dst[0];
|
||||
tempCoord[1] = invL * dst[1];
|
||||
tempCoord[2] = invL * dst[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
tempCoord[0] = dst[0];
|
||||
tempCoord[1] = dst[1];
|
||||
tempCoord[2] = dst[2];
|
||||
}
|
||||
|
||||
const float *postMat = (const float*)&xfregs.postMatrices[postInfo.index * 4];
|
||||
MultiplyVec3Mat34(tempCoord, postMat, dst);
|
||||
}
|
||||
}
|
||||
|
||||
struct LightPointer
|
||||
{
|
||||
u32 reserved[3];
|
||||
u8 color[4];
|
||||
Vec3 cosatt;
|
||||
Vec3 distatt;
|
||||
Vec3 pos;
|
||||
Vec3 dir;
|
||||
};
|
||||
|
||||
inline void AddIntegerColor(const u8 *src, Vec3 &dst)
|
||||
{
|
||||
dst.x += src[1];
|
||||
dst.y += src[2];
|
||||
dst.z += src[3];
|
||||
}
|
||||
|
||||
inline void AddScaledIntegerColor(const u8 *src, float scale, Vec3 &dst)
|
||||
{
|
||||
dst.x += src[1] * scale;
|
||||
dst.y += src[2] * scale;
|
||||
dst.z += src[3] * scale;
|
||||
}
|
||||
|
||||
inline float Clamp(float val, float a, float b)
|
||||
{
|
||||
return val<a?a:val>b?b:val;
|
||||
}
|
||||
|
||||
void LightColor(const float *vertexPos, const float *normal, u8 lightNum, const LitChannel &chan, Vec3 &lightCol)
|
||||
{
|
||||
// must be the size of 3 32bit floats for the light pointer to be valid
|
||||
_assert_(sizeof(Vec3) == 12);
|
||||
|
||||
const Vec3 *pos = (const Vec3*)vertexPos;
|
||||
const Vec3 *norm0 = (const Vec3*)normal;
|
||||
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*lightNum];
|
||||
|
||||
if (!(chan.attnfunc & 1)) {
|
||||
// atten disabled
|
||||
switch (chan.diffusefunc) {
|
||||
case LIGHTDIF_NONE:
|
||||
AddIntegerColor(light->color, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
Vec3 ldir = (light->pos - *pos).normalized();
|
||||
float diffuse = ldir * (*norm0);
|
||||
AddScaledIntegerColor(light->color, diffuse, lightCol);
|
||||
}
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
Vec3 ldir = (light->pos - *pos).normalized();
|
||||
float diffuse = max(0.0f, ldir * (*norm0));
|
||||
AddScaledIntegerColor(light->color, diffuse, lightCol);
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else { // spec and spot
|
||||
// not sure about divide by zero checks
|
||||
Vec3 ldir = light->pos - *pos;
|
||||
float attn;
|
||||
|
||||
if (chan.attnfunc == 3) { // spot
|
||||
float dist2 = ldir.length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = max(0.0f, ldir * light->dir);
|
||||
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = distAtt==0.0f?0.0f:(max(0.0f, cosAtt) / distAtt);
|
||||
}
|
||||
else if (chan.attnfunc == 1) { // specular
|
||||
attn = (light->pos * (*norm0)) > 0 ? max(0.0f, (light->dir * (*norm0))) : 0;
|
||||
ldir.set(1.0f, attn, attn * attn);
|
||||
|
||||
float cosAtt = light->cosatt * ldir;
|
||||
float distAtt = light->distatt * ldir;
|
||||
attn = distAtt==0.0f?1.0f:(max(0.0f, cosAtt) / distAtt);
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc) {
|
||||
case LIGHTDIF_NONE:
|
||||
AddScaledIntegerColor(light->color, attn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
float difAttn = ldir * (*norm0);
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
}
|
||||
break;
|
||||
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
float difAttn = max(0.0f, ldir * (*norm0));
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightAlpha(const float *vertexPos, const float *normal, u8 lightNum, const LitChannel &chan, float &lightCol)
|
||||
{
|
||||
// must be the size of 3 32bit floats for the light pointer to be valid
|
||||
_assert_(sizeof(Vec3) == 12);
|
||||
|
||||
const Vec3 *pos = (const Vec3*)vertexPos;
|
||||
const Vec3 *norm0 = (const Vec3*)normal;
|
||||
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*lightNum];
|
||||
|
||||
if (!(chan.attnfunc & 1)) {
|
||||
// atten disabled
|
||||
switch (chan.diffusefunc) {
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0];
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
Vec3 ldir = (light->pos - *pos).normalized();
|
||||
float diffuse = ldir * (*norm0);
|
||||
lightCol += light->color[0] * diffuse;
|
||||
}
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
Vec3 ldir = (light->pos - *pos).normalized();
|
||||
float diffuse = max(0.0f, ldir * (*norm0));
|
||||
lightCol += light->color[0] * diffuse;
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else { // spec and spot
|
||||
Vec3 ldir = light->pos - *pos;
|
||||
float attn;
|
||||
|
||||
if (chan.attnfunc == 3) { // spot
|
||||
float dist2 = ldir.length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = max(0.0f, ldir * light->dir);
|
||||
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = distAtt==0.0f?0.0f:(max(0.0f, cosAtt) / distAtt);
|
||||
}
|
||||
else if (chan.attnfunc == 1) { // specular
|
||||
attn = (light->pos * (*norm0)) > 0 ? max(0.0f, (light->dir * (*norm0))) : 0;
|
||||
ldir.set(1.0f, attn, attn * attn);
|
||||
|
||||
float cosAtt = light->cosatt * ldir;
|
||||
float distAtt = light->distatt * ldir;
|
||||
attn = distAtt==0.0f?1.0f:(max(0.0f, cosAtt) / distAtt);
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc) {
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0] * attn;
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
float difAttn = ldir * (*norm0);
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
float difAttn = max(0.0f, ldir * (*norm0));
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst)
|
||||
{
|
||||
for (u32 chan = 0; chan < xfregs.nNumChans; chan++)
|
||||
{
|
||||
// abgr
|
||||
u8 matcolor[4];
|
||||
u8 chancolor[4];
|
||||
|
||||
// color
|
||||
LitChannel &colorchan = xfregs.color[chan];
|
||||
if (colorchan.matsource)
|
||||
*(u32*)matcolor = *(u32*)src->color[chan]; // vertex
|
||||
else
|
||||
*(u32*)matcolor = xfregs.matColor[chan];
|
||||
|
||||
if (colorchan.enablelighting)
|
||||
{
|
||||
Vec3 lightCol;
|
||||
if (colorchan.ambsource)
|
||||
{
|
||||
// vertex
|
||||
lightCol.x = src->color[chan][1];
|
||||
lightCol.y = src->color[chan][2];
|
||||
lightCol.z = src->color[chan][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *ambColor = (u8*)&xfregs.ambColor[chan];
|
||||
lightCol.x = ambColor[1];
|
||||
lightCol.y = ambColor[2];
|
||||
lightCol.z = ambColor[3];
|
||||
}
|
||||
|
||||
u8 mask = colorchan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (mask&(1<<i))
|
||||
LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol);
|
||||
}
|
||||
|
||||
float inv = 1.0f / 255.0f;
|
||||
chancolor[1] = (u8)(matcolor[1] * Clamp(lightCol.x * inv, 0.0f, 1.0f));
|
||||
chancolor[2] = (u8)(matcolor[2] * Clamp(lightCol.y * inv, 0.0f, 1.0f));
|
||||
chancolor[3] = (u8)(matcolor[3] * Clamp(lightCol.z * inv, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u32*)chancolor = *(u32*)matcolor;
|
||||
}
|
||||
|
||||
// alpha
|
||||
LitChannel &alphachan = xfregs.alpha[chan];
|
||||
if (alphachan.matsource)
|
||||
matcolor[0] = src->color[chan][0]; // vertex
|
||||
else
|
||||
matcolor[0] = xfregs.matColor[chan] & 0xff;
|
||||
|
||||
if (xfregs.alpha[chan].enablelighting)
|
||||
{
|
||||
float lightCol;
|
||||
if (alphachan.ambsource)
|
||||
lightCol = src->color[chan][0]; // vertex
|
||||
else
|
||||
lightCol = (float)(xfregs.ambColor[chan] & 0xff);
|
||||
|
||||
u8 mask = alphachan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (mask&(1<<i))
|
||||
LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol);
|
||||
}
|
||||
|
||||
chancolor[0] = (u8)(matcolor[0] * Clamp(lightCol / 255.0f, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
chancolor[0] = matcolor[0];
|
||||
}
|
||||
|
||||
// abgr -> rgba
|
||||
*(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst)
|
||||
{
|
||||
for (u32 coordNum = 0; coordNum < xfregs.numTexGens; coordNum++)
|
||||
{
|
||||
const TexMtxInfo &texinfo = xfregs.texMtxInfo[coordNum];
|
||||
|
||||
switch (texinfo.texgentype)
|
||||
{
|
||||
case XF_TEXGEN_REGULAR:
|
||||
TransformTexCoordRegular(texinfo, coordNum, src, dst);
|
||||
break;
|
||||
case XF_TEXGEN_EMBOSS_MAP:
|
||||
{
|
||||
const Vec3 *pos = (const Vec3*)dst->mvPosition;
|
||||
const Vec3 *norm1 = (const Vec3*)dst->normal[1];
|
||||
const Vec3 *norm2 = (const Vec3*)dst->normal[2];
|
||||
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*texinfo.embosslightshift];
|
||||
|
||||
Vec3 ldir = (light->pos - *pos).normalized();
|
||||
float d1 = ldir * (*norm1);
|
||||
float d2 = ldir * (*norm2);
|
||||
|
||||
dst->texCoords[coordNum][0] = dst->texCoords[texinfo.embosssourceshift][0] + d1;
|
||||
dst->texCoords[coordNum][1] = dst->texCoords[texinfo.embosssourceshift][1] + d2;
|
||||
dst->texCoords[coordNum][2] = dst->texCoords[texinfo.embosssourceshift][2];
|
||||
}
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC0:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum][0] = (float)dst->color[0][0] / 255.0f;
|
||||
dst->texCoords[coordNum][1] = (float)dst->color[0][1] / 255.0f;
|
||||
dst->texCoords[coordNum][2] = 1.0f;
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC1:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum][0] = (float)dst->color[1][0] / 255.0f;
|
||||
dst->texCoords[coordNum][1] = (float)dst->color[1][1] / 255.0f;
|
||||
dst->texCoords[coordNum][2] = 1.0f;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +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 _TRANSFORM_UNIT_H_
|
||||
#define _TRANSFORM_UNIT_H_
|
||||
|
||||
struct InputVertexData;
|
||||
struct OutputVertexData;
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
void MultiplyVec2Mat24(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec2Mat34(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec3Mat33(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec3Mat34(const float *vec, const float *mat, float *result);
|
||||
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst);
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
// 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 "VertexFormatConverter.h"
|
||||
|
||||
|
||||
namespace VertexFormatConverter
|
||||
{
|
||||
void LoadNormal1_Byte(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
dst->normal[0][0] = (float)(s8)src[0] / 128;
|
||||
dst->normal[0][1] = (float)(s8)src[1] / 128;
|
||||
dst->normal[0][2] = (float)(s8)src[2] / 128;
|
||||
}
|
||||
|
||||
void LoadNormal1_Short(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
dst->normal[0][0] = (float)((s16*)src)[0] / 32768;
|
||||
dst->normal[0][1] = (float)((s16*)src)[1] / 32768;
|
||||
dst->normal[0][2] = (float)((s16*)src)[2] / 32768;
|
||||
}
|
||||
|
||||
void LoadNormal1_Float(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
dst->normal[0][0] = ((float*)src)[0];
|
||||
dst->normal[0][1] = ((float*)src)[1];
|
||||
dst->normal[0][2] = ((float*)src)[2];
|
||||
}
|
||||
|
||||
void LoadNormal3_Byte(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
for (int i = 0, j = 0; i < 3; i++, j+=3)
|
||||
{
|
||||
dst->normal[i][0] = (float)(s8)src[j + 0] / 128;
|
||||
dst->normal[i][1] = (float)(s8)src[j + 1] / 128;
|
||||
dst->normal[i][2] = (float)(s8)src[j + 2] / 128;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadNormal3_Short(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
for (int i = 0, j = 0; i < 3; i++, j+=3)
|
||||
{
|
||||
dst->normal[i][0] = (float)((s16*)src)[j + 0] / 32768;
|
||||
dst->normal[i][1] = (float)((s16*)src)[j + 1] / 32768;
|
||||
dst->normal[i][2] = (float)((s16*)src)[j + 2] / 32768;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadNormal3_Float(InputVertexData *dst, u8 *src)
|
||||
{
|
||||
for (int i = 0, j = 0; i < 3; i++, j+=3)
|
||||
{
|
||||
dst->normal[i][0] = ((float*)src)[j + 0];
|
||||
dst->normal[i][1] = ((float*)src)[j + 1];
|
||||
dst->normal[i][2] = ((float*)src)[j + 2];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// 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 _VERTEXFORMATCONVERTER_H
|
||||
#define _VERTEXFORMATCONVERTER_H
|
||||
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
namespace VertexFormatConverter
|
||||
{
|
||||
typedef void (*NormalConverter)(InputVertexData*, u8*);
|
||||
|
||||
void LoadNormal1_Byte(InputVertexData *dst, u8 *src);
|
||||
void LoadNormal1_Short(InputVertexData *dst, u8 *src);
|
||||
void LoadNormal1_Float(InputVertexData *dst, u8 *src);
|
||||
void LoadNormal3_Byte(InputVertexData *dst, u8 *src);
|
||||
void LoadNormal3_Short(InputVertexData *dst, u8 *src);
|
||||
void LoadNormal3_Float(InputVertexData *dst, u8 *src);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,403 @@
|
|||
// 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();
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
switch (g_VtxDesc.Position) {
|
||||
case NOT_PRESENT: {_assert_msg_(VIDEO, 0, "Vertex descriptor without position!"); } break;
|
||||
case DIRECT:
|
||||
switch (m_CurrentVat->g0.PosFormat) {
|
||||
case FORMAT_UBYTE: m_VertexSize += m_CurrentVat->g0.PosElements?3:2; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_UByte3:Pos_ReadDirect_UByte2); break;
|
||||
case FORMAT_BYTE: m_VertexSize += m_CurrentVat->g0.PosElements?3:2; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Byte3:Pos_ReadDirect_Byte2); break;
|
||||
case FORMAT_USHORT: m_VertexSize += m_CurrentVat->g0.PosElements?6:4; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_UShort3:Pos_ReadDirect_UShort2); break;
|
||||
case FORMAT_SHORT: m_VertexSize += m_CurrentVat->g0.PosElements?6:4; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Short3:Pos_ReadDirect_Short2); break;
|
||||
case FORMAT_FLOAT: m_VertexSize += m_CurrentVat->g0.PosElements?12:8; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Float3:Pos_ReadDirect_Float2); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadPosition);
|
||||
break;
|
||||
case INDEX8:
|
||||
switch (m_CurrentVat->g0.PosFormat) {
|
||||
case FORMAT_UBYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_UByte3:Pos_ReadIndex8_UByte2); break;
|
||||
case FORMAT_BYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Byte3:Pos_ReadIndex8_Byte2); break;
|
||||
case FORMAT_USHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_UShort3:Pos_ReadIndex8_UShort2); break;
|
||||
case FORMAT_SHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Short3:Pos_ReadIndex8_Short2); break;
|
||||
case FORMAT_FLOAT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Float3:Pos_ReadIndex8_Float2); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadPosition);
|
||||
m_VertexSize += 1;
|
||||
break;
|
||||
case INDEX16:
|
||||
switch (m_CurrentVat->g0.PosFormat) {
|
||||
case FORMAT_UBYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_UByte3:Pos_ReadIndex16_UByte2); break;
|
||||
case FORMAT_BYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Byte3:Pos_ReadIndex16_Byte2); break;
|
||||
case FORMAT_USHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_UShort3:Pos_ReadIndex16_UShort2); break;
|
||||
case FORMAT_SHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Short3:Pos_ReadIndex16_Short2); break;
|
||||
case FORMAT_FLOAT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Float3:Pos_ReadIndex16_Float2); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadPosition);
|
||||
m_VertexSize += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
int elements = tcElements[i];
|
||||
switch (tcDesc[i])
|
||||
{
|
||||
case NOT_PRESENT:
|
||||
m_texCoordLoader[i] = NULL;
|
||||
break;
|
||||
case DIRECT:
|
||||
switch (tcFormat[i])
|
||||
{
|
||||
case FORMAT_UBYTE: m_VertexSize += elements?2:1; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_UByte2:TexCoord_ReadDirect_UByte1); break;
|
||||
case FORMAT_BYTE: m_VertexSize += elements?2:1; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Byte2:TexCoord_ReadDirect_Byte1); break;
|
||||
case FORMAT_USHORT: m_VertexSize += elements?4:2; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_UShort2:TexCoord_ReadDirect_UShort1); break;
|
||||
case FORMAT_SHORT: m_VertexSize += elements?4:2; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Short2:TexCoord_ReadDirect_Short1); break;
|
||||
case FORMAT_FLOAT: m_VertexSize += elements?8:4; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Float2:TexCoord_ReadDirect_Float1); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadTexCoord, i);
|
||||
break;
|
||||
case INDEX8:
|
||||
m_VertexSize += 1;
|
||||
switch (tcFormat[i])
|
||||
{
|
||||
case FORMAT_UBYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_UByte2:TexCoord_ReadIndex8_UByte1); break;
|
||||
case FORMAT_BYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Byte2:TexCoord_ReadIndex8_Byte1); break;
|
||||
case FORMAT_USHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_UShort2:TexCoord_ReadIndex8_UShort1); break;
|
||||
case FORMAT_SHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Short2:TexCoord_ReadIndex8_Short1); break;
|
||||
case FORMAT_FLOAT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Float2:TexCoord_ReadIndex8_Float1); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadTexCoord, i);
|
||||
break;
|
||||
case INDEX16:
|
||||
m_VertexSize += 2;
|
||||
switch (tcFormat[i])
|
||||
{
|
||||
case FORMAT_UBYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_UByte2:TexCoord_ReadIndex16_UByte1); break;
|
||||
case FORMAT_BYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Byte2:TexCoord_ReadIndex16_Byte1); break;
|
||||
case FORMAT_USHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_UShort2:TexCoord_ReadIndex16_UShort1); break;
|
||||
case FORMAT_SHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Short2:TexCoord_ReadIndex16_Short1); break;
|
||||
case FORMAT_FLOAT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Float2:TexCoord_ReadIndex16_Float1); break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
AddAttributeLoader(LoadTexCoord, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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_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]();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// 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 _VERTEXLOADER_H_
|
||||
#define _VERTEXLOADER_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "VertexFormatConverter.h"
|
||||
#include "CPMemLoader.h"
|
||||
|
||||
class SetupUnit;
|
||||
|
||||
class VertexLoader
|
||||
{
|
||||
u32 m_VertexSize;
|
||||
|
||||
VAT* m_CurrentVat;
|
||||
|
||||
TPipelineFunction m_positionLoader;
|
||||
TPipelineFunction m_normalLoader;
|
||||
TPipelineFunction m_colorLoader[2];
|
||||
TPipelineFunction m_texCoordLoader[8];
|
||||
|
||||
VertexFormatConverter::NormalConverter m_normalConverter;
|
||||
|
||||
InputVertexData m_Vertex;
|
||||
|
||||
typedef void (*AttributeLoader)(VertexLoader*, InputVertexData*, u8);
|
||||
struct AttrLoaderCall
|
||||
{
|
||||
AttributeLoader loader;
|
||||
u8 index;
|
||||
};
|
||||
AttrLoaderCall m_AttributeLoaders[1+8+1+1+2+8];
|
||||
int m_NumAttributeLoaders;
|
||||
void AddAttributeLoader(AttributeLoader loader, u8 index=0);
|
||||
|
||||
// attribute loader functions
|
||||
static void LoadPosMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadTexMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
static void LoadPosition(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadNormal(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadColor(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
static void LoadTexCoord(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
|
||||
SetupUnit *m_SetupUnit;
|
||||
|
||||
public:
|
||||
VertexLoader();
|
||||
~VertexLoader();
|
||||
|
||||
void SetFormat(u8 attributeIndex, u8 primitiveType);
|
||||
|
||||
u32 GetVertexSize() { return m_VertexSize; }
|
||||
|
||||
void LoadVertex();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
// 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 "NativeVertexFormat.h"
|
||||
|
||||
#include "../../../Core/VideoCommon/Src/VertexLoader_Position.h"
|
|
@ -0,0 +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 "../../../Core/VideoCommon/Src/VideoCommon.h"
|
|
@ -0,0 +1,66 @@
|
|||
// 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 "IniFile.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "../../../Core/Core/Src/ConfigManager.h" // FIXME
|
||||
|
||||
Config g_Config;
|
||||
|
||||
Config::Config()
|
||||
{
|
||||
bFullscreen = false;
|
||||
bHideCursor = false;
|
||||
renderToMainframe = false;
|
||||
|
||||
bShowStats = false;
|
||||
bDumpTextures = false;
|
||||
bDumpObjects = false;
|
||||
bDumpFrames = false;
|
||||
|
||||
bHwRasterizer = false;
|
||||
|
||||
nFrameSkip = 0;
|
||||
|
||||
drawStart = 0;
|
||||
drawEnd = 100000;
|
||||
}
|
||||
|
||||
void Config::Load()
|
||||
{
|
||||
std::string temp;
|
||||
IniFile iniFile;
|
||||
iniFile.Load(FULL_CONFIG_DIR "gfx_software.ini");
|
||||
|
||||
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
|
||||
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Config::Save()
|
||||
{
|
||||
IniFile iniFile;
|
||||
iniFile.Load(FULL_CONFIG_DIR "gfx_software.ini");
|
||||
|
||||
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
|
||||
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
|
||||
|
||||
iniFile.Save(FULL_CONFIG_DIR "gfx_opengl.ini");
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// 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 bHwRasterizer;
|
||||
|
||||
u32 nFrameSkip;
|
||||
|
||||
u32 drawStart;
|
||||
u32 drawEnd;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Config);
|
||||
};
|
||||
|
||||
extern Config g_Config;
|
||||
|
||||
#endif // _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
|
|
@ -0,0 +1,404 @@
|
|||
// 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
|
||||
// Use wxInitialize() if you don't want GUI instead of the following 12 lines
|
||||
wxSetInstance((HINSTANCE)hinstDLL);
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
wxEntryStart(argc, argv);
|
||||
if (!wxTheApp || !wxTheApp->CallOnInit())
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
wxEntryCleanup();
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
HWND m_hMain = NULL; // The main CPanel
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
HWND GetChildParentWnd()
|
||||
{
|
||||
return m_hMain;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
HDC hdc;
|
||||
PAINTSTRUCT ps;
|
||||
switch( iMsg )
|
||||
{
|
||||
case WM_CREATE:
|
||||
PostMessage(m_hMain, WM_USER, OPENGL_WM_USER_CREATE, (int)m_hParent);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
hdc = BeginPaint( hWnd, &ps );
|
||||
EndPaint( hWnd, &ps );
|
||||
return 0;
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
switch( LOWORD( wParam ))
|
||||
{
|
||||
case VK_RETURN:
|
||||
// Pressing Alt+Enter switch FullScreen/Windowed
|
||||
if (m_hParent == NULL && !g_Config.renderToMainframe)
|
||||
{
|
||||
ToggleFullscreen(hWnd);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
switch( LOWORD( wParam ))
|
||||
{
|
||||
case VK_ESCAPE:
|
||||
if (g_Config.bFullscreen)
|
||||
{
|
||||
// Pressing Esc switch to Windowed in Fullscreen mode
|
||||
ToggleFullscreen(hWnd);
|
||||
return 0;
|
||||
}
|
||||
else if (!g_Config.renderToMainframe)
|
||||
{
|
||||
// And stops the emulation when already in Windowed mode
|
||||
PostMessage(m_hMain, WM_USER, OPENGL_WM_USER_STOP, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g_VideoInitialize.pKeyPress(LOWORD(wParam), GetAsyncKeyState(VK_SHIFT) != 0, GetAsyncKeyState(VK_CONTROL) != 0);
|
||||
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_hMain, 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 nessesary */
|
||||
case WM_USER:
|
||||
/* I set wParam to 10 just in case there are other WM_USER events. If we want more
|
||||
WM_USER cases we would start making wParam or lParam cases */
|
||||
if (wParam == 10)
|
||||
{
|
||||
if (lParam)
|
||||
SetCursor(hCursor);
|
||||
else
|
||||
SetCursor(hCursorBlank);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Post thes 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)
|
||||
{
|
||||
// Simple hack to easily exit without stopping. Hope to fix the stopping errors soon.
|
||||
ExitProcess(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_DESTROY:
|
||||
//Shutdown();
|
||||
//PostQuitMessage( 0 ); // Call WM_QUIT
|
||||
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:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, iMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
// 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 = m_hMain = 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;
|
||||
|
||||
// I save this to m_hMain instead of m_hParent because it casused problems otherwise
|
||||
m_hMain = (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()
|
||||
{
|
||||
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
|
|
@ -0,0 +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_
|
|
@ -0,0 +1,73 @@
|
|||
// 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();
|
||||
}
|
||||
|
||||
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* xfmem = (u32*)&xfregs;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array]*index + i*4);
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
// 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 _XFMEMLOADER_H_
|
||||
#define _XFMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
/////////////
|
||||
// Lighting
|
||||
/////////////
|
||||
|
||||
#define XF_TEXPROJ_ST 0
|
||||
#define XF_TEXPROJ_STQ 1
|
||||
|
||||
#define XF_TEXINPUT_AB11 0
|
||||
#define XF_TEXINPUT_ABC1 1
|
||||
|
||||
#define XF_TEXGEN_REGULAR 0
|
||||
#define XF_TEXGEN_EMBOSS_MAP 1 // used when bump mapping
|
||||
#define XF_TEXGEN_COLOR_STRGBC0 2
|
||||
#define XF_TEXGEN_COLOR_STRGBC1 3
|
||||
|
||||
#define XF_SRCGEOM_INROW 0 // input is abc
|
||||
#define XF_SRCNORMAL_INROW 1 // input is abc
|
||||
#define XF_SRCCOLORS_INROW 2
|
||||
#define XF_SRCBINORMAL_T_INROW 3 // input is abc
|
||||
#define XF_SRCBINORMAL_B_INROW 4 // input is abc
|
||||
#define XF_SRCTEX0_INROW 5
|
||||
#define XF_SRCTEX1_INROW 6
|
||||
#define XF_SRCTEX2_INROW 7
|
||||
#define XF_SRCTEX3_INROW 8
|
||||
#define XF_SRCTEX4_INROW 9
|
||||
#define XF_SRCTEX5_INROW 10
|
||||
#define XF_SRCTEX6_INROW 11
|
||||
#define XF_SRCTEX7_INROW 12
|
||||
|
||||
#define GX_SRC_REG 0
|
||||
#define GX_SRC_VTX 1
|
||||
|
||||
struct Light
|
||||
{
|
||||
u32 useless[3];
|
||||
u32 color; //rgba
|
||||
float a0; //attenuation
|
||||
float a1;
|
||||
float a2;
|
||||
float k0; //k stuff
|
||||
float k1;
|
||||
float k2;
|
||||
union
|
||||
{
|
||||
struct {
|
||||
float dpos[3];
|
||||
float ddir[3]; // specular lights only
|
||||
};
|
||||
struct {
|
||||
float sdir[3];
|
||||
float shalfangle[3]; // specular lights only
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define LIGHTDIF_NONE 0
|
||||
#define LIGHTDIF_SIGN 1
|
||||
#define LIGHTDIF_CLAMP 2
|
||||
|
||||
#define LIGHTATTN_SPEC 0 // specular attenuation
|
||||
#define LIGHTATTN_SPOT 1 // distance/spotlight attenuation
|
||||
#define LIGHTATTN_NONE 2
|
||||
#define LIGHTATTN_DIR 3
|
||||
|
||||
union LitChannel
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned matsource : 1;
|
||||
unsigned enablelighting : 1;
|
||||
unsigned lightMask0_3 : 4;
|
||||
unsigned ambsource : 1;
|
||||
unsigned diffusefunc : 2; // LIGHTDIF_X
|
||||
unsigned attnfunc : 2; // LIGHTATTN_X
|
||||
unsigned lightMask4_7 : 4;
|
||||
unsigned unused : 17;
|
||||
};
|
||||
u32 hex;
|
||||
unsigned int GetFullLightMask() const
|
||||
{
|
||||
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
union INVTXSPEC
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned numcolors : 2;
|
||||
unsigned numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals
|
||||
unsigned numtextures : 4;
|
||||
unsigned unused : 24;
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
union TXFMatrixIndexA
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned PosNormalMtxIdx : 6;
|
||||
unsigned Tex0MtxIdx : 6;
|
||||
unsigned Tex1MtxIdx : 6;
|
||||
unsigned Tex2MtxIdx : 6;
|
||||
unsigned Tex3MtxIdx : 6;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 Hex : 30;
|
||||
u32 unused : 2;
|
||||
};
|
||||
};
|
||||
|
||||
union TXFMatrixIndexB
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned Tex4MtxIdx : 6;
|
||||
unsigned Tex5MtxIdx : 6;
|
||||
unsigned Tex6MtxIdx : 6;
|
||||
unsigned Tex7MtxIdx : 6;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 Hex : 24;
|
||||
u32 unused : 8;
|
||||
};
|
||||
};
|
||||
|
||||
struct Viewport
|
||||
{
|
||||
float wd;
|
||||
float ht;
|
||||
float zRange;
|
||||
float xOrig;
|
||||
float yOrig;
|
||||
float farZ;
|
||||
};
|
||||
|
||||
union TexMtxInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned unknown : 1;
|
||||
unsigned projection : 1; // XF_TEXPROJ_X
|
||||
unsigned inputform : 2; // XF_TEXINPUT_X
|
||||
unsigned texgentype : 3; // XF_TEXGEN_X
|
||||
unsigned sourcerow : 5; // XF_SRCGEOM_X
|
||||
unsigned embosssourceshift : 3; // what generated texcoord to use
|
||||
unsigned embosslightshift : 3; // light index that is used
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
union PostMtxInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned index : 6; // base row of dual transform matrix
|
||||
unsigned unused : 2;
|
||||
unsigned normalize : 1; // normalize before send operation
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
struct XFRegisters
|
||||
{
|
||||
u32 posMatrices[256]; // 0x0000 - 0x00ff
|
||||
u32 unk0[768]; // 0x0100 - 0x03ff
|
||||
u32 normalMatrices[96]; // 0x0400 - 0x045f
|
||||
u32 unk1[160]; // 0x0460 - 0x04ff
|
||||
u32 postMatrices[256]; // 0x0500 - 0x05ff
|
||||
u32 lights[128]; // 0x0600 - 0x067f
|
||||
u32 unk2[2432]; // 0x0680 - 0x0fff
|
||||
u32 error; // 0x1000
|
||||
u32 diag; // 0x1001
|
||||
u32 state0; // 0x1002
|
||||
u32 state1; // 0x1003
|
||||
u32 xfClock; // 0x1004
|
||||
u32 clipDisable; // 0x1005
|
||||
u32 perf0; // 0x1006
|
||||
u32 perf1; // 0x1007
|
||||
INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input
|
||||
u32 nNumChans; // 0x1009
|
||||
u32 ambColor[2]; // 0x100a, 0x100b
|
||||
u32 matColor[2]; // 0x100c, 0x100d
|
||||
LitChannel color[2]; // 0x100e, 0x100f
|
||||
LitChannel alpha[2]; // 0x1010, 0x1011
|
||||
u32 dualTexTrans; // 0x1012
|
||||
u32 unk3; // 0x1013
|
||||
u32 unk4; // 0x1014
|
||||
u32 unk5; // 0x1015
|
||||
u32 unk6; // 0x1016
|
||||
u32 unk7; // 0x1017
|
||||
TXFMatrixIndexA MatrixIndexA; // 0x1018
|
||||
TXFMatrixIndexB MatrixIndexB; // 0x1019
|
||||
Viewport viewport; // 0x101a - 0x101f
|
||||
float projection[7]; // 0x1020 - 0x1026
|
||||
u32 unk8[24]; // 0x1027 - 0x103e
|
||||
u32 numTexGens; // 0x103f
|
||||
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047
|
||||
u32 unk9[8]; // 0x1048 - 0x104f
|
||||
PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057
|
||||
};
|
||||
|
||||
#define XFMEM_POSMATRICES 0x000
|
||||
#define XFMEM_POSMATRICES_END 0x100
|
||||
#define XFMEM_NORMALMATRICES 0x400
|
||||
#define XFMEM_NORMALMATRICES_END 0x460
|
||||
#define XFMEM_POSTMATRICES 0x500
|
||||
#define XFMEM_POSTMATRICES_END 0x600
|
||||
#define XFMEM_LIGHTS 0x600
|
||||
#define XFMEM_LIGHTS_END 0x680
|
||||
|
||||
|
||||
extern XFRegisters xfregs;
|
||||
|
||||
void InitXFMemory();
|
||||
|
||||
void XFWritten(u32 transferSize, u32 baseAddress);
|
||||
|
||||
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData);
|
||||
|
||||
void LoadIndexedXF(u32 val, int array);
|
||||
|
||||
#endif
|
|
@ -0,0 +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"
|
||||
|
||||
|
||||
PLUGIN_GLOBALS* globals = NULL;
|
||||
static volatile bool fifoStateRun = false;
|
||||
SVideoInitialize g_VideoInitialize;
|
||||
bool g_SkipFrame;
|
||||
|
||||
|
||||
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_SkipFrame = false;
|
||||
|
||||
g_Config.Load();
|
||||
|
||||
InitBPMemory();
|
||||
InitXFMemory();
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
OpcodeDecoder::Init();
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
HwRasterizer::Init();
|
||||
Renderer::Init(_pVideoInitialize);
|
||||
}
|
||||
|
||||
void DoState(unsigned char **ptr, int mode)
|
||||
{
|
||||
}
|
||||
|
||||
void Shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
fifoStateRun = true;
|
||||
|
||||
while (fifoStateRun)
|
||||
{
|
||||
if (!CommandProcessor::RunBuffer())
|
||||
Common::SleepCurrentThread(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Video_ExitLoop()
|
||||
{
|
||||
}
|
||||
|
||||
void Video_AddMessage(const char* pstr, u32 milliseconds)
|
||||
{
|
||||
}
|
||||
|
||||
void Video_SetRendering(bool 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);
|
||||
}
|
||||
|
||||
inline void Video_GatherPipeBursted(void)
|
||||
{
|
||||
CommandProcessor::GatherPipeBursted();
|
||||
}
|
||||
|
||||
void Video_WaitForFrameFinish(void)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// 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;
|
||||
|
||||
extern bool g_SkipFrame;
|
||||
|
||||
#endif
|
|
@ -0,0 +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"
|
|
@ -0,0 +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>
|
||||
|
Loading…
Reference in New Issue