Update svn:eol-style=native ( r1442 ) for Source/*.cpp

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2384 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
LPFaint99
2009-02-23 06:15:48 +00:00
parent 472582022b
commit 578c402d2c
41 changed files with 13757 additions and 13757 deletions

View File

@ -1,117 +1,117 @@
// 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/
// --------------------
// Includes
#include <string>
#include <stdio.h>
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#endif
#if defined(HAVE_WX) && HAVE_WX
#include "../Debugger/Debugger.h"
extern CDebugger* m_frame;
#endif
#include "../Debugger/File.h"
// --------------------
// On and off
bool g_consoleEnable = true;
//int gSaveFile = 0;
#define DEBUG_HLE
// --------------------
// Create file handles
#ifdef DEBUG_HLE
FILE* __fStdOut[nFiles];
#endif
// =======================================================================================
/* Open file handles */
// -------------
void StartFile(int width, int height, char* fname)
{
#if defined(DEBUG_HLE) && defined(_WIN32)
if(fname)
{
for(int i = 0; i < nFiles; i++)
{
// Edit the log file name
std::string FileEnding = ".log";
std::string FileName = fname;
char buffer[33]; _itoa(i, buffer, 10); // convert number to string
std::string FullFilename = (FileName + buffer + FileEnding);
__fStdOut[i] = fopen(FullFilename.c_str(), "w");
}
}
#endif
}
// ======================
//////////////////////////////////////////////////////////////////////////////////////////
/* Close the file handles */
// -------------
void CloseFile()
{
// Close the file handles
for(int i = 0; i < nFiles; i++)
{
if(__fStdOut[i]) fclose(__fStdOut[i]);
}
}
//////////////////////////////
// ---------------------------------------------------------------------------------------
// File printf function
// -------------
int PrintFile(int a, char *fmt, ...)
{
#if defined(DEBUG_HLE) && defined(_WIN32)
if(m_frame->gSaveFile)
{
char s[StringSize];
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(s, StringSize, fmt, argptr);
va_end(argptr);
// ---------------------------------------------------------------------------------------
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
// to make it work
fprintf(__fStdOut[a], s);
// -------------
return(cnt);
}
else
{
return 0;
}
#else
return 0;
#endif
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// --------------------
// Includes
#include <string>
#include <stdio.h>
#include "Common.h"
#ifdef _WIN32
#include <windows.h>
#endif
#if defined(HAVE_WX) && HAVE_WX
#include "../Debugger/Debugger.h"
extern CDebugger* m_frame;
#endif
#include "../Debugger/File.h"
// --------------------
// On and off
bool g_consoleEnable = true;
//int gSaveFile = 0;
#define DEBUG_HLE
// --------------------
// Create file handles
#ifdef DEBUG_HLE
FILE* __fStdOut[nFiles];
#endif
// =======================================================================================
/* Open file handles */
// -------------
void StartFile(int width, int height, char* fname)
{
#if defined(DEBUG_HLE) && defined(_WIN32)
if(fname)
{
for(int i = 0; i < nFiles; i++)
{
// Edit the log file name
std::string FileEnding = ".log";
std::string FileName = fname;
char buffer[33]; _itoa(i, buffer, 10); // convert number to string
std::string FullFilename = (FileName + buffer + FileEnding);
__fStdOut[i] = fopen(FullFilename.c_str(), "w");
}
}
#endif
}
// ======================
//////////////////////////////////////////////////////////////////////////////////////////
/* Close the file handles */
// -------------
void CloseFile()
{
// Close the file handles
for(int i = 0; i < nFiles; i++)
{
if(__fStdOut[i]) fclose(__fStdOut[i]);
}
}
//////////////////////////////
// ---------------------------------------------------------------------------------------
// File printf function
// -------------
int PrintFile(int a, char *fmt, ...)
{
#if defined(DEBUG_HLE) && defined(_WIN32)
if(m_frame->gSaveFile)
{
char s[StringSize];
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(s, StringSize, fmt, argptr);
va_end(argptr);
// ---------------------------------------------------------------------------------------
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
// to make it work
fprintf(__fStdOut[a], s);
// -------------
return(cnt);
}
else
{
return 0;
}
#else
return 0;
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -1,145 +1,145 @@
// 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/
#include "D3DBase.h"
#include "Profiler.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "MemoryUtil.h"
#include "VertexShader.h"
#include "CPMemory.h"
#include "NativeVertexFormat.h"
class D3DVertexFormat : public NativeVertexFormat
{
PortableVertexDeclaration vtx_decl;
LPDIRECT3DVERTEXDECLARATION9 d3d_decl;
public:
D3DVertexFormat();
~D3DVertexFormat();
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
virtual void SetupVertexPointers() const;
};
NativeVertexFormat *NativeVertexFormat::Create()
{
return new D3DVertexFormat();
}
D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL)
{
}
D3DVertexFormat::~D3DVertexFormat()
{
if (d3d_decl)
{
d3d_decl->Release();
d3d_decl = NULL;
}
}
D3DDECLTYPE VarToD3D(VarType t)
{
static const D3DDECLTYPE lookup[5] =
{
D3DDECLTYPE_UBYTE4, D3DDECLTYPE_UBYTE4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT3,
};
return lookup[t];
}
// TODO: Ban signed bytes as normals - not likely that ATI supports them natively.
// We probably won't see much of a speed loss, and any speed loss will be regained anyway
// when we finally compile display lists.
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32];
memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32);
// There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream.
// Same for method.
// So, here we go. First position:
int elem_idx = 0;
elems[elem_idx].Offset = 0; // Positions are always first, at position 0.
elems[elem_idx].Type = D3DDECLTYPE_FLOAT3;
elems[elem_idx].Usage = D3DDECLUSAGE_POSITION;
++elem_idx;
for (int i = 0; i < 3; i++)
{
if (_vtx_decl.normal_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.normal_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 2; i++)
{
if (_vtx_decl.color_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.color_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_COLOR;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 8; i++)
{
if (_vtx_decl.texcoord_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i]);
elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
if (vtx_decl.posmtx_offset != -1)
{
// glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)vtx_decl.posmtx_offset);
elems[elem_idx].Offset = _vtx_decl.posmtx_offset;
elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES;
elems[elem_idx].UsageIndex = 0;
++elem_idx;
}
if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl)))
{
PanicAlert("Failed to create D3D vertex declaration!");
return;
}
}
void D3DVertexFormat::SetupVertexPointers() const
{
D3D::dev->SetVertexDeclaration(d3d_decl);
// 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/
#include "D3DBase.h"
#include "Profiler.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "MemoryUtil.h"
#include "VertexShader.h"
#include "CPMemory.h"
#include "NativeVertexFormat.h"
class D3DVertexFormat : public NativeVertexFormat
{
PortableVertexDeclaration vtx_decl;
LPDIRECT3DVERTEXDECLARATION9 d3d_decl;
public:
D3DVertexFormat();
~D3DVertexFormat();
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
virtual void SetupVertexPointers() const;
};
NativeVertexFormat *NativeVertexFormat::Create()
{
return new D3DVertexFormat();
}
D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL)
{
}
D3DVertexFormat::~D3DVertexFormat()
{
if (d3d_decl)
{
d3d_decl->Release();
d3d_decl = NULL;
}
}
D3DDECLTYPE VarToD3D(VarType t)
{
static const D3DDECLTYPE lookup[5] =
{
D3DDECLTYPE_UBYTE4, D3DDECLTYPE_UBYTE4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT3,
};
return lookup[t];
}
// TODO: Ban signed bytes as normals - not likely that ATI supports them natively.
// We probably won't see much of a speed loss, and any speed loss will be regained anyway
// when we finally compile display lists.
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32];
memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32);
// There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream.
// Same for method.
// So, here we go. First position:
int elem_idx = 0;
elems[elem_idx].Offset = 0; // Positions are always first, at position 0.
elems[elem_idx].Type = D3DDECLTYPE_FLOAT3;
elems[elem_idx].Usage = D3DDECLUSAGE_POSITION;
++elem_idx;
for (int i = 0; i < 3; i++)
{
if (_vtx_decl.normal_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.normal_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 2; i++)
{
if (_vtx_decl.color_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.color_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type);
elems[elem_idx].Usage = D3DDECLUSAGE_COLOR;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
for (int i = 0; i < 8; i++)
{
if (_vtx_decl.texcoord_offset[i] >= 0)
{
elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i];
elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i]);
elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD;
elems[elem_idx].UsageIndex = i;
++elem_idx;
}
}
if (vtx_decl.posmtx_offset != -1)
{
// glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)vtx_decl.posmtx_offset);
elems[elem_idx].Offset = _vtx_decl.posmtx_offset;
elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES;
elems[elem_idx].UsageIndex = 0;
++elem_idx;
}
if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl)))
{
PanicAlert("Failed to create D3D vertex declaration!");
return;
}
}
void D3DVertexFormat::SetupVertexPointers() const
{
D3D::dev->SetVertexDeclaration(d3d_decl);
}

View File

@ -1,133 +1,133 @@
// 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/
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "PixelShaderCache.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
PShaderCache::PSCache PShaderCache::pshaders;
//I hope we don't get too many hash collisions :p
//all these magic numbers are primes, it should help a bit
tevhash GetCurrentTEV()
{
u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17;
for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++)
{
hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13);
hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3);
hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451;
}
for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++)
{
hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7);
}
for (int i = 0; i < 8; i++)
{
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1;
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2;
}
hash ^= bpmem.dstalpha.enable ^ 0xc0debabe;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11;
return hash;
}
void PShaderCache::Init()
{
}
void PShaderCache::Shutdown()
{
PSCache::iterator iter = pshaders.begin();
for (;iter!=pshaders.end();iter++)
iter->second.Destroy();
pshaders.clear();
}
void PShaderCache::SetShader()
{
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
static LPDIRECT3DPIXELSHADER9 lastShader = 0;
DVSTARTPROFILE();
tevhash currentHash = GetCurrentTEV();
PSCache::iterator iter;
iter = pshaders.find(currentHash);
if (iter != pshaders.end())
{
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetPixelShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GeneratePixelShader();
LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
PSCacheEntry newentry;
newentry.shader = shader;
newentry.frameCount = frameCount;
pshaders[currentHash] = newentry;
}
D3D::dev->SetPixelShader(shader);
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
void PShaderCache::Cleanup()
{
PSCache::iterator iter;
iter = pshaders.begin();
while (iter != pshaders.end())
{
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount-30)
{
entry.Destroy();
iter = pshaders.erase(iter);
}
else
{
iter++;
}
}
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
// 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/
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "PixelShaderCache.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
PShaderCache::PSCache PShaderCache::pshaders;
//I hope we don't get too many hash collisions :p
//all these magic numbers are primes, it should help a bit
tevhash GetCurrentTEV()
{
u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17;
for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++)
{
hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13);
hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3);
hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451;
}
for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++)
{
hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7);
}
for (int i = 0; i < 8; i++)
{
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1;
hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2;
}
hash ^= bpmem.dstalpha.enable ^ 0xc0debabe;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13;
hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11;
return hash;
}
void PShaderCache::Init()
{
}
void PShaderCache::Shutdown()
{
PSCache::iterator iter = pshaders.begin();
for (;iter!=pshaders.end();iter++)
iter->second.Destroy();
pshaders.clear();
}
void PShaderCache::SetShader()
{
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
static LPDIRECT3DPIXELSHADER9 lastShader = 0;
DVSTARTPROFILE();
tevhash currentHash = GetCurrentTEV();
PSCache::iterator iter;
iter = pshaders.find(currentHash);
if (iter != pshaders.end())
{
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetPixelShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GeneratePixelShader();
LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
PSCacheEntry newentry;
newentry.shader = shader;
newentry.frameCount = frameCount;
pshaders[currentHash] = newentry;
}
D3D::dev->SetPixelShader(shader);
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}
void PShaderCache::Cleanup()
{
PSCache::iterator iter;
iter = pshaders.begin();
while (iter != pshaders.end())
{
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount-30)
{
entry.Destroy();
iter = pshaders.erase(iter);
}
else
{
iter++;
}
}
SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size());
}

View File

@ -1,56 +1,56 @@
// 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/
#include "VideoCommon.h"
#include "VertexLoader.h"
#include "VertexManager.h"
DecodedVArray tempvarray;
namespace VertexLoaderManager
{
void Init()
{
tempvarray.Create(65536*3, 1, 8, 3, 2, 8);
}
void Shutdown()
{
tempvarray.Destroy();
}
int GetVertexSize(int vat)
{
VertexLoader& vtxLoader = g_VertexLoaders[vat];
vtxLoader.Setup();
return vtxLoader.GetVertexSize();
}
void RunVertices(int vat, int primitive, int num_vertices)
{
tempvarray.Reset();
VertexLoader::SetVArray(&tempvarray);
VertexLoader& vtxLoader = g_VertexLoaders[vat];
vtxLoader.Setup();
vtxLoader.PrepareRun();
int vsize = vtxLoader.GetVertexSize();
vtxLoader.RunVertices(num_vertices);
VertexManager::AddVertices(primitive, num_vertices, &tempvarray);
}
// 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/
#include "VideoCommon.h"
#include "VertexLoader.h"
#include "VertexManager.h"
DecodedVArray tempvarray;
namespace VertexLoaderManager
{
void Init()
{
tempvarray.Create(65536*3, 1, 8, 3, 2, 8);
}
void Shutdown()
{
tempvarray.Destroy();
}
int GetVertexSize(int vat)
{
VertexLoader& vtxLoader = g_VertexLoaders[vat];
vtxLoader.Setup();
return vtxLoader.GetVertexSize();
}
void RunVertices(int vat, int primitive, int num_vertices)
{
tempvarray.Reset();
VertexLoader::SetVArray(&tempvarray);
VertexLoader& vtxLoader = g_VertexLoaders[vat];
vtxLoader.Setup();
vtxLoader.PrepareRun();
int vsize = vtxLoader.GetVertexSize();
vtxLoader.RunVertices(num_vertices);
VertexManager::AddVertices(primitive, num_vertices, &tempvarray);
}
}

View File

@ -1,110 +1,110 @@
// 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/
#include <map>
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "VertexShaderCache.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
VShaderCache::VSCache VShaderCache::vshaders;
void VShaderCache::Init()
{
}
void VShaderCache::Shutdown()
{
VSCache::iterator iter = vshaders.begin();
for (; iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
void VShaderCache::SetShader()
{
static LPDIRECT3DVERTEXSHADER9 shader = NULL;
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
if (shader) {
//D3D::dev->SetVertexShader(shader);
return;
}
static LPDIRECT3DVERTEXSHADER9 lastShader = 0;
DVSTARTPROFILE();
u32 currentHash = 0x1337; // GetCurrentTEV();
VSCache::iterator iter;
iter = vshaders.find(currentHash);
if (iter != vshaders.end())
{
iter->second.frameCount=frameCount;
VSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetVertexShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GenerateVertexShader();
shader = D3D::CompileVShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.frameCount=frameCount;
vshaders[currentHash] = entry;
}
D3D::dev->SetVertexShader(shader);
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
void VShaderCache::Cleanup()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end();)
{
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 30)
{
entry.Destroy();
iter = vshaders.erase(iter);
}
else
{
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
// 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/
#include <map>
#include "D3DBase.h"
#include "Statistics.h"
#include "Utils.h"
#include "Profiler.h"
#include "VertexShaderCache.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
VShaderCache::VSCache VShaderCache::vshaders;
void VShaderCache::Init()
{
}
void VShaderCache::Shutdown()
{
VSCache::iterator iter = vshaders.begin();
for (; iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
void VShaderCache::SetShader()
{
static LPDIRECT3DVERTEXSHADER9 shader = NULL;
if (D3D::GetShaderVersion() < 2)
return; // we are screwed
if (shader) {
//D3D::dev->SetVertexShader(shader);
return;
}
static LPDIRECT3DVERTEXSHADER9 lastShader = 0;
DVSTARTPROFILE();
u32 currentHash = 0x1337; // GetCurrentTEV();
VSCache::iterator iter;
iter = vshaders.find(currentHash);
if (iter != vshaders.end())
{
iter->second.frameCount=frameCount;
VSCacheEntry &entry = iter->second;
if (!lastShader || entry.shader != lastShader)
{
D3D::dev->SetVertexShader(entry.shader);
lastShader = entry.shader;
}
return;
}
const char *code = GenerateVertexShader();
shader = D3D::CompileVShader(code, int(strlen(code)));
if (shader)
{
//Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.frameCount=frameCount;
vshaders[currentHash] = entry;
}
D3D::dev->SetVertexShader(shader);
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}
void VShaderCache::Cleanup()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end();)
{
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 30)
{
entry.Destroy();
iter = vshaders.erase(iter);
}
else
{
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
}

View File

@ -1,87 +1,87 @@
// 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/
#include <list>
#include "Common.h"
#include "GLUtil.h"
#include "OnScreenDisplay.h"
#include "Render.h"
#include "Timer.h"
namespace OSD
{
struct MESSAGE
{
MESSAGE() {}
MESSAGE(const char* p, u32 dw) {
strncpy(str, p, 255);
str[255] = '\0';
dwTimeStamp = dw;
}
char str[256];
u32 dwTimeStamp;
};
static std::list<MESSAGE> s_listMsgs;
void AddMessage(const char* pstr, u32 ms)
{
s_listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms));
}
void DrawMessages()
{
GLboolean wasEnabled = glIsEnabled(GL_BLEND);
if (!wasEnabled)
glEnable(GL_BLEND);
if (s_listMsgs.size() > 0)
{
int left = 25, top = 15;
std::list<MESSAGE>::iterator it = s_listMsgs.begin();
while (it != s_listMsgs.end())
{
int time_left = (int)(it->dwTimeStamp - timeGetTime());
int alpha = 255;
if (time_left < 1024)
{
alpha = time_left >> 2;
if (time_left < 0) alpha = 0;
}
alpha <<= 24;
Renderer::RenderText(it->str, left+1, top+1, 0x000000|alpha);
Renderer::RenderText(it->str, left, top, 0xffff30|alpha);
top += 15;
if (time_left <= 0)
it = s_listMsgs.erase(it);
else
++it;
}
}
if (!wasEnabled)
glDisable(GL_BLEND);
}
} // namespace
// 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/
#include <list>
#include "Common.h"
#include "GLUtil.h"
#include "OnScreenDisplay.h"
#include "Render.h"
#include "Timer.h"
namespace OSD
{
struct MESSAGE
{
MESSAGE() {}
MESSAGE(const char* p, u32 dw) {
strncpy(str, p, 255);
str[255] = '\0';
dwTimeStamp = dw;
}
char str[256];
u32 dwTimeStamp;
};
static std::list<MESSAGE> s_listMsgs;
void AddMessage(const char* pstr, u32 ms)
{
s_listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms));
}
void DrawMessages()
{
GLboolean wasEnabled = glIsEnabled(GL_BLEND);
if (!wasEnabled)
glEnable(GL_BLEND);
if (s_listMsgs.size() > 0)
{
int left = 25, top = 15;
std::list<MESSAGE>::iterator it = s_listMsgs.begin();
while (it != s_listMsgs.end())
{
int time_left = (int)(it->dwTimeStamp - timeGetTime());
int alpha = 255;
if (time_left < 1024)
{
alpha = time_left >> 2;
if (time_left < 0) alpha = 0;
}
alpha <<= 24;
Renderer::RenderText(it->str, left+1, top+1, 0x000000|alpha);
Renderer::RenderText(it->str, left, top, 0xffff30|alpha);
top += 15;
if (time_left <= 0)
it = s_listMsgs.erase(it);
else
++it;
}
}
if (!wasEnabled)
glDisable(GL_BLEND);
}
} // namespace

View File

@ -1,223 +1,223 @@
// 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/
#include "Globals.h"
#include "Profiler.h"
#include "GLUtil.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <cmath>
#include "Statistics.h"
#include "Config.h"
#include "ImageWrite.h"
#include "Common.h"
#include "Render.h"
#include "VertexShaderGen.h"
#include "PixelShaderCache.h"
#include "PixelShaderManager.h"
static int s_nMaxPixelInstructions;
static GLuint s_ColorMatrixProgram = 0;
PixelShaderCache::PSCache PixelShaderCache::pshaders;
PIXELSHADERUID PixelShaderCache::s_curuid;
static FRAGMENTSHADER* pShaderLast = NULL;
void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f1, f2, f3, f4);
}
void SetPSConstant4fv(int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
}
void PixelShaderCache::Init()
{
GL_REPORT_ERRORD();
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
int maxinst, maxattribs;
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst);
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs);
ERROR_LOG("pixel max_alu=%d, max_inst=%d, max_attrib=%d\n", s_nMaxPixelInstructions, maxinst, maxattribs);
char pmatrixprog[1024];
sprintf(pmatrixprog, "!!ARBfp1.0"
"TEMP R0;\n"
"TEMP R1;\n"
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
"DP4 R1.w, R0, program.env[%d];\n"
"DP4 R1.z, R0, program.env[%d];\n"
"DP4 R1.x, R0, program.env[%d];\n"
"DP4 R1.y, R0, program.env[%d];\n"
"ADD result.color, R1, program.env[%d];\n"
"END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4);
glGenProgramsARB(1, &s_ColorMatrixProgram);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_ColorMatrixProgram);
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG("Failed to create color matrix fragment program\n");
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
}
}
void PixelShaderCache::Shutdown()
{
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
PSCache::iterator iter = pshaders.begin();
for (; iter != pshaders.end(); iter++)
iter->second.Destroy();
pshaders.clear();
}
GLuint PixelShaderCache::GetColorMatrixProgram()
{
return s_ColorMatrixProgram;
}
FRAGMENTSHADER* PixelShaderCache::GetShader()
{
DVSTARTPROFILE();
PIXELSHADERUID uid;
u32 zbufrender = (Renderer::GetZBufferTarget() && bpmem.zmode.updateenable) ? 1 : 0;
u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal;
GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0);
PSCache::iterator iter = pshaders.find(uid);
if (iter != pshaders.end()) {
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (&entry.shader != pShaderLast)
{
pShaderLast = &entry.shader;
}
return pShaderLast;
}
PSCacheEntry& newentry = pshaders[uid];
const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(),
Renderer::GetZBufferTarget() != 0,
Renderer::GetRenderMode() != Renderer::RM_Normal);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_Config.iLog & CONF_SAVESHADERS && code) {
static int counter = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%s/ps_%04i.txt", FULL_DUMP_DIR, counter++);
SaveData(szTemp, code);
}
#endif
// printf("Compiling pixel shader. size = %i\n", strlen(code));
if (!code || !CompilePixelShader(newentry.shader, code)) {
ERROR_LOG("failed to create pixel shader\n");
return NULL;
}
//Make an entry in the table
newentry.frameCount = frameCount;
pShaderLast = &newentry.shader;
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
return pShaderLast;
}
void PixelShaderCache::Cleanup()
{
PSCache::iterator iter = pshaders.begin();
while (iter != pshaders.end()) {
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 400) {
entry.Destroy();
#ifdef _WIN32
iter = pshaders.erase(iter);
#else
pshaders.erase(iter++); // (this is gcc standard!)
#endif
}
else
iter++;
}
SETSTAT(stats.numPixelShadersAlive,(int)pshaders.size());
}
bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram)
{
char stropt[64];
sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions);
const char* opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts);
if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) {
ERROR_LOG("Failed to create ps %s:\n", cgGetLastListing(g_cgcontext));
ERROR_LOG(pstrprogram);
return false;
}
char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
char *plocal = strstr(pcompiledprog, "program.local");
while (plocal != NULL) {
const char* penv = " program.env";
memcpy(plocal, penv, 13);
plocal = strstr(plocal+13, "program.local");
}
if (Renderer::IsUsingATIDrawBuffers()) {
// sometimes compilation can use ARB_draw_buffers, which would fail for ATI cards
// replace the three characters ARB with ATI. TODO - check whether this is fixed in modern ATI drivers.
char* poptions = strstr(pcompiledprog, "ARB_draw_buffers");
if (poptions != NULL) {
poptions[0] = 'A';
poptions[1] = 'T';
poptions[2] = 'I';
}
}
glGenProgramsARB( 1, &ps.glprogid );
glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ps.glprogid );
glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG(pstrprogram);
ERROR_LOG(pcompiledprog);
}
cgDestroyProgram(tempprog);
// printf("Compiled pixel shader %i\n", ps.glprogid);
#if defined(_DEBUG) || defined(DEBUGFAST)
ps.strprog = pstrprogram;
#endif
return true;
}
// 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/
#include "Globals.h"
#include "Profiler.h"
#include "GLUtil.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <cmath>
#include "Statistics.h"
#include "Config.h"
#include "ImageWrite.h"
#include "Common.h"
#include "Render.h"
#include "VertexShaderGen.h"
#include "PixelShaderCache.h"
#include "PixelShaderManager.h"
static int s_nMaxPixelInstructions;
static GLuint s_ColorMatrixProgram = 0;
PixelShaderCache::PSCache PixelShaderCache::pshaders;
PIXELSHADERUID PixelShaderCache::s_curuid;
static FRAGMENTSHADER* pShaderLast = NULL;
void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f1, f2, f3, f4);
}
void SetPSConstant4fv(int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
}
void PixelShaderCache::Init()
{
GL_REPORT_ERRORD();
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
int maxinst, maxattribs;
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst);
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs);
ERROR_LOG("pixel max_alu=%d, max_inst=%d, max_attrib=%d\n", s_nMaxPixelInstructions, maxinst, maxattribs);
char pmatrixprog[1024];
sprintf(pmatrixprog, "!!ARBfp1.0"
"TEMP R0;\n"
"TEMP R1;\n"
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
"DP4 R1.w, R0, program.env[%d];\n"
"DP4 R1.z, R0, program.env[%d];\n"
"DP4 R1.x, R0, program.env[%d];\n"
"DP4 R1.y, R0, program.env[%d];\n"
"ADD result.color, R1, program.env[%d];\n"
"END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4);
glGenProgramsARB(1, &s_ColorMatrixProgram);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_ColorMatrixProgram);
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG("Failed to create color matrix fragment program\n");
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
}
}
void PixelShaderCache::Shutdown()
{
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
PSCache::iterator iter = pshaders.begin();
for (; iter != pshaders.end(); iter++)
iter->second.Destroy();
pshaders.clear();
}
GLuint PixelShaderCache::GetColorMatrixProgram()
{
return s_ColorMatrixProgram;
}
FRAGMENTSHADER* PixelShaderCache::GetShader()
{
DVSTARTPROFILE();
PIXELSHADERUID uid;
u32 zbufrender = (Renderer::GetZBufferTarget() && bpmem.zmode.updateenable) ? 1 : 0;
u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal;
GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0);
PSCache::iterator iter = pshaders.find(uid);
if (iter != pshaders.end()) {
iter->second.frameCount = frameCount;
PSCacheEntry &entry = iter->second;
if (&entry.shader != pShaderLast)
{
pShaderLast = &entry.shader;
}
return pShaderLast;
}
PSCacheEntry& newentry = pshaders[uid];
const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(),
Renderer::GetZBufferTarget() != 0,
Renderer::GetRenderMode() != Renderer::RM_Normal);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_Config.iLog & CONF_SAVESHADERS && code) {
static int counter = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%s/ps_%04i.txt", FULL_DUMP_DIR, counter++);
SaveData(szTemp, code);
}
#endif
// printf("Compiling pixel shader. size = %i\n", strlen(code));
if (!code || !CompilePixelShader(newentry.shader, code)) {
ERROR_LOG("failed to create pixel shader\n");
return NULL;
}
//Make an entry in the table
newentry.frameCount = frameCount;
pShaderLast = &newentry.shader;
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
return pShaderLast;
}
void PixelShaderCache::Cleanup()
{
PSCache::iterator iter = pshaders.begin();
while (iter != pshaders.end()) {
PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 400) {
entry.Destroy();
#ifdef _WIN32
iter = pshaders.erase(iter);
#else
pshaders.erase(iter++); // (this is gcc standard!)
#endif
}
else
iter++;
}
SETSTAT(stats.numPixelShadersAlive,(int)pshaders.size());
}
bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram)
{
char stropt[64];
sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions);
const char* opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts);
if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) {
ERROR_LOG("Failed to create ps %s:\n", cgGetLastListing(g_cgcontext));
ERROR_LOG(pstrprogram);
return false;
}
char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
char *plocal = strstr(pcompiledprog, "program.local");
while (plocal != NULL) {
const char* penv = " program.env";
memcpy(plocal, penv, 13);
plocal = strstr(plocal+13, "program.local");
}
if (Renderer::IsUsingATIDrawBuffers()) {
// sometimes compilation can use ARB_draw_buffers, which would fail for ATI cards
// replace the three characters ARB with ATI. TODO - check whether this is fixed in modern ATI drivers.
char* poptions = strstr(pcompiledprog, "ARB_draw_buffers");
if (poptions != NULL) {
poptions[0] = 'A';
poptions[1] = 'T';
poptions[2] = 'I';
}
}
glGenProgramsARB( 1, &ps.glprogid );
glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, ps.glprogid );
glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG(pstrprogram);
ERROR_LOG(pcompiledprog);
}
cgDestroyProgram(tempprog);
// printf("Compiled pixel shader %i\n", ps.glprogid);
#if defined(_DEBUG) || defined(DEBUGFAST)
ps.strprog = pstrprogram;
#endif
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +1,176 @@
// 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/
#include <math.h>
#include "Globals.h"
#include "Profiler.h"
#include "Config.h"
#include "Statistics.h"
#include "GLUtil.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include "Render.h"
#include "VertexShaderGen.h"
#include "VertexShaderManager.h"
#include "VertexShaderCache.h"
#include "VertexManager.h"
#include "VertexLoader.h"
#include "XFMemory.h"
#include "ImageWrite.h"
VertexShaderCache::VSCache VertexShaderCache::vshaders;
static VERTEXSHADER *pShaderLast = NULL;
static int s_nMaxVertexInstructions;
void SetVSConstant4f(int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
}
void SetVSConstant4fv(int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
}
void VertexShaderCache::Init()
{
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
}
void VertexShaderCache::Shutdown()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
VERTEXSHADER* VertexShaderCache::GetShader(u32 components)
{
DVSTARTPROFILE();
VERTEXSHADERUID uid;
u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetZBufferTarget() != 0;
GetVertexShaderId(uid, components, zbufrender);
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end()) {
iter->second.frameCount = frameCount;
VSCacheEntry &entry = iter->second;
if (&entry.shader != pShaderLast) {
pShaderLast = &entry.shader;
}
return pShaderLast;
}
VSCacheEntry& entry = vshaders[uid];
const char *code = GenerateVertexShader(components, Renderer::GetZBufferTarget() != 0);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_Config.iLog & CONF_SAVESHADERS && code) {
static int counter = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%s/vs_%04i.txt", FULL_DUMP_DIR, counter++);
SaveData(szTemp, code);
}
#endif
if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) {
ERROR_LOG("failed to create vertex shader\n");
return NULL;
}
//Make an entry in the table
entry.frameCount = frameCount;
pShaderLast = &entry.shader;
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
return pShaderLast;
}
void VertexShaderCache::Cleanup()
{
VSCache::iterator iter = vshaders.begin();
while (iter != vshaders.end()) {
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 200) {
entry.Destroy();
#ifdef _WIN32
iter = vshaders.erase(iter);
#else
vshaders.erase(iter++);
#endif
}
else {
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
}
bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram)
{
char stropt[64];
sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions);
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts);
if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) {
ERROR_LOG("Failed to load vs %s:\n", cgGetLastListing(g_cgcontext));
ERROR_LOG(pstrprogram);
return false;
}
//ERROR_LOG(pstrprogram);
//ERROR_LOG("id: %d\n", g_Config.iSaveTargetId);
char* pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
char* plocal = strstr(pcompiledprog, "program.local");
while (plocal != NULL) {
const char* penv = " program.env";
memcpy(plocal, penv, 13);
plocal = strstr(plocal+13, "program.local");
}
glGenProgramsARB(1, &vs.glprogid);
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vs.glprogid);
glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG(pstrprogram);
ERROR_LOG(pcompiledprog);
}
cgDestroyProgram(tempprog);
// printf("Compiled vertex shader %i\n", vs.glprogid);
#if defined(_DEBUG) || defined(DEBUGFAST)
vs.strprog = pstrprogram;
#endif
return true;
}
// 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/
#include <math.h>
#include "Globals.h"
#include "Profiler.h"
#include "Config.h"
#include "Statistics.h"
#include "GLUtil.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include "Render.h"
#include "VertexShaderGen.h"
#include "VertexShaderManager.h"
#include "VertexShaderCache.h"
#include "VertexManager.h"
#include "VertexLoader.h"
#include "XFMemory.h"
#include "ImageWrite.h"
VertexShaderCache::VSCache VertexShaderCache::vshaders;
static VERTEXSHADER *pShaderLast = NULL;
static int s_nMaxVertexInstructions;
void SetVSConstant4f(int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
}
void SetVSConstant4fv(int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
}
void VertexShaderCache::Init()
{
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
}
void VertexShaderCache::Shutdown()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++)
iter->second.Destroy();
vshaders.clear();
}
VERTEXSHADER* VertexShaderCache::GetShader(u32 components)
{
DVSTARTPROFILE();
VERTEXSHADERUID uid;
u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetZBufferTarget() != 0;
GetVertexShaderId(uid, components, zbufrender);
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end()) {
iter->second.frameCount = frameCount;
VSCacheEntry &entry = iter->second;
if (&entry.shader != pShaderLast) {
pShaderLast = &entry.shader;
}
return pShaderLast;
}
VSCacheEntry& entry = vshaders[uid];
const char *code = GenerateVertexShader(components, Renderer::GetZBufferTarget() != 0);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_Config.iLog & CONF_SAVESHADERS && code) {
static int counter = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%s/vs_%04i.txt", FULL_DUMP_DIR, counter++);
SaveData(szTemp, code);
}
#endif
if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) {
ERROR_LOG("failed to create vertex shader\n");
return NULL;
}
//Make an entry in the table
entry.frameCount = frameCount;
pShaderLast = &entry.shader;
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
return pShaderLast;
}
void VertexShaderCache::Cleanup()
{
VSCache::iterator iter = vshaders.begin();
while (iter != vshaders.end()) {
VSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 200) {
entry.Destroy();
#ifdef _WIN32
iter = vshaders.erase(iter);
#else
vshaders.erase(iter++);
#endif
}
else {
++iter;
}
}
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
}
bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram)
{
char stropt[64];
sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions);
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts);
if (!cgIsProgram(tempprog) || cgGetError() != CG_NO_ERROR) {
ERROR_LOG("Failed to load vs %s:\n", cgGetLastListing(g_cgcontext));
ERROR_LOG(pstrprogram);
return false;
}
//ERROR_LOG(pstrprogram);
//ERROR_LOG("id: %d\n", g_Config.iSaveTargetId);
char* pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
char* plocal = strstr(pcompiledprog, "program.local");
while (plocal != NULL) {
const char* penv = " program.env";
memcpy(plocal, penv, 13);
plocal = strstr(plocal+13, "program.local");
}
glGenProgramsARB(1, &vs.glprogid);
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vs.glprogid);
glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
GLenum err = GL_NO_ERROR;
GL_REPORT_ERROR();
if (err != GL_NO_ERROR) {
ERROR_LOG(pstrprogram);
ERROR_LOG(pcompiledprog);
}
cgDestroyProgram(tempprog);
// printf("Compiled vertex shader %i\n", vs.glprogid);
#if defined(_DEBUG) || defined(DEBUGFAST)
vs.strprog = pstrprogram;
#endif
return true;
}

View File

@ -1,236 +1,236 @@
// 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/
#include "Common.h"
#include "Globals.h"
#include "XFMemory.h"
#include "VertexManager.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
// LoadXFReg 0x10
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
u32 address = baseAddress;
for (int i = 0; i < (int)transferSize; i++)
{
address = baseAddress + i;
// Setup a Matrix
if (address < 0x1000)
{
VertexManager::Flush();
VertexShaderManager::InvalidateXFRange(address, address + transferSize);
//PRIM_LOG("xfmem write: 0x%x-0x%x\n", address, address+transferSize);
u32* p1 = &xfmem[address];
memcpy_gc(p1, &pData[i], transferSize*4);
i += transferSize;
}
else if (address<0x2000)
{
u32 data = pData[i];
switch (address)
{
case 0x1000: // error
break;
case 0x1001: // diagnostics
break;
case 0x1002: // internal state 0
break;
case 0x1003: // internal state 1
break;
case 0x1004: // xf_clock
break;
case 0x1005: // clipdisable
if (data & 1) { // disable clipping detection
}
if (data & 2) { // disable trivial rejection
}
if (data & 4) { // disable cpoly clipping acceleration
}
break;
case 0x1006: //SetGPMetric
break;
case 0x1008: //__GXXfVtxSpecs, wrote 0004
xfregs.hostinfo = *(INVTXSPEC*)&data;
break;
case 0x1009: //GXSetNumChans (no)
if ((u32)xfregs.nNumChans != (data&3)) {
VertexManager::Flush();
xfregs.nNumChans = data&3;
}
break;
case 0x100a: //GXSetChanAmbientcolor
if (xfregs.colChans[0].ambColor != data) {
VertexManager::Flush();
xfregs.colChans[0].ambColor = data;
VertexShaderManager::SetMaterialColor(0, data);
}
break;
case 0x100b: //GXSetChanAmbientcolor
if (xfregs.colChans[1].ambColor != data) {
VertexManager::Flush();
xfregs.colChans[1].ambColor = data;
VertexShaderManager::SetMaterialColor(1, data);
}
break;
case 0x100c: //GXSetChanMatcolor (rgba)
if (xfregs.colChans[0].matColor != data) {
VertexManager::Flush();
xfregs.colChans[0].matColor = data;
VertexShaderManager::SetMaterialColor(2, data);
}
break;
case 0x100d: //GXSetChanMatcolor (rgba)
if (xfregs.colChans[1].matColor != data) {
VertexManager::Flush();
xfregs.colChans[1].matColor = data;
VertexShaderManager::SetMaterialColor(3, data);
}
break;
case 0x100e: // color0
if (xfregs.colChans[0].color.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[0].color.hex = data;
}
break;
case 0x100f: // color1
if (xfregs.colChans[1].color.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[1].color.hex = data;
}
break;
case 0x1010: // alpha0
if (xfregs.colChans[0].alpha.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[0].alpha.hex = data;
}
break;
case 0x1011: // alpha1
if (xfregs.colChans[1].alpha.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[1].alpha.hex = data;
}
break;
case 0x1012: // dual tex transform
if (xfregs.bEnableDualTexTransform != (data & 1)) {
VertexManager::Flush();
xfregs.bEnableDualTexTransform = data & 1;
}
break;
case 0x1013:
case 0x1014:
case 0x1015:
case 0x1016:
case 0x1017:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
case 0x1018:
//_assert_msg_(GX_XF, 0, "XF matrixindex0");
VertexShaderManager::SetTexMatrixChangedA(data); //?
break;
case 0x1019:
//_assert_msg_(GX_XF, 0, "XF matrixindex1");
VertexShaderManager::SetTexMatrixChangedB(data); //?
break;
case 0x101a:
VertexManager::Flush();
VertexShaderManager::SetViewport((float*)&pData[i]);
PixelShaderManager::SetViewport((float*)&pData[i]);
i += 6;
break;
case 0x101c: // paper mario writes 16777216.0f, 1677721.75
break;
case 0x101f: // paper mario writes 16777216.0f, 5033165.0f
break;
case 0x1020:
VertexManager::Flush();
VertexShaderManager::SetProjection((float*)&pData[i]);
i += 7;
return;
case 0x103f: // GXSetNumTexGens
if ((u32)xfregs.numTexGens != data) {
VertexManager::Flush();
xfregs.numTexGens = data;
}
break;
case 0x1040: xfregs.texcoords[0].texmtxinfo.hex = data; break;
case 0x1041: xfregs.texcoords[1].texmtxinfo.hex = data; break;
case 0x1042: xfregs.texcoords[2].texmtxinfo.hex = data; break;
case 0x1043: xfregs.texcoords[3].texmtxinfo.hex = data; break;
case 0x1044: xfregs.texcoords[4].texmtxinfo.hex = data; break;
case 0x1045: xfregs.texcoords[5].texmtxinfo.hex = data; break;
case 0x1046: xfregs.texcoords[6].texmtxinfo.hex = data; break;
case 0x1047: xfregs.texcoords[7].texmtxinfo.hex = data; break;
case 0x1048:
case 0x1049:
case 0x104a:
case 0x104b:
case 0x104c:
case 0x104d:
case 0x104e:
case 0x104f:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
case 0x1050: xfregs.texcoords[0].postmtxinfo.hex = data; break;
case 0x1051: xfregs.texcoords[1].postmtxinfo.hex = data; break;
case 0x1052: xfregs.texcoords[2].postmtxinfo.hex = data; break;
case 0x1053: xfregs.texcoords[3].postmtxinfo.hex = data; break;
case 0x1054: xfregs.texcoords[4].postmtxinfo.hex = data; break;
case 0x1055: xfregs.texcoords[5].postmtxinfo.hex = data; break;
case 0x1056: xfregs.texcoords[6].postmtxinfo.hex = data; break;
case 0x1057: xfregs.texcoords[7].postmtxinfo.hex = data; break;
default:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
}
}
else if (address >= 0x4000)
{
// MessageBox(NULL, "1", "1", MB_OK);
//4010 __GXSetGenMode
}
}
}
// TODO - verify that it is correct. Seems to work, though.
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
VertexManager::Flush();
VertexShaderManager::InvalidateXFRange(address, address + size);
//PRIM_LOG("xfmem iwrite: 0x%x-0x%x\n", address, address + size);
for (int i = 0; i < size; i++)
xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array] * index + i * 4);
}
// 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/
#include "Common.h"
#include "Globals.h"
#include "XFMemory.h"
#include "VertexManager.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
// LoadXFReg 0x10
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
u32 address = baseAddress;
for (int i = 0; i < (int)transferSize; i++)
{
address = baseAddress + i;
// Setup a Matrix
if (address < 0x1000)
{
VertexManager::Flush();
VertexShaderManager::InvalidateXFRange(address, address + transferSize);
//PRIM_LOG("xfmem write: 0x%x-0x%x\n", address, address+transferSize);
u32* p1 = &xfmem[address];
memcpy_gc(p1, &pData[i], transferSize*4);
i += transferSize;
}
else if (address<0x2000)
{
u32 data = pData[i];
switch (address)
{
case 0x1000: // error
break;
case 0x1001: // diagnostics
break;
case 0x1002: // internal state 0
break;
case 0x1003: // internal state 1
break;
case 0x1004: // xf_clock
break;
case 0x1005: // clipdisable
if (data & 1) { // disable clipping detection
}
if (data & 2) { // disable trivial rejection
}
if (data & 4) { // disable cpoly clipping acceleration
}
break;
case 0x1006: //SetGPMetric
break;
case 0x1008: //__GXXfVtxSpecs, wrote 0004
xfregs.hostinfo = *(INVTXSPEC*)&data;
break;
case 0x1009: //GXSetNumChans (no)
if ((u32)xfregs.nNumChans != (data&3)) {
VertexManager::Flush();
xfregs.nNumChans = data&3;
}
break;
case 0x100a: //GXSetChanAmbientcolor
if (xfregs.colChans[0].ambColor != data) {
VertexManager::Flush();
xfregs.colChans[0].ambColor = data;
VertexShaderManager::SetMaterialColor(0, data);
}
break;
case 0x100b: //GXSetChanAmbientcolor
if (xfregs.colChans[1].ambColor != data) {
VertexManager::Flush();
xfregs.colChans[1].ambColor = data;
VertexShaderManager::SetMaterialColor(1, data);
}
break;
case 0x100c: //GXSetChanMatcolor (rgba)
if (xfregs.colChans[0].matColor != data) {
VertexManager::Flush();
xfregs.colChans[0].matColor = data;
VertexShaderManager::SetMaterialColor(2, data);
}
break;
case 0x100d: //GXSetChanMatcolor (rgba)
if (xfregs.colChans[1].matColor != data) {
VertexManager::Flush();
xfregs.colChans[1].matColor = data;
VertexShaderManager::SetMaterialColor(3, data);
}
break;
case 0x100e: // color0
if (xfregs.colChans[0].color.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[0].color.hex = data;
}
break;
case 0x100f: // color1
if (xfregs.colChans[1].color.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[1].color.hex = data;
}
break;
case 0x1010: // alpha0
if (xfregs.colChans[0].alpha.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[0].alpha.hex = data;
}
break;
case 0x1011: // alpha1
if (xfregs.colChans[1].alpha.hex != (data & 0x7fff) ) {
VertexManager::Flush();
xfregs.colChans[1].alpha.hex = data;
}
break;
case 0x1012: // dual tex transform
if (xfregs.bEnableDualTexTransform != (data & 1)) {
VertexManager::Flush();
xfregs.bEnableDualTexTransform = data & 1;
}
break;
case 0x1013:
case 0x1014:
case 0x1015:
case 0x1016:
case 0x1017:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
case 0x1018:
//_assert_msg_(GX_XF, 0, "XF matrixindex0");
VertexShaderManager::SetTexMatrixChangedA(data); //?
break;
case 0x1019:
//_assert_msg_(GX_XF, 0, "XF matrixindex1");
VertexShaderManager::SetTexMatrixChangedB(data); //?
break;
case 0x101a:
VertexManager::Flush();
VertexShaderManager::SetViewport((float*)&pData[i]);
PixelShaderManager::SetViewport((float*)&pData[i]);
i += 6;
break;
case 0x101c: // paper mario writes 16777216.0f, 1677721.75
break;
case 0x101f: // paper mario writes 16777216.0f, 5033165.0f
break;
case 0x1020:
VertexManager::Flush();
VertexShaderManager::SetProjection((float*)&pData[i]);
i += 7;
return;
case 0x103f: // GXSetNumTexGens
if ((u32)xfregs.numTexGens != data) {
VertexManager::Flush();
xfregs.numTexGens = data;
}
break;
case 0x1040: xfregs.texcoords[0].texmtxinfo.hex = data; break;
case 0x1041: xfregs.texcoords[1].texmtxinfo.hex = data; break;
case 0x1042: xfregs.texcoords[2].texmtxinfo.hex = data; break;
case 0x1043: xfregs.texcoords[3].texmtxinfo.hex = data; break;
case 0x1044: xfregs.texcoords[4].texmtxinfo.hex = data; break;
case 0x1045: xfregs.texcoords[5].texmtxinfo.hex = data; break;
case 0x1046: xfregs.texcoords[6].texmtxinfo.hex = data; break;
case 0x1047: xfregs.texcoords[7].texmtxinfo.hex = data; break;
case 0x1048:
case 0x1049:
case 0x104a:
case 0x104b:
case 0x104c:
case 0x104d:
case 0x104e:
case 0x104f:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
case 0x1050: xfregs.texcoords[0].postmtxinfo.hex = data; break;
case 0x1051: xfregs.texcoords[1].postmtxinfo.hex = data; break;
case 0x1052: xfregs.texcoords[2].postmtxinfo.hex = data; break;
case 0x1053: xfregs.texcoords[3].postmtxinfo.hex = data; break;
case 0x1054: xfregs.texcoords[4].postmtxinfo.hex = data; break;
case 0x1055: xfregs.texcoords[5].postmtxinfo.hex = data; break;
case 0x1056: xfregs.texcoords[6].postmtxinfo.hex = data; break;
case 0x1057: xfregs.texcoords[7].postmtxinfo.hex = data; break;
default:
DEBUG_LOG("xf addr: %x=%x\n", address, data);
break;
}
}
else if (address >= 0x4000)
{
// MessageBox(NULL, "1", "1", MB_OK);
//4010 __GXSetGenMode
}
}
}
// TODO - verify that it is correct. Seems to work, though.
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
VertexManager::Flush();
VertexShaderManager::InvalidateXFRange(address, address + size);
//PRIM_LOG("xfmem iwrite: 0x%x-0x%x\n", address, address + size);
for (int i = 0; i < size; i++)
xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array] * index + i * 4);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,367 +1,367 @@
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <vector>
#include <string>
#include "../../../Core/InputCommon/Src/SDL.h" // Core
#include "../../../Core/InputCommon/Src/XInput.h"
#include "Common.h" // Common
#include "MathUtil.h"
#include "StringUtil.h" // for ArrayToString()
#include "IniFile.h"
#include "pluginspecs_wiimote.h"
#include "EmuDefinitions.h" // Local
#include "main.h"
#include "wiimote_hid.h"
#include "EmuSubroutines.h"
#include "EmuMain.h"
#include "Encryption.h" // for extension encryption
#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
#include "Config.h" // for g_Config
////////////////////////////////////
namespace WiiMoteEmu
{
//******************************************************************************
// Accelerometer functions
//******************************************************************************
//////////////////////////////////////////////////////////////////////////////////////////
// Test the calculations
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void TiltTest(u8 x, u8 y, u8 z)
{
int Roll, Pitch, RollAdj, PitchAdj;
PitchAccelerometerToDegree(x, y, z, Roll, Pitch, RollAdj, PitchAdj);
std::string From = StringFromFormat("From: X:%i Y:%i Z:%i Roll:%s Pitch:%s", x, y, z,
(Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
(Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str());
float _Roll = (float)Roll, _Pitch = (float)Pitch;
PitchDegreeToAccelerometer(_Roll, _Pitch, x, y, z);
std::string To = StringFromFormat("%s\nTo: X:%i Y:%i Z:%i Roll:%s Pitch:%s", From.c_str(), x, y, z,
(_Roll >= 0) ? StringFromFormat(" %03i", (int)_Roll).c_str() : StringFromFormat("%04i", (int)_Roll).c_str(),
(_Pitch >= 0) ? StringFromFormat(" %03i", (int)_Pitch).c_str() : StringFromFormat("%04i", (int)_Pitch).c_str());
Console::Print("%s\n", To.c_str());
}
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/* Angles adjustment for the upside down state when both roll and pitch is used. When the absolute values
of the angles go over 90<39> the Wiimote is upside down and these adjustments are needed. */
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void AdjustAngles(float &Roll, float &Pitch)
{
float OldPitch = Pitch;
if (abs(Roll) > 90)
{
if (Pitch >= 0)
Pitch = 180 - Pitch; // 15 to 165
else if (Pitch < 0)
Pitch = -180 - Pitch; // -15 to -165
}
if (abs(OldPitch) > 90)
{
if (Roll >= 0)
Roll = 180 - Roll; // 15 to 165
else if (Roll < 0)
Roll = -180 - Roll; // -15 to -165
}
}
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Angles to accelerometer values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z)
{
// We need radiands for the math functions
_Roll = InputCommon::Deg2Rad(_Roll);
_Pitch = InputCommon::Deg2Rad(_Pitch);
// We need decimal values
float x = (float)_x, y = (float)_y, z = (float)_z;
// In these cases we can use the simple and accurate formula
if(g_Config.Trigger.Range.Pitch == 0)
{
x = sin(_Roll);
z = cos(_Roll);
}
else if (g_Config.Trigger.Range.Roll == 0)
{
y = sin(_Pitch);
z = cos(_Pitch);
}
else
{
// ====================================================
/* This seems to always produce the exact same combination of x, y, z and Roll and Pitch that the
real Wiimote produce. There is an unlimited amount of x, y, z combinations for any combination of
Roll and Pitch. But if we select a Z from the smallest of the absolute value of cos(Roll) and
cos (Pitch) we get the right values. */
// ---------
if (abs(cos(_Roll)) < abs(cos(_Pitch))) z = cos(_Roll); else z = cos(_Pitch);
/* I got these from reversing the calculation in PitchAccelerometerToDegree() in a math program
I don't know if we can derive these from some kind of matrix or something */
float x_num = 2 * tanf(0.5f * _Roll) * z;
float x_den = pow2f(tanf(0.5f * _Roll)) - 1;
x = - (x_num / x_den);
float y_num = 2 * tanf(0.5f * _Pitch) * z;
float y_den = pow2f(tanf(0.5f * _Pitch)) - 1;
y = - (y_num / y_den);
// =========================
}
// Multiply with the neutral of z and its g
float xg = g_wm.cal_g.x;
float yg = g_wm.cal_g.y;
float zg = g_wm.cal_g.z;
float x_zero = g_wm.cal_zero.x;
float y_zero = g_wm.cal_zero.y;
float z_zero = g_wm.cal_zero.z;
int ix = (int) (x_zero + xg * x);
int iy = (int) (y_zero + yg * y);
int iz = (int) (z_zero + zg * z);
// Boundaries
if (ix < 0) ix = 0; if (ix > 255) ix = 255;
if (iy < 0) iy = 0; if (iy > 255) iy = 255;
if (iz < 0) iz = 0; if (iz > 255) iz = 255;
if(g_Config.Trigger.Range.Roll != 0) _x = ix;
if(g_Config.Trigger.Range.Pitch != 0) _y = iy;
_z = iz;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Accelerometer to roll and pitch angles
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
float AccelerometerToG(float Current, float Neutral, float G)
{
float _G = (Current - Neutral) / G;
return _G;
}
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj)
{
// Definitions
float Roll = 0, Pitch = 0;
// Calculate how many g we are from the neutral
float x = AccelerometerToG((float)_x, (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x);
float y = AccelerometerToG((float)_y, (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y);
float z = AccelerometerToG((float)_z, (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z);
// If it is over 1g then it is probably accelerating and may not reliable
//if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x)
{
// Calculate the degree
Roll = InputCommon::Rad2Deg(atan2(x, z));
}
//if (abs(_y - g_wm.cal_zero.y) <= g_wm.cal_g.y)
{
// Calculate the degree
Pitch = InputCommon::Rad2Deg(atan2(y, z));
}
_Roll = (int)Roll;
_Pitch = (int)Pitch;
/* Don't allow forces bigger than 1g */
if (x < -1.0) x = -1.0; else if (x > 1.0) x = 1.0;
if (y < -1.0) y = -1.0; else if (y > 1.0) y = 1.0;
if (z < -1.0) z = -1.0; else if (z > 1.0) z = 1.0;
Roll = InputCommon::Rad2Deg(atan2(x, z));
Pitch = InputCommon::Rad2Deg(atan2(y, z));
_RollAdj = (int)Roll;
_PitchAdj = (int)Pitch;
}
//******************************************************************************
// IR data functions
//******************************************************************************
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the basic 10 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2DotsBasic(u8 *Data)
{
struct SDot* Dot = g_Wm.IR.Dot;
Dot[0].Rx = 1023 - (Data[0] | ((Data[2] & 0x30) << 4));
Dot[0].Ry = Data[1] | ((Data[2] & 0xc0) << 2);
Dot[1].Rx = 1023 - (Data[3] | ((Data[2] & 0x03) << 8));
Dot[1].Ry = Data[4] | ((Data[2] & 0x0c) << 6);
Dot[2].Rx = 1023 - (Data[5] | ((Data[7] & 0x30) << 4));
Dot[2].Ry = Data[6] | ((Data[7] & 0xc0) << 2);
Dot[3].Rx = 1023 - (Data[8] | ((Data[7] & 0x03) << 8));
Dot[3].Ry = Data[9] | ((Data[7] & 0x0c) << 6);
/* set each IR spot to visible if spot is in range */
for (int i = 0; i < 4; ++i)
{
if (Dot[i].Ry == 1023)
{
Dot[i].Visible = 0;
}
else
{
Dot[i].Visible = 1;
Dot[i].Size = 0; /* since we don't know the size, set it as 0 */
}
// For now we let our virtual resolution be the same as the default one
Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
}
// Calculate the other values
ReorderIRDots();
IRData2Distance();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the extented 12 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2Dots(u8 *Data)
{
struct SDot* Dot = g_Wm.IR.Dot;
for (int i = 0; i < 4; ++i)
{
//Console::Print("Rx: %i\n", Dot[i].Rx);
Dot[i].Rx = 1023 - (Data[3*i] | ((Data[(3*i)+2] & 0x30) << 4));
Dot[i].Ry = Data[(3*i)+1] | ((Data[(3*i)+2] & 0xc0) << 2);
Dot[i].Size = Data[(3*i)+2] & 0x0f;
/* if in range set to visible */
if (Dot[i].Ry == 1023)
Dot[i].Visible = false;
else
Dot[i].Visible = true;
//Console::Print("Rx: %i\n", Dot[i].Rx);
// For now we let our virtual resolution be the same as the default one
Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
}
// Calculate the other values
ReorderIRDots();
IRData2Distance();
}
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Reorder the IR dots according to their x-axis value
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ReorderIRDots()
{
// Create a shortcut
struct SDot* Dot = g_Wm.IR.Dot;
// Variables
int i, j, order;
// Reset the dot ordering to zero
for (i = 0; i < 4; ++i)
Dot[i].Order = 0;
for (order = 1; order < 5; ++order)
{
i = 0;
//
for (; !Dot[i].Visible || Dot[i].Order; ++i)
if (i > 4) return;
//
for (j = 0; j < 4; ++j)
{
if (Dot[j].Visible && !Dot[j].Order && (Dot[j].X < Dot[i].X))
i = j;
}
Dot[i].Order = order;
}
}
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the extented 12 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2Distance()
{
// Create a shortcut
struct SDot* Dot = g_Wm.IR.Dot;
// Make these ones global
int i1, i2;
for (i1 = 0; i1 < 4; ++i1)
if (Dot[i1].Visible) break;
// Only one dot was visible, we can not calculate the distance
if (i1 == 4) { g_Wm.IR.Distance = 0; return; }
// Look at the next dot
for (i2 = i1 + 1; i2 < 4; ++i2)
if (Dot[i2].Visible) break;
// Only one dot was visible, we can not calculate the distance
if (i2 == 4) { g_Wm.IR.Distance = 0; return; }
/* For the emulated Wiimote the y distance is always zero so then the distance is the
simple distance between the x dots, i.e. the sensor bar width */
int xd = Dot[i2].X - Dot[i1].X;
int yd = Dot[i2].Y - Dot[i1].Y;
// Save the distance
g_Wm.IR.Distance = (int)sqrt((float)(xd*xd) + (float)(yd*yd));
}
////////////////////////////////
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <vector>
#include <string>
#include "../../../Core/InputCommon/Src/SDL.h" // Core
#include "../../../Core/InputCommon/Src/XInput.h"
#include "Common.h" // Common
#include "MathUtil.h"
#include "StringUtil.h" // for ArrayToString()
#include "IniFile.h"
#include "pluginspecs_wiimote.h"
#include "EmuDefinitions.h" // Local
#include "main.h"
#include "wiimote_hid.h"
#include "EmuSubroutines.h"
#include "EmuMain.h"
#include "Encryption.h" // for extension encryption
#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
#include "Config.h" // for g_Config
////////////////////////////////////
namespace WiiMoteEmu
{
//******************************************************************************
// Accelerometer functions
//******************************************************************************
//////////////////////////////////////////////////////////////////////////////////////////
// Test the calculations
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void TiltTest(u8 x, u8 y, u8 z)
{
int Roll, Pitch, RollAdj, PitchAdj;
PitchAccelerometerToDegree(x, y, z, Roll, Pitch, RollAdj, PitchAdj);
std::string From = StringFromFormat("From: X:%i Y:%i Z:%i Roll:%s Pitch:%s", x, y, z,
(Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
(Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str());
float _Roll = (float)Roll, _Pitch = (float)Pitch;
PitchDegreeToAccelerometer(_Roll, _Pitch, x, y, z);
std::string To = StringFromFormat("%s\nTo: X:%i Y:%i Z:%i Roll:%s Pitch:%s", From.c_str(), x, y, z,
(_Roll >= 0) ? StringFromFormat(" %03i", (int)_Roll).c_str() : StringFromFormat("%04i", (int)_Roll).c_str(),
(_Pitch >= 0) ? StringFromFormat(" %03i", (int)_Pitch).c_str() : StringFromFormat("%04i", (int)_Pitch).c_str());
Console::Print("%s\n", To.c_str());
}
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/* Angles adjustment for the upside down state when both roll and pitch is used. When the absolute values
of the angles go over 90<39> the Wiimote is upside down and these adjustments are needed. */
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void AdjustAngles(float &Roll, float &Pitch)
{
float OldPitch = Pitch;
if (abs(Roll) > 90)
{
if (Pitch >= 0)
Pitch = 180 - Pitch; // 15 to 165
else if (Pitch < 0)
Pitch = -180 - Pitch; // -15 to -165
}
if (abs(OldPitch) > 90)
{
if (Roll >= 0)
Roll = 180 - Roll; // 15 to 165
else if (Roll < 0)
Roll = -180 - Roll; // -15 to -165
}
}
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Angles to accelerometer values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z)
{
// We need radiands for the math functions
_Roll = InputCommon::Deg2Rad(_Roll);
_Pitch = InputCommon::Deg2Rad(_Pitch);
// We need decimal values
float x = (float)_x, y = (float)_y, z = (float)_z;
// In these cases we can use the simple and accurate formula
if(g_Config.Trigger.Range.Pitch == 0)
{
x = sin(_Roll);
z = cos(_Roll);
}
else if (g_Config.Trigger.Range.Roll == 0)
{
y = sin(_Pitch);
z = cos(_Pitch);
}
else
{
// ====================================================
/* This seems to always produce the exact same combination of x, y, z and Roll and Pitch that the
real Wiimote produce. There is an unlimited amount of x, y, z combinations for any combination of
Roll and Pitch. But if we select a Z from the smallest of the absolute value of cos(Roll) and
cos (Pitch) we get the right values. */
// ---------
if (abs(cos(_Roll)) < abs(cos(_Pitch))) z = cos(_Roll); else z = cos(_Pitch);
/* I got these from reversing the calculation in PitchAccelerometerToDegree() in a math program
I don't know if we can derive these from some kind of matrix or something */
float x_num = 2 * tanf(0.5f * _Roll) * z;
float x_den = pow2f(tanf(0.5f * _Roll)) - 1;
x = - (x_num / x_den);
float y_num = 2 * tanf(0.5f * _Pitch) * z;
float y_den = pow2f(tanf(0.5f * _Pitch)) - 1;
y = - (y_num / y_den);
// =========================
}
// Multiply with the neutral of z and its g
float xg = g_wm.cal_g.x;
float yg = g_wm.cal_g.y;
float zg = g_wm.cal_g.z;
float x_zero = g_wm.cal_zero.x;
float y_zero = g_wm.cal_zero.y;
float z_zero = g_wm.cal_zero.z;
int ix = (int) (x_zero + xg * x);
int iy = (int) (y_zero + yg * y);
int iz = (int) (z_zero + zg * z);
// Boundaries
if (ix < 0) ix = 0; if (ix > 255) ix = 255;
if (iy < 0) iy = 0; if (iy > 255) iy = 255;
if (iz < 0) iz = 0; if (iz > 255) iz = 255;
if(g_Config.Trigger.Range.Roll != 0) _x = ix;
if(g_Config.Trigger.Range.Pitch != 0) _y = iy;
_z = iz;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Accelerometer to roll and pitch angles
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
float AccelerometerToG(float Current, float Neutral, float G)
{
float _G = (Current - Neutral) / G;
return _G;
}
void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj)
{
// Definitions
float Roll = 0, Pitch = 0;
// Calculate how many g we are from the neutral
float x = AccelerometerToG((float)_x, (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x);
float y = AccelerometerToG((float)_y, (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y);
float z = AccelerometerToG((float)_z, (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z);
// If it is over 1g then it is probably accelerating and may not reliable
//if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x)
{
// Calculate the degree
Roll = InputCommon::Rad2Deg(atan2(x, z));
}
//if (abs(_y - g_wm.cal_zero.y) <= g_wm.cal_g.y)
{
// Calculate the degree
Pitch = InputCommon::Rad2Deg(atan2(y, z));
}
_Roll = (int)Roll;
_Pitch = (int)Pitch;
/* Don't allow forces bigger than 1g */
if (x < -1.0) x = -1.0; else if (x > 1.0) x = 1.0;
if (y < -1.0) y = -1.0; else if (y > 1.0) y = 1.0;
if (z < -1.0) z = -1.0; else if (z > 1.0) z = 1.0;
Roll = InputCommon::Rad2Deg(atan2(x, z));
Pitch = InputCommon::Rad2Deg(atan2(y, z));
_RollAdj = (int)Roll;
_PitchAdj = (int)Pitch;
}
//******************************************************************************
// IR data functions
//******************************************************************************
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the basic 10 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2DotsBasic(u8 *Data)
{
struct SDot* Dot = g_Wm.IR.Dot;
Dot[0].Rx = 1023 - (Data[0] | ((Data[2] & 0x30) << 4));
Dot[0].Ry = Data[1] | ((Data[2] & 0xc0) << 2);
Dot[1].Rx = 1023 - (Data[3] | ((Data[2] & 0x03) << 8));
Dot[1].Ry = Data[4] | ((Data[2] & 0x0c) << 6);
Dot[2].Rx = 1023 - (Data[5] | ((Data[7] & 0x30) << 4));
Dot[2].Ry = Data[6] | ((Data[7] & 0xc0) << 2);
Dot[3].Rx = 1023 - (Data[8] | ((Data[7] & 0x03) << 8));
Dot[3].Ry = Data[9] | ((Data[7] & 0x0c) << 6);
/* set each IR spot to visible if spot is in range */
for (int i = 0; i < 4; ++i)
{
if (Dot[i].Ry == 1023)
{
Dot[i].Visible = 0;
}
else
{
Dot[i].Visible = 1;
Dot[i].Size = 0; /* since we don't know the size, set it as 0 */
}
// For now we let our virtual resolution be the same as the default one
Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
}
// Calculate the other values
ReorderIRDots();
IRData2Distance();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the extented 12 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2Dots(u8 *Data)
{
struct SDot* Dot = g_Wm.IR.Dot;
for (int i = 0; i < 4; ++i)
{
//Console::Print("Rx: %i\n", Dot[i].Rx);
Dot[i].Rx = 1023 - (Data[3*i] | ((Data[(3*i)+2] & 0x30) << 4));
Dot[i].Ry = Data[(3*i)+1] | ((Data[(3*i)+2] & 0xc0) << 2);
Dot[i].Size = Data[(3*i)+2] & 0x0f;
/* if in range set to visible */
if (Dot[i].Ry == 1023)
Dot[i].Visible = false;
else
Dot[i].Visible = true;
//Console::Print("Rx: %i\n", Dot[i].Rx);
// For now we let our virtual resolution be the same as the default one
Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
}
// Calculate the other values
ReorderIRDots();
IRData2Distance();
}
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Reorder the IR dots according to their x-axis value
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ReorderIRDots()
{
// Create a shortcut
struct SDot* Dot = g_Wm.IR.Dot;
// Variables
int i, j, order;
// Reset the dot ordering to zero
for (i = 0; i < 4; ++i)
Dot[i].Order = 0;
for (order = 1; order < 5; ++order)
{
i = 0;
//
for (; !Dot[i].Visible || Dot[i].Order; ++i)
if (i > 4) return;
//
for (j = 0; j < 4; ++j)
{
if (Dot[j].Visible && !Dot[j].Order && (Dot[j].X < Dot[i].X))
i = j;
}
Dot[i].Order = order;
}
}
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Calculate dot positions from the extented 12 byte IR data
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void IRData2Distance()
{
// Create a shortcut
struct SDot* Dot = g_Wm.IR.Dot;
// Make these ones global
int i1, i2;
for (i1 = 0; i1 < 4; ++i1)
if (Dot[i1].Visible) break;
// Only one dot was visible, we can not calculate the distance
if (i1 == 4) { g_Wm.IR.Distance = 0; return; }
// Look at the next dot
for (i2 = i1 + 1; i2 < 4; ++i2)
if (Dot[i2].Visible) break;
// Only one dot was visible, we can not calculate the distance
if (i2 == 4) { g_Wm.IR.Distance = 0; return; }
/* For the emulated Wiimote the y distance is always zero so then the distance is the
simple distance between the x dots, i.e. the sensor bar width */
int xd = Dot[i2].X - Dot[i1].X;
int yd = Dot[i2].Y - Dot[i1].Y;
// Save the distance
g_Wm.IR.Distance = (int)sqrt((float)(xd*xd) + (float)(yd*yd));
}
////////////////////////////////
} // WiiMoteEmu

View File

@ -1,194 +1,194 @@
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <vector>
#include <string>
#include "../../../Core/InputCommon/Src/SDL.h" // Core
#include "../../../Core/InputCommon/Src/XInput.h"
#include "Common.h" // Common
#include "StringUtil.h" // for ArrayToString()
#include "IniFile.h"
#include "pluginspecs_wiimote.h"
#include "EmuDefinitions.h" // Local
#include "main.h"
#include "wiimote_hid.h"
#include "EmuSubroutines.h"
#include "EmuMain.h"
#include "Encryption.h" // for extension encryption
#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
#include "Config.h" // for g_Config
////////////////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu
{
// ===================================================
// Fill joyinfo with the current connected devices
// ----------------
bool Search_Devices(std::vector<InputCommon::CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads)
{
bool Success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads);
// Warn the user if no gamepads are detected
if (_NumGoodPads == 0 && g_EmulatorRunning)
{
//PanicAlert("nJoy: No Gamepad Detected");
//return false;
}
// Load PadMapping[] etc
g_Config.Load();
// Update the PadState[].joy handle
for (int i = 0; i < 1; i++)
{
if (PadMapping[i].enabled && joyinfo.size() > PadMapping[i].ID)
if(joyinfo.at(PadMapping[i].ID).Good)
PadState[i].joy = SDL_JoystickOpen(PadMapping[i].ID);
}
return Success;
}
// ===========================
//////////////////////////////////////////////////////////////////////////////////////////
// Return adjusted input values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr)
{
// This has to be changed if multiple Wiimotes are to be supported later
const int Page = 0;
// Copy all states to a local variable
Lx = PadState[Page].Axis.Lx;
Ly = PadState[Page].Axis.Ly;
Rx = PadState[Page].Axis.Rx;
Ry = PadState[Page].Axis.Ry;
Tl = PadState[Page].Axis.Tl;
Tr = PadState[Page].Axis.Tr;
// Check the circle to square option
if(PadMapping[Page].bCircle2Square)
{
std::vector<int> main_xy = InputCommon::Square2Circle(Lx, Ly, Page, PadMapping[Page].SDiagonal, true);
Lx = main_xy.at(0);
Ly = main_xy.at(1);
}
// Dead zone adjustment
float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f;
float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f;
if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly))
{
Lx = 0;
Ly = 0;
}
if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry))
{
Rx = 0;
Ry = 0;
}
// Downsize the values from 0x8000 to 0x80
Lx = InputCommon::Pad_Convert(Lx);
Ly = InputCommon::Pad_Convert(Ly);
Rx = InputCommon::Pad_Convert(Rx);
Ry = InputCommon::Pad_Convert(Ry);
// The XInput range is already 0 to 0x80
if (PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL)
{
Tl = InputCommon::Pad_Convert(PadState[Page].Axis.Tl);
Tr = InputCommon::Pad_Convert(PadState[Page].Axis.Tr);
}
}
////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Request joystick state
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/* Called from: PAD_GetStatus()
Input: The virtual device 0, 1, 2 or 3
Function: Updates the PadState struct with the current pad status. The input value "controller" is
for a virtual controller 0 to 3. */
void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons)
{
// Return if we have no pads
if (NumGoodPads == 0) return;
// Update the gamepad status
SDL_JoystickUpdate();
// Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here.
_PadState.Axis.Lx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Lx);
_PadState.Axis.Ly = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ly);
_PadState.Axis.Rx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Rx);
_PadState.Axis.Ry = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ry);
// Update the analog trigger axis values
#ifdef _WIN32
if (_PadMapping.triggertype == InputCommon::CTL_TRIGGER_SDL)
{
#endif
// If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used
// We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has
// no good way of handling that
if ((_PadMapping.Axis.Tl - 1000) >= 0) _PadState.Axis.Tl = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tl - 1000);
if ((_PadMapping.Axis.Tr - 1000) >= 0) _PadState.Axis.Tr = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tr - 1000);
#ifdef _WIN32
}
else
{
_PadState.Axis.Tl = XInput::GetXI(0, _PadMapping.Axis.Tl - 1000);
_PadState.Axis.Tr = XInput::GetXI(0, _PadMapping.Axis.Tr - 1000);
}
#endif
/* Debugging
Console::ClearScreen();
Console::Print(
"Controller and handle: %i %i\n"
"Triggers:%i %i %i %i %i\n"
"Analog:%06i %06i \n",
controller, (int)_PadState.joy,
_PadMapping.triggertype,
_PadMapping.Axis.Tl, _PadMapping.Axis.Tr,
_PadState.Axis.Tl, _PadState.Axis.Tr,
_PadState.Axis.Lx, _PadState.Axis.Ly
);*/
}
////////////////////////////////////////////
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <vector>
#include <string>
#include "../../../Core/InputCommon/Src/SDL.h" // Core
#include "../../../Core/InputCommon/Src/XInput.h"
#include "Common.h" // Common
#include "StringUtil.h" // for ArrayToString()
#include "IniFile.h"
#include "pluginspecs_wiimote.h"
#include "EmuDefinitions.h" // Local
#include "main.h"
#include "wiimote_hid.h"
#include "EmuSubroutines.h"
#include "EmuMain.h"
#include "Encryption.h" // for extension encryption
#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
#include "Config.h" // for g_Config
////////////////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu
{
// ===================================================
// Fill joyinfo with the current connected devices
// ----------------
bool Search_Devices(std::vector<InputCommon::CONTROLLER_INFO> &_joyinfo, int &_NumPads, int &_NumGoodPads)
{
bool Success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads);
// Warn the user if no gamepads are detected
if (_NumGoodPads == 0 && g_EmulatorRunning)
{
//PanicAlert("nJoy: No Gamepad Detected");
//return false;
}
// Load PadMapping[] etc
g_Config.Load();
// Update the PadState[].joy handle
for (int i = 0; i < 1; i++)
{
if (PadMapping[i].enabled && joyinfo.size() > PadMapping[i].ID)
if(joyinfo.at(PadMapping[i].ID).Good)
PadState[i].joy = SDL_JoystickOpen(PadMapping[i].ID);
}
return Success;
}
// ===========================
//////////////////////////////////////////////////////////////////////////////////////////
// Return adjusted input values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr)
{
// This has to be changed if multiple Wiimotes are to be supported later
const int Page = 0;
// Copy all states to a local variable
Lx = PadState[Page].Axis.Lx;
Ly = PadState[Page].Axis.Ly;
Rx = PadState[Page].Axis.Rx;
Ry = PadState[Page].Axis.Ry;
Tl = PadState[Page].Axis.Tl;
Tr = PadState[Page].Axis.Tr;
// Check the circle to square option
if(PadMapping[Page].bCircle2Square)
{
std::vector<int> main_xy = InputCommon::Square2Circle(Lx, Ly, Page, PadMapping[Page].SDiagonal, true);
Lx = main_xy.at(0);
Ly = main_xy.at(1);
}
// Dead zone adjustment
float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f;
float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f;
if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly))
{
Lx = 0;
Ly = 0;
}
if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry))
{
Rx = 0;
Ry = 0;
}
// Downsize the values from 0x8000 to 0x80
Lx = InputCommon::Pad_Convert(Lx);
Ly = InputCommon::Pad_Convert(Ly);
Rx = InputCommon::Pad_Convert(Rx);
Ry = InputCommon::Pad_Convert(Ry);
// The XInput range is already 0 to 0x80
if (PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL)
{
Tl = InputCommon::Pad_Convert(PadState[Page].Axis.Tl);
Tr = InputCommon::Pad_Convert(PadState[Page].Axis.Tr);
}
}
////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Request joystick state
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/* Called from: PAD_GetStatus()
Input: The virtual device 0, 1, 2 or 3
Function: Updates the PadState struct with the current pad status. The input value "controller" is
for a virtual controller 0 to 3. */
void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons)
{
// Return if we have no pads
if (NumGoodPads == 0) return;
// Update the gamepad status
SDL_JoystickUpdate();
// Update axis states. It doesn't hurt much if we happen to ask for nonexisting axises here.
_PadState.Axis.Lx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Lx);
_PadState.Axis.Ly = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ly);
_PadState.Axis.Rx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Rx);
_PadState.Axis.Ry = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ry);
// Update the analog trigger axis values
#ifdef _WIN32
if (_PadMapping.triggertype == InputCommon::CTL_TRIGGER_SDL)
{
#endif
// If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used
// We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has
// no good way of handling that
if ((_PadMapping.Axis.Tl - 1000) >= 0) _PadState.Axis.Tl = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tl - 1000);
if ((_PadMapping.Axis.Tr - 1000) >= 0) _PadState.Axis.Tr = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tr - 1000);
#ifdef _WIN32
}
else
{
_PadState.Axis.Tl = XInput::GetXI(0, _PadMapping.Axis.Tl - 1000);
_PadState.Axis.Tr = XInput::GetXI(0, _PadMapping.Axis.Tr - 1000);
}
#endif
/* Debugging
Console::ClearScreen();
Console::Print(
"Controller and handle: %i %i\n"
"Triggers:%i %i %i %i %i\n"
"Analog:%06i %06i \n",
controller, (int)_PadState.joy,
_PadMapping.triggertype,
_PadMapping.Axis.Tl, _PadMapping.Axis.Tr,
_PadState.Axis.Tl, _PadState.Axis.Tr,
_PadState.Axis.Lx, _PadState.Axis.Ly
);*/
}
////////////////////////////////////////////
} // end of namespace WiiMoteEmu

View File

@ -1,119 +1,119 @@
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// -------------
#include <string>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include "StringUtil.h"
#define HAVE_WX 1
#if defined(HAVE_WX) && HAVE_WX // wxWidgets
#include <wx/datetime.h> // for the timestamps
#endif
///////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Settings
// -------------
// On and off
bool g_consoleEnable = true;
bool gSaveFile = true;
#define DEBUG_WIIMOTE // On or off
const int nFiles = 1;
// Create handles
#ifdef DEBUG_WIIMOTE
FILE* __fStdOut[nFiles];
#endif
#ifdef _WIN32
HANDLE __hStdOut = NULL;
#endif
//////////////////////////////
// =======================================================================================
/* Get Timestamp */
// -------------
std::string Tm(bool Ms)
{
#if defined(HAVE_WX) && HAVE_WX
std::string Tmp;
if(Ms)
{
wxDateTime datetime = wxDateTime::UNow(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i:%03i",
datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond());
}
else
{
wxDateTime datetime = wxDateTime::Now(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i",
datetime.GetMinute(), datetime.GetSecond());
}
return Tmp;
#else
std::string Tmp = "";
return Tmp;
#endif
}
// ===========================
// ---------------------------------------------------------------------------------------
// File printf function
// ---------------
int PrintFile(int a, char *fmt, ...)
{
#if defined(DEBUG_WIIMOTE) && defined(_WIN32)
if(gSaveFile)
{
char s[500]; // WARNING: mind this value
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(s, 500, fmt, argptr); // remember to update this value to
va_end(argptr);
// ---------------------------------------------------------------------------------------
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
//to make it work
fprintf(__fStdOut[a], s);
fflush(__fStdOut[0]); // Write file now, don't wait
// -------------
return(cnt);
}
else
{
return 0;
}
#else
return 0;
#endif
}
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// -------------
#include <string>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include "StringUtil.h"
#define HAVE_WX 1
#if defined(HAVE_WX) && HAVE_WX // wxWidgets
#include <wx/datetime.h> // for the timestamps
#endif
///////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Settings
// -------------
// On and off
bool g_consoleEnable = true;
bool gSaveFile = true;
#define DEBUG_WIIMOTE // On or off
const int nFiles = 1;
// Create handles
#ifdef DEBUG_WIIMOTE
FILE* __fStdOut[nFiles];
#endif
#ifdef _WIN32
HANDLE __hStdOut = NULL;
#endif
//////////////////////////////
// =======================================================================================
/* Get Timestamp */
// -------------
std::string Tm(bool Ms)
{
#if defined(HAVE_WX) && HAVE_WX
std::string Tmp;
if(Ms)
{
wxDateTime datetime = wxDateTime::UNow(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i:%03i",
datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond());
}
else
{
wxDateTime datetime = wxDateTime::Now(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i",
datetime.GetMinute(), datetime.GetSecond());
}
return Tmp;
#else
std::string Tmp = "";
return Tmp;
#endif
}
// ===========================
// ---------------------------------------------------------------------------------------
// File printf function
// ---------------
int PrintFile(int a, char *fmt, ...)
{
#if defined(DEBUG_WIIMOTE) && defined(_WIN32)
if(gSaveFile)
{
char s[500]; // WARNING: mind this value
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(s, 500, fmt, argptr); // remember to update this value to
va_end(argptr);
// ---------------------------------------------------------------------------------------
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
//to make it work
fprintf(__fStdOut[a], s);
fflush(__fStdOut[0]); // Write file now, don't wait
// -------------
return(cnt);
}
else
{
return 0;
}
#else
return 0;
#endif
}

View File

@ -1,386 +1,386 @@
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <iostream> // System
#include "wiiuse.h" // Externals
#include "ConsoleWindow.h" // Common
#include "StringUtil.h"
#include "Timer.h"
#include "pluginspecs_wiimote.h"
#include "wiimote_real.h" // Local
#include "wiimote_hid.h"
#include "EmuDefinitions.h"
#include "EmuMain.h"
#include "main.h"
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
#endif
#include "Config.h"
////////////////////////////////////////
namespace WiiMoteReal
{
int GetReportSize(struct wiimote_t* wm)
{
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
if(WIIUSE_USING_EXP(wm)) return 22; else return 18;
}
void handle_ctrl_status(struct wiimote_t* wm)
{
Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid);
Console::Print("attachment: %i\n", wm->exp.type);
Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm));
Console::Print("ir: %i\n", WIIUSE_USING_IR(wm));
Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4));
Console::Print("battery: %f %%\n", wm->battery_level);
}
bool IRDataOK(struct wiimote_t* wm)
{
//Console::Print("IRDataOK: ");
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
int ReportSize = GetReportSize(wm);
for(int i = 0; i < ReportSize; i++)
{
//Console::Print("%02x ", wm->event_buf[i]);
if (wm->event_buf[i] > 0)
{
//Console::Print("\n");
return true;
}
}
return false;
}
void handle_event(struct wiimote_t* wm)
{
//Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid);
// if a button is pressed, report it
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) Console::Print("B pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) Console::Print("UP pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) Console::Print("DOWN pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) Console::Print("LEFT pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) Console::Print("RIGHT pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) Console::Print("MINUS pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) Console::Print("PLUS pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) Console::Print("ONE pressed\n");
//if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false;
if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) Console::Print("TWO pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) Console::Print("HOME pressed\n");
// Pressing minus will tell the wiimote we are no longer interested in movement.
// This is useful because it saves battery power.
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
{
wiiuse_motion_sensing(wm, 0);
wiiuse_set_ir(wm, 0);
g_MotionSensing = false;
}
// Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on
// directly after each other, so we have to wait for another wiiuse_poll() this way
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
{
wiiuse_motion_sensing(wm, 1);
g_MotionSensing = true;
}
// Turn IR reporting on
if (g_MotionSensing && !WIIUSE_USING_IR(wm))
wiiuse_set_ir(wm, 1);
// Print battery status
#if defined(HAVE_WX) && HAVE_WX
if(frame && g_Config.bUpdateRealWiimote)
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
#endif
// Create shortcut to the nunchuck
struct nunchuk_t* nc = NULL;
if (wm->exp.type == EXP_NUNCHUK)
nc = (nunchuk_t*)&wm->exp.nunchuk;
// If the accelerometer is turned on then print angles
if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm))
{
std::string Tmp;
Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll);
Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch);
Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level);
Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z);
Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z);
// The report size is 0x33 = 18, 0x37 = 22
int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18;
// wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero
// after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time,
// it seems to fails with a regular interval about each tenth read.
if(wiiuse_io_read(wm))
{
// Check that it's not zero
if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize);
}
// Go through each of the 4 possible IR sources
for (int i = 0; i < 4; ++i)
{
// Check if the source is visible
if (wm->ir.dot[i].visible)
Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y);
}
Tmp += "\n";
Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y);
Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z);
if(wm->exp.type == EXP_NUNCHUK)
{
Tmp += "\n";
Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z);
}
//Tmp += "\n";
//std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30);
//Tmp += "Data: " + TmpData;
//Console::ClearScreen();
//Console::Print("%s\n\n", Tmp.c_str());
#if defined(HAVE_WX) && HAVE_WX
if(frame)
{
// Produce adjusted accelerometer values
float _Gx = (float)(wm->accel.x - wm->accel_calib.cal_zero.x) / (float)wm->accel_calib.cal_g.x;
float _Gy = (float)(wm->accel.y - wm->accel_calib.cal_zero.y) / (float)wm->accel_calib.cal_g.y;
float _Gz = (float)(wm->accel.z - wm->accel_calib.cal_zero.z) / (float)wm->accel_calib.cal_g.z;
// Conver the data to integers
int Gx = (int)(_Gx * 100);
int Gy = (int)(_Gy * 100);
int Gz = (int)(_Gz * 100);
// And for the Nunchuck
u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0;
if(wm->exp.type == EXP_NUNCHUK)
{
if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX;
if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY;
if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ;
}
if(g_Config.bUpdateRealWiimote)
{
// Update gauges
frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
// Show g. forces between -3 and 3
frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5));
frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5));
frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5));
frame->m_GaugeAccel[0]->SetValue(wm->accel.x);
frame->m_GaugeAccel[1]->SetValue(wm->accel.y);
frame->m_GaugeAccel[2]->SetValue(wm->accel.z);
frame->m_TextIR->SetLabel(wxString::Format(
wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z));
//frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format(
// wxT("Current: %03u %03u %03u"), Gx, Gy, Gz));
if(frame->m_bRecording)
Console::Print("Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", Gx, Gy, Gz);
//Console::Print("Wiiuse Recorded accel x, y, z: %02x %02x %02x\n", Gx, Gy, Gz);
}
// Send the data to be saved
//const u8* data = (const u8*)wm->event_buf;
frame->DoRecordMovement(Gx, Gy, Gz, (g_EventBuffer + 6),
(WIIUSE_USING_EXP(wm) ? 10 : 12));
// Turn recording on and off
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
else frame->DoRecordA(false);
// ------------------------------------
// Show roll and pitch in the status box
// --------------
/*
if(!g_DebugData)
{
Console::ClearScreen();
Console::Print("Roll:%03i Pitch:%03i\n", (int)wm->orient.roll, (int)wm->orient.pitch);
}
// Convert Roll and Pitch from 180 to 0x8000
int Roll = (int)wm->orient.roll * (0x8000 / 180);
int Pitch = (int)wm->orient.pitch * (0x8000 / 180);
// Convert it to the box
frame->Convert2Box(Roll);
frame->Convert2Box(Pitch);
// Show roll and pitch in the axis boxes
frame->m_bmpDotRightOut[0]->SetPosition(wxPoint(Roll, Pitch));*/
// ---------------------
}
#endif
}
// Otherwise remove the values
else
{
#if defined(HAVE_WX) && HAVE_WX
if (frame)
{
frame->m_GaugeRoll[0]->SetValue(0);
frame->m_GaugeRoll[1]->SetValue(0);
frame->m_GaugeGForce[0]->SetValue(0);
frame->m_GaugeGForce[1]->SetValue(0);
frame->m_GaugeGForce[2]->SetValue(0);
frame->m_GaugeAccel[0]->SetValue(0);
frame->m_GaugeAccel[1]->SetValue(0);
frame->m_GaugeAccel[2]->SetValue(0);
frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:"));
}
#endif
}
}
void ReadWiimote()
{
/* I place this outside wiiuse_poll() to produce a continous recording regardless of the status
change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the
timing functions for recording playback that checks the time of the recording this should not
be needed. But I still use it becase it seemed like state_changed() or the threshold values or
something else might fail so that only huge status changed were reported. */
handle_event(g_WiiMotesFromWiiUse[0]);
// Declaration
std::string Temp;
/* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten
what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular
wiiuse_io_read() and wiiuse_io_write() loop again. */
if (g_RunTemporary)
{
// The SecondsToWait holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms
static const int SecondsToWait = 2;
g_RunTemporaryCountdown++;
if(g_RunTemporaryCountdown > (SecondsToWait * 100))
{
g_RunTemporaryCountdown = 0;
g_RunTemporary = false;
}
}
// Read formatted Wiimote data
if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES))
{
/*
* This happens if something happened on any wiimote.
* So go through each one and check if anything happened.
*/
int i = 0;
for (; i < MAX_WIIMOTES; ++i)
{
switch (g_WiiMotesFromWiiUse[i]->event)
{
case WIIUSE_EVENT:
/* a generic event occured */
//handle_event(g_WiiMotesFromWiiUse[i]);
break;
case WIIUSE_STATUS:
/* a status event occured */
//handle_ctrl_status(g_WiiMotesFromWiiUse[i]);
break;
case WIIUSE_DISCONNECT:
case WIIUSE_UNEXPECTED_DISCONNECT:
/* the wiimote disconnected */
//handle_disconnect(wiimotes[i]);
break;
case WIIUSE_READ_DATA:
/*
* Data we requested to read was returned.
* Take a look at wiimotes[i]->read_req
* for the data.
*/
if(g_WiiMotesFromWiiUse[0]->read_req->size == sizeof(WiiMoteEmu::EepromData_0)
&& g_WiiMotesFromWiiUse[0]->read_req->addr == 0)
{
Temp = ArrayToString(g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30);
memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0));
Console::Print("EEPROM: %s\n", Temp.c_str());
WiiMoteEmu::UpdateEeprom();
g_RunTemporary = false;
}
break;
case WIIUSE_NUNCHUK_INSERTED:
/*
* a nunchuk was inserted
* This is a good place to set any nunchuk specific
* threshold values. By default they are the same
* as the wiimote.
*/
//wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f);
//wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100);
Console::Print("Nunchuk inserted.\n");
break;
case WIIUSE_CLASSIC_CTRL_INSERTED:
Console::Print("Classic controller inserted.\n");
break;
case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
// some expansion was inserted
//handle_ctrl_status(wiimotes[i]);
Console::Print("Guitar Hero 3 controller inserted.\n");
break;
case WIIUSE_NUNCHUK_REMOVED:
case WIIUSE_CLASSIC_CTRL_REMOVED:
case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
// some expansion was removed
//handle_ctrl_status(wiimotes[i]);
Console::Print("An expansion was removed.\n");
break;
default:
break;
}
}
}
}
}; // end of namespace
// 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/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <iostream> // System
#include "wiiuse.h" // Externals
#include "ConsoleWindow.h" // Common
#include "StringUtil.h"
#include "Timer.h"
#include "pluginspecs_wiimote.h"
#include "wiimote_real.h" // Local
#include "wiimote_hid.h"
#include "EmuDefinitions.h"
#include "EmuMain.h"
#include "main.h"
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
#endif
#include "Config.h"
////////////////////////////////////////
namespace WiiMoteReal
{
int GetReportSize(struct wiimote_t* wm)
{
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
if(WIIUSE_USING_EXP(wm)) return 22; else return 18;
}
void handle_ctrl_status(struct wiimote_t* wm)
{
Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid);
Console::Print("attachment: %i\n", wm->exp.type);
Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm));
Console::Print("ir: %i\n", WIIUSE_USING_IR(wm));
Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4));
Console::Print("battery: %f %%\n", wm->battery_level);
}
bool IRDataOK(struct wiimote_t* wm)
{
//Console::Print("IRDataOK: ");
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
int ReportSize = GetReportSize(wm);
for(int i = 0; i < ReportSize; i++)
{
//Console::Print("%02x ", wm->event_buf[i]);
if (wm->event_buf[i] > 0)
{
//Console::Print("\n");
return true;
}
}
return false;
}
void handle_event(struct wiimote_t* wm)
{
//Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid);
// if a button is pressed, report it
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) Console::Print("B pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) Console::Print("UP pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) Console::Print("DOWN pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) Console::Print("LEFT pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) Console::Print("RIGHT pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) Console::Print("MINUS pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) Console::Print("PLUS pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) Console::Print("ONE pressed\n");
//if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false;
if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) Console::Print("TWO pressed\n");
if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) Console::Print("HOME pressed\n");
// Pressing minus will tell the wiimote we are no longer interested in movement.
// This is useful because it saves battery power.
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
{
wiiuse_motion_sensing(wm, 0);
wiiuse_set_ir(wm, 0);
g_MotionSensing = false;
}
// Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on
// directly after each other, so we have to wait for another wiiuse_poll() this way
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
{
wiiuse_motion_sensing(wm, 1);
g_MotionSensing = true;
}
// Turn IR reporting on
if (g_MotionSensing && !WIIUSE_USING_IR(wm))
wiiuse_set_ir(wm, 1);
// Print battery status
#if defined(HAVE_WX) && HAVE_WX
if(frame && g_Config.bUpdateRealWiimote)
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
#endif
// Create shortcut to the nunchuck
struct nunchuk_t* nc = NULL;
if (wm->exp.type == EXP_NUNCHUK)
nc = (nunchuk_t*)&wm->exp.nunchuk;
// If the accelerometer is turned on then print angles
if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm))
{
std::string Tmp;
Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll);
Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch);
Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level);
Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z);
Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z);
// The report size is 0x33 = 18, 0x37 = 22
int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18;
// wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero
// after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time,
// it seems to fails with a regular interval about each tenth read.
if(wiiuse_io_read(wm))
{
// Check that it's not zero
if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize);
}
// Go through each of the 4 possible IR sources
for (int i = 0; i < 4; ++i)
{
// Check if the source is visible
if (wm->ir.dot[i].visible)
Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y);
}
Tmp += "\n";
Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y);
Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z);
if(wm->exp.type == EXP_NUNCHUK)
{
Tmp += "\n";
Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z);
}
//Tmp += "\n";
//std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30);
//Tmp += "Data: " + TmpData;
//Console::ClearScreen();
//Console::Print("%s\n\n", Tmp.c_str());
#if defined(HAVE_WX) && HAVE_WX
if(frame)
{
// Produce adjusted accelerometer values
float _Gx = (float)(wm->accel.x - wm->accel_calib.cal_zero.x) / (float)wm->accel_calib.cal_g.x;
float _Gy = (float)(wm->accel.y - wm->accel_calib.cal_zero.y) / (float)wm->accel_calib.cal_g.y;
float _Gz = (float)(wm->accel.z - wm->accel_calib.cal_zero.z) / (float)wm->accel_calib.cal_g.z;
// Conver the data to integers
int Gx = (int)(_Gx * 100);
int Gy = (int)(_Gy * 100);
int Gz = (int)(_Gz * 100);
// And for the Nunchuck
u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0;
if(wm->exp.type == EXP_NUNCHUK)
{
if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX;
if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY;
if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ;
}
if(g_Config.bUpdateRealWiimote)
{
// Update gauges
frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
// Show g. forces between -3 and 3
frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5));
frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5));
frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5));
frame->m_GaugeAccel[0]->SetValue(wm->accel.x);
frame->m_GaugeAccel[1]->SetValue(wm->accel.y);
frame->m_GaugeAccel[2]->SetValue(wm->accel.z);
frame->m_TextIR->SetLabel(wxString::Format(
wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z));
//frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format(
// wxT("Current: %03u %03u %03u"), Gx, Gy, Gz));
if(frame->m_bRecording)
Console::Print("Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", Gx, Gy, Gz);
//Console::Print("Wiiuse Recorded accel x, y, z: %02x %02x %02x\n", Gx, Gy, Gz);
}
// Send the data to be saved
//const u8* data = (const u8*)wm->event_buf;
frame->DoRecordMovement(Gx, Gy, Gz, (g_EventBuffer + 6),
(WIIUSE_USING_EXP(wm) ? 10 : 12));
// Turn recording on and off
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
else frame->DoRecordA(false);
// ------------------------------------
// Show roll and pitch in the status box
// --------------
/*
if(!g_DebugData)
{
Console::ClearScreen();
Console::Print("Roll:%03i Pitch:%03i\n", (int)wm->orient.roll, (int)wm->orient.pitch);
}
// Convert Roll and Pitch from 180 to 0x8000
int Roll = (int)wm->orient.roll * (0x8000 / 180);
int Pitch = (int)wm->orient.pitch * (0x8000 / 180);
// Convert it to the box
frame->Convert2Box(Roll);
frame->Convert2Box(Pitch);
// Show roll and pitch in the axis boxes
frame->m_bmpDotRightOut[0]->SetPosition(wxPoint(Roll, Pitch));*/
// ---------------------
}
#endif
}
// Otherwise remove the values
else
{
#if defined(HAVE_WX) && HAVE_WX
if (frame)
{
frame->m_GaugeRoll[0]->SetValue(0);
frame->m_GaugeRoll[1]->SetValue(0);
frame->m_GaugeGForce[0]->SetValue(0);
frame->m_GaugeGForce[1]->SetValue(0);
frame->m_GaugeGForce[2]->SetValue(0);
frame->m_GaugeAccel[0]->SetValue(0);
frame->m_GaugeAccel[1]->SetValue(0);
frame->m_GaugeAccel[2]->SetValue(0);
frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:"));
}
#endif
}
}
void ReadWiimote()
{
/* I place this outside wiiuse_poll() to produce a continous recording regardless of the status
change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the
timing functions for recording playback that checks the time of the recording this should not
be needed. But I still use it becase it seemed like state_changed() or the threshold values or
something else might fail so that only huge status changed were reported. */
handle_event(g_WiiMotesFromWiiUse[0]);
// Declaration
std::string Temp;
/* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten
what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular
wiiuse_io_read() and wiiuse_io_write() loop again. */
if (g_RunTemporary)
{
// The SecondsToWait holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms
static const int SecondsToWait = 2;
g_RunTemporaryCountdown++;
if(g_RunTemporaryCountdown > (SecondsToWait * 100))
{
g_RunTemporaryCountdown = 0;
g_RunTemporary = false;
}
}
// Read formatted Wiimote data
if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES))
{
/*
* This happens if something happened on any wiimote.
* So go through each one and check if anything happened.
*/
int i = 0;
for (; i < MAX_WIIMOTES; ++i)
{
switch (g_WiiMotesFromWiiUse[i]->event)
{
case WIIUSE_EVENT:
/* a generic event occured */
//handle_event(g_WiiMotesFromWiiUse[i]);
break;
case WIIUSE_STATUS:
/* a status event occured */
//handle_ctrl_status(g_WiiMotesFromWiiUse[i]);
break;
case WIIUSE_DISCONNECT:
case WIIUSE_UNEXPECTED_DISCONNECT:
/* the wiimote disconnected */
//handle_disconnect(wiimotes[i]);
break;
case WIIUSE_READ_DATA:
/*
* Data we requested to read was returned.
* Take a look at wiimotes[i]->read_req
* for the data.
*/
if(g_WiiMotesFromWiiUse[0]->read_req->size == sizeof(WiiMoteEmu::EepromData_0)
&& g_WiiMotesFromWiiUse[0]->read_req->addr == 0)
{
Temp = ArrayToString(g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30);
memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0));
Console::Print("EEPROM: %s\n", Temp.c_str());
WiiMoteEmu::UpdateEeprom();
g_RunTemporary = false;
}
break;
case WIIUSE_NUNCHUK_INSERTED:
/*
* a nunchuk was inserted
* This is a good place to set any nunchuk specific
* threshold values. By default they are the same
* as the wiimote.
*/
//wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f);
//wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100);
Console::Print("Nunchuk inserted.\n");
break;
case WIIUSE_CLASSIC_CTRL_INSERTED:
Console::Print("Classic controller inserted.\n");
break;
case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
// some expansion was inserted
//handle_ctrl_status(wiimotes[i]);
Console::Print("Guitar Hero 3 controller inserted.\n");
break;
case WIIUSE_NUNCHUK_REMOVED:
case WIIUSE_CLASSIC_CTRL_REMOVED:
case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
// some expansion was removed
//handle_ctrl_status(wiimotes[i]);
Console::Print("An expansion was removed.\n");
break;
default:
break;
}
}
}
}
}; // end of namespace

View File

@ -1,277 +1,277 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
#include "Common.h"
Config g_Config;
#if defined(HAVE_WX) && HAVE_WX
extern ConfigBox* m_frame;
#endif
//////////////////////////////////
// Run when created
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Config::Config()
{
// Clear the memory
//memset(this, 0, sizeof(Config));
}
// Enable output log
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void DEBUG_INIT()
{
if (pFile)
return;
#ifdef _WIN32
char dateStr [9];
_strdate( dateStr);
char timeStr [9];
_strtime( timeStr );
#endif
pFile = fopen ("nJoy-debug.txt","wt");
fprintf(pFile, "nJoy v"INPUT_VERSION" Debug\n");
#ifdef _WIN32
fprintf(pFile, "Date: %s\nTime: %s\n", dateStr, timeStr);
#endif
fprintf(pFile, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n");
}
// Disable output log
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void DEBUG_QUIT()
{
if (!pFile)
return;
#ifdef _WIN32
char timeStr [9];
_strtime(timeStr);
fprintf(pFile, "_______________\n");
fprintf(pFile, "Time: %s", timeStr);
#endif
fclose(pFile);
}
/////////////////////////////////////////////////////////////////////////////////////
// Save settings to file
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Config::Save(int Slot)
{
// If there are no good pads don't save
if (NumGoodPads == 0) return;
// Load ini file
IniFile file;
file.Load("nJoy.ini");
// ==================================================================
// Global settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
file.Set("General", "ShowAdvanced", g_Config.bShowAdvanced);
file.Set("General", "SaveByID", g_Config.bSaveByID);
file.Set("General", "CheckForFocus", g_Config.bCheckFocus);
file.Set("General", "NoTriggerFilter", g_Config.bNoTriggerFilter);
#ifdef RERECORDING
file.Set("General", "Recording", g_Config.bRecording);
file.Set("General", "Playback", g_Config.bPlayback);
#endif
// ========================
for (int i = 0; i < 4; i++)
{
// Should we save this slot?
if (Slot != -1 && Slot != i) continue;
// ==================================================================
// Slot specific settings only
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string SectionName = StringFromFormat("PAD%i", i+1);
file.Set(SectionName.c_str(), "enabled", PadMapping[i].enabled);
// Save the physical device ID
file.Set(SectionName.c_str(), "joy_id", PadMapping[i].ID);
// ===================
// ==================================================================
// Joypad or slot specific settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Current joypad device ID: PadMapping[i].ID
// Current joypad name: joyinfo[PadMapping[i].ID].Name
if(g_Config.bSaveByID)
{
/* Save joypad specific settings. Check for "PadMapping[i].ID < SDL_NumJoysticks()" to
avoid reading a joyinfo that does't exist */
if(PadMapping[i].ID >= joyinfo.size()) continue;
// Create a new section name after the joypad name
SectionName = joyinfo[PadMapping[i].ID].Name;
}
file.Set(SectionName.c_str(), "l_shoulder", PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER]);
file.Set(SectionName.c_str(), "r_shoulder", PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER]);
file.Set(SectionName.c_str(), "a_button", PadMapping[i].buttons[InputCommon::CTL_A_BUTTON]);
file.Set(SectionName.c_str(), "b_button", PadMapping[i].buttons[InputCommon::CTL_B_BUTTON]);
file.Set(SectionName.c_str(), "x_button", PadMapping[i].buttons[InputCommon::CTL_X_BUTTON]);
file.Set(SectionName.c_str(), "y_button", PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON]);
file.Set(SectionName.c_str(), "z_trigger", PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER]);
file.Set(SectionName.c_str(), "start_button", PadMapping[i].buttons[InputCommon::CTL_START]);
file.Set(SectionName.c_str(), "dpad", PadMapping[i].dpad);
file.Set(SectionName.c_str(), "dpad_up", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP]);
file.Set(SectionName.c_str(), "dpad_down", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN]);
file.Set(SectionName.c_str(), "dpad_left", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT]);
file.Set(SectionName.c_str(), "dpad_right", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT]);
file.Set(SectionName.c_str(), "main_x", PadMapping[i].axis[InputCommon::CTL_MAIN_X]);
file.Set(SectionName.c_str(), "main_y", PadMapping[i].axis[InputCommon::CTL_MAIN_Y]);
file.Set(SectionName.c_str(), "sub_x", PadMapping[i].axis[InputCommon::CTL_SUB_X]);
file.Set(SectionName.c_str(), "sub_y", PadMapping[i].axis[InputCommon::CTL_SUB_Y]);
file.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone);
file.Set(SectionName.c_str(), "halfpress", PadMapping[i].halfpress);
file.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype);
file.Set(SectionName.c_str(), "TriggerType", PadMapping[i].triggertype);
file.Set(SectionName.c_str(), "eventnum", PadMapping[i].eventnum);
file.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal);
file.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle);
// ======================================
// Debugging
//if(m_frame) m_frame->LogMsg("Saved: %s %i\n", SectionName.c_str(), PadMapping[i].triggertype);
}
Console::Print("%i: Save: %i\n", 0, PadMapping[0].halfpress);
file.Save("nJoy.ini");
}
// Load settings from file
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Config::Load(bool ChangePad, bool ChangeSaveByID)
{
// If there are no good pads don't load
if (NumGoodPads == 0) return;
// Load file
IniFile file;
file.Load("nJoy.ini");
bool Tmp; // Tmp storage
// ==================================================================
// Global settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
file.Get("General", "ShowAdvanced", &g_Config.bShowAdvanced, false);
file.Get("General", "CheckForFocus", &g_Config.bCheckFocus, false);
file.Get("General", "NoTriggerFilter", &g_Config.bNoTriggerFilter, false);
#ifdef RERECORDING
file.Get("General", "Recording", &g_Config.bRecording, false);
file.Get("General", "Playback", &g_Config.bPlayback, false);
#endif
if(!ChangeSaveByID)
{
file.Get("General", "SaveByID", &Tmp, false); g_Config.bSaveByID = Tmp;
}
// =============
for (int i = 0; i < 4; i++)
{
std::string SectionName = StringFromFormat("PAD%i", i+1);
// Don't update this when we are loading settings from the ConfigBox
if(!ChangePad)
{
file.Get(SectionName.c_str(), "joy_id", &PadMapping[i].ID, 0);
file.Get(SectionName.c_str(), "enabled", &PadMapping[i].enabled, 1);
}
// ==================================================================
// Joypad or slot specific settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Current joypad device ID: PadMapping[i].ID
// Current joypad name: joyinfo[PadMapping[i].ID].Name
if(g_Config.bSaveByID)
{
/* Prevent a crash from illegal access to joyinfo that will only have values for
the current amount of connected pads */
if(PadMapping[i].ID >= joyinfo.size()) continue;
// Create a section name
SectionName = joyinfo[PadMapping[i].ID].Name;
}
file.Get(SectionName.c_str(), "l_shoulder", &PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER], 4);
file.Get(SectionName.c_str(), "r_shoulder", &PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER], 5);
file.Get(SectionName.c_str(), "a_button", &PadMapping[i].buttons[InputCommon::CTL_A_BUTTON], 0);
file.Get(SectionName.c_str(), "b_button", &PadMapping[i].buttons[InputCommon::CTL_B_BUTTON], 1);
file.Get(SectionName.c_str(), "x_button", &PadMapping[i].buttons[InputCommon::CTL_X_BUTTON], 3);
file.Get(SectionName.c_str(), "y_button", &PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON], 2);
file.Get(SectionName.c_str(), "z_trigger", &PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER], 7);
file.Get(SectionName.c_str(), "start_button", &PadMapping[i].buttons[InputCommon::CTL_START], 9);
file.Get(SectionName.c_str(), "dpad", &PadMapping[i].dpad, 0);
file.Get(SectionName.c_str(), "dpad_up", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP], 0);
file.Get(SectionName.c_str(), "dpad_down", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN], 0);
file.Get(SectionName.c_str(), "dpad_left", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT], 0);
file.Get(SectionName.c_str(), "dpad_right", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT], 0);
file.Get(SectionName.c_str(), "main_x", &PadMapping[i].axis[InputCommon::CTL_MAIN_X], 0);
file.Get(SectionName.c_str(), "main_y", &PadMapping[i].axis[InputCommon::CTL_MAIN_Y], 1);
file.Get(SectionName.c_str(), "sub_x", &PadMapping[i].axis[InputCommon::CTL_SUB_X], 2);
file.Get(SectionName.c_str(), "sub_y", &PadMapping[i].axis[InputCommon::CTL_SUB_Y], 3);
file.Get(SectionName.c_str(), "deadzone", &PadMapping[i].deadzone, 9);
file.Get(SectionName.c_str(), "halfpress", &PadMapping[i].halfpress, -1);
file.Get(SectionName.c_str(), "controllertype", &PadMapping[i].controllertype, 0);
file.Get(SectionName.c_str(), "TriggerType", &PadMapping[i].triggertype, 0);
file.Get(SectionName.c_str(), "eventnum", &PadMapping[i].eventnum, 0);
file.Get(SectionName.c_str(), "Diagonal", &PadMapping[i].SDiagonal, "100%");
file.Get(SectionName.c_str(), "SquareToCircle", &Tmp, false); PadMapping[i].bSquareToCircle = Tmp;
// =============================
// Debugging
//if(m_frame) m_frame->LogMsg("%i: Enabled: %i\n", i, PadMapping[i].buttons[CTL_X_BUTTON]);
}
Console::Print("%i: Load: %i\n", 0, PadMapping[0].halfpress);
}
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
#include "Common.h"
Config g_Config;
#if defined(HAVE_WX) && HAVE_WX
extern ConfigBox* m_frame;
#endif
//////////////////////////////////
// Run when created
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Config::Config()
{
// Clear the memory
//memset(this, 0, sizeof(Config));
}
// Enable output log
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void DEBUG_INIT()
{
if (pFile)
return;
#ifdef _WIN32
char dateStr [9];
_strdate( dateStr);
char timeStr [9];
_strtime( timeStr );
#endif
pFile = fopen ("nJoy-debug.txt","wt");
fprintf(pFile, "nJoy v"INPUT_VERSION" Debug\n");
#ifdef _WIN32
fprintf(pFile, "Date: %s\nTime: %s\n", dateStr, timeStr);
#endif
fprintf(pFile, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\n");
}
// Disable output log
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void DEBUG_QUIT()
{
if (!pFile)
return;
#ifdef _WIN32
char timeStr [9];
_strtime(timeStr);
fprintf(pFile, "_______________\n");
fprintf(pFile, "Time: %s", timeStr);
#endif
fclose(pFile);
}
/////////////////////////////////////////////////////////////////////////////////////
// Save settings to file
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Config::Save(int Slot)
{
// If there are no good pads don't save
if (NumGoodPads == 0) return;
// Load ini file
IniFile file;
file.Load("nJoy.ini");
// ==================================================================
// Global settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
file.Set("General", "ShowAdvanced", g_Config.bShowAdvanced);
file.Set("General", "SaveByID", g_Config.bSaveByID);
file.Set("General", "CheckForFocus", g_Config.bCheckFocus);
file.Set("General", "NoTriggerFilter", g_Config.bNoTriggerFilter);
#ifdef RERECORDING
file.Set("General", "Recording", g_Config.bRecording);
file.Set("General", "Playback", g_Config.bPlayback);
#endif
// ========================
for (int i = 0; i < 4; i++)
{
// Should we save this slot?
if (Slot != -1 && Slot != i) continue;
// ==================================================================
// Slot specific settings only
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string SectionName = StringFromFormat("PAD%i", i+1);
file.Set(SectionName.c_str(), "enabled", PadMapping[i].enabled);
// Save the physical device ID
file.Set(SectionName.c_str(), "joy_id", PadMapping[i].ID);
// ===================
// ==================================================================
// Joypad or slot specific settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Current joypad device ID: PadMapping[i].ID
// Current joypad name: joyinfo[PadMapping[i].ID].Name
if(g_Config.bSaveByID)
{
/* Save joypad specific settings. Check for "PadMapping[i].ID < SDL_NumJoysticks()" to
avoid reading a joyinfo that does't exist */
if(PadMapping[i].ID >= joyinfo.size()) continue;
// Create a new section name after the joypad name
SectionName = joyinfo[PadMapping[i].ID].Name;
}
file.Set(SectionName.c_str(), "l_shoulder", PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER]);
file.Set(SectionName.c_str(), "r_shoulder", PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER]);
file.Set(SectionName.c_str(), "a_button", PadMapping[i].buttons[InputCommon::CTL_A_BUTTON]);
file.Set(SectionName.c_str(), "b_button", PadMapping[i].buttons[InputCommon::CTL_B_BUTTON]);
file.Set(SectionName.c_str(), "x_button", PadMapping[i].buttons[InputCommon::CTL_X_BUTTON]);
file.Set(SectionName.c_str(), "y_button", PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON]);
file.Set(SectionName.c_str(), "z_trigger", PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER]);
file.Set(SectionName.c_str(), "start_button", PadMapping[i].buttons[InputCommon::CTL_START]);
file.Set(SectionName.c_str(), "dpad", PadMapping[i].dpad);
file.Set(SectionName.c_str(), "dpad_up", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP]);
file.Set(SectionName.c_str(), "dpad_down", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN]);
file.Set(SectionName.c_str(), "dpad_left", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT]);
file.Set(SectionName.c_str(), "dpad_right", PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT]);
file.Set(SectionName.c_str(), "main_x", PadMapping[i].axis[InputCommon::CTL_MAIN_X]);
file.Set(SectionName.c_str(), "main_y", PadMapping[i].axis[InputCommon::CTL_MAIN_Y]);
file.Set(SectionName.c_str(), "sub_x", PadMapping[i].axis[InputCommon::CTL_SUB_X]);
file.Set(SectionName.c_str(), "sub_y", PadMapping[i].axis[InputCommon::CTL_SUB_Y]);
file.Set(SectionName.c_str(), "deadzone", PadMapping[i].deadzone);
file.Set(SectionName.c_str(), "halfpress", PadMapping[i].halfpress);
file.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype);
file.Set(SectionName.c_str(), "TriggerType", PadMapping[i].triggertype);
file.Set(SectionName.c_str(), "eventnum", PadMapping[i].eventnum);
file.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal);
file.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle);
// ======================================
// Debugging
//if(m_frame) m_frame->LogMsg("Saved: %s %i\n", SectionName.c_str(), PadMapping[i].triggertype);
}
Console::Print("%i: Save: %i\n", 0, PadMapping[0].halfpress);
file.Save("nJoy.ini");
}
// Load settings from file
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Config::Load(bool ChangePad, bool ChangeSaveByID)
{
// If there are no good pads don't load
if (NumGoodPads == 0) return;
// Load file
IniFile file;
file.Load("nJoy.ini");
bool Tmp; // Tmp storage
// ==================================================================
// Global settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
file.Get("General", "ShowAdvanced", &g_Config.bShowAdvanced, false);
file.Get("General", "CheckForFocus", &g_Config.bCheckFocus, false);
file.Get("General", "NoTriggerFilter", &g_Config.bNoTriggerFilter, false);
#ifdef RERECORDING
file.Get("General", "Recording", &g_Config.bRecording, false);
file.Get("General", "Playback", &g_Config.bPlayback, false);
#endif
if(!ChangeSaveByID)
{
file.Get("General", "SaveByID", &Tmp, false); g_Config.bSaveByID = Tmp;
}
// =============
for (int i = 0; i < 4; i++)
{
std::string SectionName = StringFromFormat("PAD%i", i+1);
// Don't update this when we are loading settings from the ConfigBox
if(!ChangePad)
{
file.Get(SectionName.c_str(), "joy_id", &PadMapping[i].ID, 0);
file.Get(SectionName.c_str(), "enabled", &PadMapping[i].enabled, 1);
}
// ==================================================================
// Joypad or slot specific settings
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Current joypad device ID: PadMapping[i].ID
// Current joypad name: joyinfo[PadMapping[i].ID].Name
if(g_Config.bSaveByID)
{
/* Prevent a crash from illegal access to joyinfo that will only have values for
the current amount of connected pads */
if(PadMapping[i].ID >= joyinfo.size()) continue;
// Create a section name
SectionName = joyinfo[PadMapping[i].ID].Name;
}
file.Get(SectionName.c_str(), "l_shoulder", &PadMapping[i].buttons[InputCommon::CTL_L_SHOULDER], 4);
file.Get(SectionName.c_str(), "r_shoulder", &PadMapping[i].buttons[InputCommon::CTL_R_SHOULDER], 5);
file.Get(SectionName.c_str(), "a_button", &PadMapping[i].buttons[InputCommon::CTL_A_BUTTON], 0);
file.Get(SectionName.c_str(), "b_button", &PadMapping[i].buttons[InputCommon::CTL_B_BUTTON], 1);
file.Get(SectionName.c_str(), "x_button", &PadMapping[i].buttons[InputCommon::CTL_X_BUTTON], 3);
file.Get(SectionName.c_str(), "y_button", &PadMapping[i].buttons[InputCommon::CTL_Y_BUTTON], 2);
file.Get(SectionName.c_str(), "z_trigger", &PadMapping[i].buttons[InputCommon::CTL_Z_TRIGGER], 7);
file.Get(SectionName.c_str(), "start_button", &PadMapping[i].buttons[InputCommon::CTL_START], 9);
file.Get(SectionName.c_str(), "dpad", &PadMapping[i].dpad, 0);
file.Get(SectionName.c_str(), "dpad_up", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_UP], 0);
file.Get(SectionName.c_str(), "dpad_down", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_DOWN], 0);
file.Get(SectionName.c_str(), "dpad_left", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_LEFT], 0);
file.Get(SectionName.c_str(), "dpad_right", &PadMapping[i].dpad2[InputCommon::CTL_D_PAD_RIGHT], 0);
file.Get(SectionName.c_str(), "main_x", &PadMapping[i].axis[InputCommon::CTL_MAIN_X], 0);
file.Get(SectionName.c_str(), "main_y", &PadMapping[i].axis[InputCommon::CTL_MAIN_Y], 1);
file.Get(SectionName.c_str(), "sub_x", &PadMapping[i].axis[InputCommon::CTL_SUB_X], 2);
file.Get(SectionName.c_str(), "sub_y", &PadMapping[i].axis[InputCommon::CTL_SUB_Y], 3);
file.Get(SectionName.c_str(), "deadzone", &PadMapping[i].deadzone, 9);
file.Get(SectionName.c_str(), "halfpress", &PadMapping[i].halfpress, -1);
file.Get(SectionName.c_str(), "controllertype", &PadMapping[i].controllertype, 0);
file.Get(SectionName.c_str(), "TriggerType", &PadMapping[i].triggertype, 0);
file.Get(SectionName.c_str(), "eventnum", &PadMapping[i].eventnum, 0);
file.Get(SectionName.c_str(), "Diagonal", &PadMapping[i].SDiagonal, "100%");
file.Get(SectionName.c_str(), "SquareToCircle", &Tmp, false); PadMapping[i].bSquareToCircle = Tmp;
// =============================
// Debugging
//if(m_frame) m_frame->LogMsg("%i: Enabled: %i\n", i, PadMapping[i].buttons[CTL_X_BUTTON]);
}
Console::Print("%i: Load: %i\n", 0, PadMapping[0].halfpress);
}

View File

@ -1,384 +1,384 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "ConfigBox.h"
#include "../nJoy.h"
#include "Images/controller.xpm"
extern bool g_EmulatorRunning;
////////////////////////
/* If we don't use this hack m_MainSizer->GetMinSize().GetWidth() will not change
when we enable and disable bShowAdvanced */
bool StrangeHack = true;
// Set PAD status
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::PadGetStatus()
{
/* Return if it's not detected. The ID should never be less than zero here, it can only be that
because of a manual ini file change, but we make that check anway. */
if(PadMapping[notebookpage].ID < 0 || PadMapping[notebookpage].ID >= SDL_NumJoysticks())
{
m_TStatusIn[notebookpage]->SetLabel(wxT("Not connected"));
m_TStatusOut[notebookpage]->SetLabel(wxT("Not connected"));
m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not connected"));
return;
}
// Return if it's not enabled
if (!PadMapping[notebookpage].enabled)
{
m_TStatusIn[notebookpage]->SetLabel(wxT("Not enabled"));
m_TStatusOut[notebookpage]->SetLabel(wxT("Not enabled"));
m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not enabled"));
return;
}
// Get physical device status
int PhysicalDevice = PadMapping[notebookpage].ID;
int TriggerType = PadMapping[notebookpage].triggertype;
//////////////////////////////////////
// Analog stick
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Set Deadzones perhaps out of function
//int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
//int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
// Get original values
int main_x = PadState[notebookpage].axis[InputCommon::CTL_MAIN_X];
int main_y = PadState[notebookpage].axis[InputCommon::CTL_MAIN_Y];
//int sub_x = (PadState[_numPAD].axis[CTL_SUB_X];
//int sub_y = -(PadState[_numPAD].axis[CTL_SUB_Y];
// Get adjusted values
int main_x_after = main_x, main_y_after = main_y;
if(PadMapping[notebookpage].bSquareToCircle)
{
std::vector<int> main_xy = InputCommon::Square2Circle(main_x, main_y, notebookpage, PadMapping[notebookpage].SDiagonal);
main_x_after = main_xy.at(0);
main_y_after = main_xy.at(1);
}
//
float f_x = main_x / 32767.0;
float f_y = main_y / 32767.0;
float f_x_aft = main_x_after / 32767.0;
float f_y_aft = main_y_after / 32767.0;
m_TStatusIn[notebookpage]->SetLabel(wxString::Format(
wxT("x:%1.2f y:%1.2f"),
f_x, f_y
));
m_TStatusOut[notebookpage]->SetLabel(wxString::Format(
wxT("x:%1.2f y:%1.2f"),
f_x_aft, f_y_aft
));
// Adjust the values for the plot
int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2; // Border adjustment
main_x = (BoxW_ / 2) + (main_x * BoxW_ / (32767 * 2));
main_y = (BoxH_ / 2) + (main_y * BoxH_ / (32767 * 2));
int main_x_out = (BoxW_ / 2) + (main_x_after * BoxW_ / (32767 * 2));
int main_y_out = (BoxH_ / 2) + (main_y_after * BoxH_ / (32767 * 2));
// Adjust the dot
m_bmpDot[notebookpage]->SetPosition(wxPoint(main_x, main_y));
m_bmpDotOut[notebookpage]->SetPosition(wxPoint(main_x_out, main_y_out));
///////////////////// Analog stick
//////////////////////////////////////
// Triggers
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int TriggerValue = 255;
if (PadState[notebookpage].halfpress) TriggerValue = 100;
// Get the selected keys
long Left, Right;
m_JoyShoulderL[notebookpage]->GetValue().ToLong(&Left);
m_JoyShoulderR[notebookpage]->GetValue().ToLong(&Right);
// Get the trigger values
int TriggerLeft = PadState[notebookpage].axis[InputCommon::CTL_L_SHOULDER];
int TriggerRight = PadState[notebookpage].axis[InputCommon::CTL_R_SHOULDER];
// Convert the triggers values
if (PadMapping[notebookpage].triggertype == InputCommon::CTL_TRIGGER_SDL)
{
TriggerLeft = InputCommon::Pad_Convert(TriggerLeft);
TriggerRight = InputCommon::Pad_Convert(TriggerRight);
}
// If we don't have any axis selected for the shoulder buttons
if(Left < 1000) TriggerLeft = 0;
if(Right < 1000) TriggerRight = 0;
// Get the digital values
if(Left < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_L_SHOULDER]) TriggerLeft = TriggerValue;
if(Right < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_R_SHOULDER]) TriggerRight = TriggerValue;
m_TStatusTriggers[notebookpage]->SetLabel(wxString::Format(
wxT("Left:%03i Right:%03i"),
TriggerLeft, TriggerRight
));
///////////////////// Triggers
}
// Show the current pad status
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string ShowStatus(int VirtualController)
{
// Check if it's enabled
if (!PadMapping[VirtualController].enabled) return StringFromFormat("%i disabled", VirtualController);
// Save the physical device
int PhysicalDevice = PadMapping[VirtualController].ID;
// Make local shortcut
SDL_Joystick *joy = PadState[VirtualController].joy;
// Make shortcuts for all pads
SDL_Joystick *joy0 = PadState[0].joy;
SDL_Joystick *joy1 = PadState[1].joy;
SDL_Joystick *joy2 = PadState[2].joy;
SDL_Joystick *joy3 = PadState[3].joy;
// Temporary storage
std::string StrAxes, StrHats, StrBut;
int value;
// Get status
int Axes = joyinfo[PhysicalDevice].NumAxes;
int Balls = joyinfo[PhysicalDevice].NumBalls;
int Hats = joyinfo[PhysicalDevice].NumHats;
int Buttons = joyinfo[PhysicalDevice].NumButtons;
// Get version
//SDL_version Version;
//SDL_GetVersion(&Version);
// Update the internal values
SDL_JoystickUpdate();
// Go through all axes and read out their values
for(int i = 0; i < Axes; i++)
{
value = SDL_JoystickGetAxis(joy, i);
StrAxes += StringFromFormat(" %i:%06i", i, value);
}
for(int i = 0;i < Hats; i++)
{
value = SDL_JoystickGetHat(joy, i);
StrHats += StringFromFormat(" %i:%i", i, value);
}
for(int i = 0;i < Buttons; i++)
{
value = SDL_JoystickGetButton(joy, i);
StrBut += StringFromFormat(" %i:%i", i+1, value);
}
return StringFromFormat(
//"Version: %i.%i.%i\n"
"All pads:\n"
"Enabled: %i %i %i %i\n"
"ID: %i %i %i %i\n"
"Controllertype: %i %i %i %i\n"
"SquareToCircle: %i %i %i %i\n\n"
#ifdef _WIN32
"Handles: %i %i %i %i\n"
"XInput: %i %i %i\n"
#endif
"This pad:\n"
"Axes: %s\n"
"Hats: %s\n"
"But: %s\n"
"Device: Ax: %i Balls:%i Hats:%i But:%i",
//Version.major, Version.minor, Version.patch,
PadMapping[0].enabled, PadMapping[1].enabled, PadMapping[2].enabled, PadMapping[3].enabled,
PadMapping[0].ID, PadMapping[1].ID, PadMapping[2].ID, PadMapping[3].ID,
PadMapping[0].controllertype, PadMapping[1].controllertype, PadMapping[2].controllertype, PadMapping[3].controllertype,
PadMapping[0].bSquareToCircle, PadMapping[1].bSquareToCircle, PadMapping[2].bSquareToCircle, PadMapping[3].bSquareToCircle,
#ifdef _WIN32
joy0, joy1, joy2, joy3,
//PadState[PadMapping[0].ID].joy, PadState[PadMapping[1].ID].joy, PadState[PadMapping[2].ID].joy, PadState[PadMapping[3].ID].joy,
XInput::IsConnected(0), XInput::GetXI(0, InputCommon::XI_TRIGGER_L), XInput::GetXI(0, InputCommon::XI_TRIGGER_R),
#endif
StrAxes.c_str(), StrHats.c_str(), StrBut.c_str(),
Axes, Balls, Hats, Buttons
);
}
// Populate the advanced tab
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::Update()
{
// Check that Dolphin is in focus, otherwise don't update the pad status
/* If the emulator is running and unpaused GetJoyState() is run a little more often than needed,
but I allow that since it can confuse the user if the input status in the configuration window
is not update when the emulator is paused. */
if (g_Config.bCheckFocus || IsFocus()) // && !g_EmulatorRunning)
{
for (int i = 0; i < joyinfo.size(); i++)
InputCommon::GetJoyState(PadState[i], PadMapping[i], i, joyinfo[PadMapping[i].ID].NumButtons);
}
// Show the current status in a window in the wxPanel
#ifdef SHOW_PAD_STATUS
m_pStatusBar->SetLabel(wxString::Format(
"%s", ShowStatus(notebookpage).c_str()
));
#endif
//LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str());
if(StrangeHack) PadGetStatus();
if(!g_Config.bShowAdvanced) StrangeHack = false; else StrangeHack = true;
}
// Populate the advanced tab
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::CreateAdvancedControls(int i)
{
m_TStatusIn[i] = new wxStaticText(m_Controller[i], IDT_STATUS_IN, wxT("In"));
m_TStatusOut[i] = new wxStaticText(m_Controller[i], IDT_STATUS_OUT, wxT("Out"));
m_gStatusIn[i] = new wxStaticBoxSizer( wxHORIZONTAL, m_Controller[i], wxT("Main-stick (In) (Out)"));
m_pInStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize);
m_bmpSquare[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSBMP1 + i, CreateBitmap(),
//wxPoint(4, 15), wxSize(70,70));
//wxPoint(4, 20), wxDefaultSize);
wxDefaultPosition, wxDefaultSize);
m_bmpDot[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(),
wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
m_pOutStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize);
m_bmpSquareOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSBMP1 + i, CreateBitmap(),
//wxPoint(4, 15), wxSize(70,70));
//wxPoint(4, 20), wxDefaultSize);
wxDefaultPosition, wxDefaultSize);
m_bmpDotOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(),
wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
/////////////////////////////////////////////////////////////////////////////////////
// Rerecording
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#ifdef RERECORDING
// Create controls
m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording"));
m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input"));
m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input"));
m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize);
// Tool tips
m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game"));
m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir"));
m_BtnSaveRecording[i]->SetToolTip(wxT(
"This will save the current recording to pad-record.bin. Your recording will\n"
"also be automatically saved every 60 * 10 frames. And when you shut down the\n"
"game."));
// Sizers
m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1);
// Only enable these options for pad 0
m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true);
m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true);
m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true);
// Don't allow saving when we are not recording
m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && g_Config.bRecording);
//sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1);
// Set values
//m_CheckRecording[0]->SetValue(g_Config.bRecording);
//m_CheckPlayback[0]->SetValue(g_Config.bPlayback);
//Console::Print("m_CheckRecording: %i\n", g_Config.bRecording, g_Config.bPlayback);
#endif
//////////////////////////////////////
}
wxBitmap ConfigBox::CreateBitmap() // Create box
{
BoxW = 70, BoxH = 70;
wxBitmap bitmap(BoxW, BoxH);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
//wxBrush LightBlueBrush(_T("#0383f0"));
//wxPen LightBluePen(_T("#80c5fd"));
//wxPen LightGrayPen(_T("#909090"));
wxPen LightBluePen(_T("#7f9db9")); // Windows XP color
dc.SetPen(LightBluePen);
dc.SetBrush(*wxWHITE_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, BoxW, BoxH);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
wxBitmap ConfigBox::CreateBitmapDot() // Create dot
{
int w = 2, h = 2;
wxBitmap bitmap(w, h);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
//wxBrush RedBrush(_T("#0383f0"));
//wxPen RedPen(_T("#80c5fd"));
//wxPen LightGrayPen(_T("#909090"));
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, w, h);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "ConfigBox.h"
#include "../nJoy.h"
#include "Images/controller.xpm"
extern bool g_EmulatorRunning;
////////////////////////
/* If we don't use this hack m_MainSizer->GetMinSize().GetWidth() will not change
when we enable and disable bShowAdvanced */
bool StrangeHack = true;
// Set PAD status
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::PadGetStatus()
{
/* Return if it's not detected. The ID should never be less than zero here, it can only be that
because of a manual ini file change, but we make that check anway. */
if(PadMapping[notebookpage].ID < 0 || PadMapping[notebookpage].ID >= SDL_NumJoysticks())
{
m_TStatusIn[notebookpage]->SetLabel(wxT("Not connected"));
m_TStatusOut[notebookpage]->SetLabel(wxT("Not connected"));
m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not connected"));
return;
}
// Return if it's not enabled
if (!PadMapping[notebookpage].enabled)
{
m_TStatusIn[notebookpage]->SetLabel(wxT("Not enabled"));
m_TStatusOut[notebookpage]->SetLabel(wxT("Not enabled"));
m_TStatusTriggers[notebookpage]->SetLabel(wxT("Not enabled"));
return;
}
// Get physical device status
int PhysicalDevice = PadMapping[notebookpage].ID;
int TriggerType = PadMapping[notebookpage].triggertype;
//////////////////////////////////////
// Analog stick
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Set Deadzones perhaps out of function
//int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
//int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
// Get original values
int main_x = PadState[notebookpage].axis[InputCommon::CTL_MAIN_X];
int main_y = PadState[notebookpage].axis[InputCommon::CTL_MAIN_Y];
//int sub_x = (PadState[_numPAD].axis[CTL_SUB_X];
//int sub_y = -(PadState[_numPAD].axis[CTL_SUB_Y];
// Get adjusted values
int main_x_after = main_x, main_y_after = main_y;
if(PadMapping[notebookpage].bSquareToCircle)
{
std::vector<int> main_xy = InputCommon::Square2Circle(main_x, main_y, notebookpage, PadMapping[notebookpage].SDiagonal);
main_x_after = main_xy.at(0);
main_y_after = main_xy.at(1);
}
//
float f_x = main_x / 32767.0;
float f_y = main_y / 32767.0;
float f_x_aft = main_x_after / 32767.0;
float f_y_aft = main_y_after / 32767.0;
m_TStatusIn[notebookpage]->SetLabel(wxString::Format(
wxT("x:%1.2f y:%1.2f"),
f_x, f_y
));
m_TStatusOut[notebookpage]->SetLabel(wxString::Format(
wxT("x:%1.2f y:%1.2f"),
f_x_aft, f_y_aft
));
// Adjust the values for the plot
int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2; // Border adjustment
main_x = (BoxW_ / 2) + (main_x * BoxW_ / (32767 * 2));
main_y = (BoxH_ / 2) + (main_y * BoxH_ / (32767 * 2));
int main_x_out = (BoxW_ / 2) + (main_x_after * BoxW_ / (32767 * 2));
int main_y_out = (BoxH_ / 2) + (main_y_after * BoxH_ / (32767 * 2));
// Adjust the dot
m_bmpDot[notebookpage]->SetPosition(wxPoint(main_x, main_y));
m_bmpDotOut[notebookpage]->SetPosition(wxPoint(main_x_out, main_y_out));
///////////////////// Analog stick
//////////////////////////////////////
// Triggers
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int TriggerValue = 255;
if (PadState[notebookpage].halfpress) TriggerValue = 100;
// Get the selected keys
long Left, Right;
m_JoyShoulderL[notebookpage]->GetValue().ToLong(&Left);
m_JoyShoulderR[notebookpage]->GetValue().ToLong(&Right);
// Get the trigger values
int TriggerLeft = PadState[notebookpage].axis[InputCommon::CTL_L_SHOULDER];
int TriggerRight = PadState[notebookpage].axis[InputCommon::CTL_R_SHOULDER];
// Convert the triggers values
if (PadMapping[notebookpage].triggertype == InputCommon::CTL_TRIGGER_SDL)
{
TriggerLeft = InputCommon::Pad_Convert(TriggerLeft);
TriggerRight = InputCommon::Pad_Convert(TriggerRight);
}
// If we don't have any axis selected for the shoulder buttons
if(Left < 1000) TriggerLeft = 0;
if(Right < 1000) TriggerRight = 0;
// Get the digital values
if(Left < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_L_SHOULDER]) TriggerLeft = TriggerValue;
if(Right < 1000 && PadState[notebookpage].buttons[InputCommon::CTL_R_SHOULDER]) TriggerRight = TriggerValue;
m_TStatusTriggers[notebookpage]->SetLabel(wxString::Format(
wxT("Left:%03i Right:%03i"),
TriggerLeft, TriggerRight
));
///////////////////// Triggers
}
// Show the current pad status
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string ShowStatus(int VirtualController)
{
// Check if it's enabled
if (!PadMapping[VirtualController].enabled) return StringFromFormat("%i disabled", VirtualController);
// Save the physical device
int PhysicalDevice = PadMapping[VirtualController].ID;
// Make local shortcut
SDL_Joystick *joy = PadState[VirtualController].joy;
// Make shortcuts for all pads
SDL_Joystick *joy0 = PadState[0].joy;
SDL_Joystick *joy1 = PadState[1].joy;
SDL_Joystick *joy2 = PadState[2].joy;
SDL_Joystick *joy3 = PadState[3].joy;
// Temporary storage
std::string StrAxes, StrHats, StrBut;
int value;
// Get status
int Axes = joyinfo[PhysicalDevice].NumAxes;
int Balls = joyinfo[PhysicalDevice].NumBalls;
int Hats = joyinfo[PhysicalDevice].NumHats;
int Buttons = joyinfo[PhysicalDevice].NumButtons;
// Get version
//SDL_version Version;
//SDL_GetVersion(&Version);
// Update the internal values
SDL_JoystickUpdate();
// Go through all axes and read out their values
for(int i = 0; i < Axes; i++)
{
value = SDL_JoystickGetAxis(joy, i);
StrAxes += StringFromFormat(" %i:%06i", i, value);
}
for(int i = 0;i < Hats; i++)
{
value = SDL_JoystickGetHat(joy, i);
StrHats += StringFromFormat(" %i:%i", i, value);
}
for(int i = 0;i < Buttons; i++)
{
value = SDL_JoystickGetButton(joy, i);
StrBut += StringFromFormat(" %i:%i", i+1, value);
}
return StringFromFormat(
//"Version: %i.%i.%i\n"
"All pads:\n"
"Enabled: %i %i %i %i\n"
"ID: %i %i %i %i\n"
"Controllertype: %i %i %i %i\n"
"SquareToCircle: %i %i %i %i\n\n"
#ifdef _WIN32
"Handles: %i %i %i %i\n"
"XInput: %i %i %i\n"
#endif
"This pad:\n"
"Axes: %s\n"
"Hats: %s\n"
"But: %s\n"
"Device: Ax: %i Balls:%i Hats:%i But:%i",
//Version.major, Version.minor, Version.patch,
PadMapping[0].enabled, PadMapping[1].enabled, PadMapping[2].enabled, PadMapping[3].enabled,
PadMapping[0].ID, PadMapping[1].ID, PadMapping[2].ID, PadMapping[3].ID,
PadMapping[0].controllertype, PadMapping[1].controllertype, PadMapping[2].controllertype, PadMapping[3].controllertype,
PadMapping[0].bSquareToCircle, PadMapping[1].bSquareToCircle, PadMapping[2].bSquareToCircle, PadMapping[3].bSquareToCircle,
#ifdef _WIN32
joy0, joy1, joy2, joy3,
//PadState[PadMapping[0].ID].joy, PadState[PadMapping[1].ID].joy, PadState[PadMapping[2].ID].joy, PadState[PadMapping[3].ID].joy,
XInput::IsConnected(0), XInput::GetXI(0, InputCommon::XI_TRIGGER_L), XInput::GetXI(0, InputCommon::XI_TRIGGER_R),
#endif
StrAxes.c_str(), StrHats.c_str(), StrBut.c_str(),
Axes, Balls, Hats, Buttons
);
}
// Populate the advanced tab
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::Update()
{
// Check that Dolphin is in focus, otherwise don't update the pad status
/* If the emulator is running and unpaused GetJoyState() is run a little more often than needed,
but I allow that since it can confuse the user if the input status in the configuration window
is not update when the emulator is paused. */
if (g_Config.bCheckFocus || IsFocus()) // && !g_EmulatorRunning)
{
for (int i = 0; i < joyinfo.size(); i++)
InputCommon::GetJoyState(PadState[i], PadMapping[i], i, joyinfo[PadMapping[i].ID].NumButtons);
}
// Show the current status in a window in the wxPanel
#ifdef SHOW_PAD_STATUS
m_pStatusBar->SetLabel(wxString::Format(
"%s", ShowStatus(notebookpage).c_str()
));
#endif
//LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str());
if(StrangeHack) PadGetStatus();
if(!g_Config.bShowAdvanced) StrangeHack = false; else StrangeHack = true;
}
// Populate the advanced tab
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::CreateAdvancedControls(int i)
{
m_TStatusIn[i] = new wxStaticText(m_Controller[i], IDT_STATUS_IN, wxT("In"));
m_TStatusOut[i] = new wxStaticText(m_Controller[i], IDT_STATUS_OUT, wxT("Out"));
m_gStatusIn[i] = new wxStaticBoxSizer( wxHORIZONTAL, m_Controller[i], wxT("Main-stick (In) (Out)"));
m_pInStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize);
m_bmpSquare[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSBMP1 + i, CreateBitmap(),
//wxPoint(4, 15), wxSize(70,70));
//wxPoint(4, 20), wxDefaultSize);
wxDefaultPosition, wxDefaultSize);
m_bmpDot[i] = new wxStaticBitmap(m_pInStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(),
wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
m_pOutStatus[i] = new wxPanel(m_Controller[i], ID_INSTATUS1 + i, wxDefaultPosition, wxDefaultSize);
m_bmpSquareOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSBMP1 + i, CreateBitmap(),
//wxPoint(4, 15), wxSize(70,70));
//wxPoint(4, 20), wxDefaultSize);
wxDefaultPosition, wxDefaultSize);
m_bmpDotOut[i] = new wxStaticBitmap(m_pOutStatus[i], ID_STATUSDOTBMP1 + i, CreateBitmapDot(),
wxPoint(BoxW / 2, BoxH / 2), wxDefaultSize);
/////////////////////////////////////////////////////////////////////////////////////
// Rerecording
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#ifdef RERECORDING
// Create controls
m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording"));
m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input"));
m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input"));
m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize);
// Tool tips
m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game"));
m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir"));
m_BtnSaveRecording[i]->SetToolTip(wxT(
"This will save the current recording to pad-record.bin. Your recording will\n"
"also be automatically saved every 60 * 10 frames. And when you shut down the\n"
"game."));
// Sizers
m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1);
// Only enable these options for pad 0
m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true);
m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true);
m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true);
// Don't allow saving when we are not recording
m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && g_Config.bRecording);
//sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1);
// Set values
//m_CheckRecording[0]->SetValue(g_Config.bRecording);
//m_CheckPlayback[0]->SetValue(g_Config.bPlayback);
//Console::Print("m_CheckRecording: %i\n", g_Config.bRecording, g_Config.bPlayback);
#endif
//////////////////////////////////////
}
wxBitmap ConfigBox::CreateBitmap() // Create box
{
BoxW = 70, BoxH = 70;
wxBitmap bitmap(BoxW, BoxH);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
//wxBrush LightBlueBrush(_T("#0383f0"));
//wxPen LightBluePen(_T("#80c5fd"));
//wxPen LightGrayPen(_T("#909090"));
wxPen LightBluePen(_T("#7f9db9")); // Windows XP color
dc.SetPen(LightBluePen);
dc.SetBrush(*wxWHITE_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, BoxW, BoxH);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
wxBitmap ConfigBox::CreateBitmapDot() // Create dot
{
int w = 2, h = 2;
wxBitmap bitmap(w, h);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
//wxBrush RedBrush(_T("#0383f0"));
//wxPen RedPen(_T("#80c5fd"));
//wxPen LightGrayPen(_T("#909090"));
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, w, h);
dc.SelectObject(wxNullBitmap);
return bitmap;
}

View File

@ -1,434 +1,434 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "math.h" // System
#include "ConfigBox.h" // Local
#include "../nJoy.h"
#include "Images/controller.xpm"
extern bool g_EmulatorRunning;
////////////////////////
// Set dialog items from saved values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::UpdateGUIButtonMapping(int controller)
{
// http://wiki.wxwidgets.org/Converting_everything_to_and_from_wxString
wxString tmp;
// Update selected gamepad
m_Joyname[controller]->SetSelection(PadMapping[controller].ID);
// Update the enabled checkbox
m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false);
tmp << PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER]; m_JoyShoulderL[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER]; m_JoyShoulderR[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON]; m_JoyButtonA[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON]; m_JoyButtonB[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON]; m_JoyButtonX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON]; m_JoyButtonY[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER]; m_JoyButtonZ[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_START]; m_JoyButtonStart[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].halfpress; m_JoyButtonHalfpress[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_X]; m_JoyAnalogMainX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_Y]; m_JoyAnalogMainY[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_X]; m_JoyAnalogSubX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_Y]; m_JoyAnalogSubY[controller]->SetValue(tmp); tmp.clear();
// Update the deadzone and controller type controls
m_ControlType[controller]->SetSelection(PadMapping[controller].controllertype);
m_TriggerType[controller]->SetSelection(PadMapping[controller].triggertype);
m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone);
m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str()));
m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle);
m_AdvancedMapFilter[controller]->SetValue(g_Config.bNoTriggerFilter);
#ifdef RERECORDING
m_CheckRecording[controller]->SetValue(g_Config.bRecording);
m_CheckPlayback[controller]->SetValue(g_Config.bPlayback);
#endif
//LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype);
// Update D-Pad
if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT)
{
tmp << PadMapping[controller].dpad; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear();
}
else
{
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP]; m_JoyDpadUp[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN]; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT]; m_JoyDpadLeft[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT]; m_JoyDpadRight[controller]->SetValue(tmp); tmp.clear();
}
// Replace "-1" with "" in the GUI controls
//if(ControlsCreated) ToBlank();
}
/* Populate the PadMapping array with the dialog items settings (for example
selected joystick, enabled or disabled status and so on) */
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot)
{
// Temporary storage
wxString tmp;
long value;
// Save from or to the same or different slots
if (FromSlot == -1) FromSlot = controller;
// Replace "" with "-1" in the GUI controls
ToBlank(false);
// Set enabled or disable status and other settings
if(!DontChangeId) PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection();
if(FromSlot == controller) PadMapping[controller].enabled = m_Joyattach[FromSlot]->GetValue(); // Only enable one
PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection();
PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection();
PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection();
PadMapping[controller].SDiagonal = m_CoBDiagonal[FromSlot]->GetLabel().mb_str();
PadMapping[controller].bSquareToCircle = m_CBS_to_C[FromSlot]->IsChecked();
// The analog buttons
m_JoyAnalogMainX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_X] = value; tmp.clear();
m_JoyAnalogMainY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_Y] = value; tmp.clear();
m_JoyAnalogSubX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_X] = value; tmp.clear();
m_JoyAnalogSubY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_Y] = value; tmp.clear();
// The shoulder buttons
m_JoyShoulderL[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER] = value;
m_JoyShoulderR[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER] = value;
// The digital buttons
m_JoyButtonA[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON] = value; tmp.clear();
m_JoyButtonB[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON] = value; tmp.clear();
m_JoyButtonX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON] = value; tmp.clear();
m_JoyButtonY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON] = value; tmp.clear();
m_JoyButtonZ[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER] = value; tmp.clear();
m_JoyButtonStart[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_START] = value; tmp.clear();
//LogMsg("PadMapping[%i].triggertype = %i, m_TriggerType[%i]->GetSelection() = %i\n",
// controller, PadMapping[controller].triggertype, FromSlot, m_TriggerType[FromSlot]->GetSelection());
// The halfpress button
m_JoyButtonHalfpress[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].halfpress = value; tmp.clear();
// The digital pad
if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT)
{
m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad = value; tmp.clear();
}
else
{
m_JoyDpadUp[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP] = value; tmp.clear();
m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN] = value; tmp.clear();
m_JoyDpadLeft[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT] = value; tmp.clear();
m_JoyDpadRight[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT] = value; tmp.clear();
}
// Replace "-1" with ""
ToBlank();
}
// Update the textbox for the buttons
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::SetButtonText(int id, char text[128], int Page)
{
// Set controller value
int controller;
if (Page == -1) controller = notebookpage; else controller = Page;
switch(id)
{
case IDB_DPAD_RIGHT: m_JoyDpadRight[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_UP: m_JoyDpadUp[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_DOWN: m_JoyDpadDown[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_LEFT: m_JoyDpadLeft[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_MAIN_X: m_JoyAnalogMainX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_MAIN_Y: m_JoyAnalogMainY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_SUB_X: m_JoyAnalogSubX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_SUB_Y: m_JoyAnalogSubY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_SHOULDER_L: m_JoyShoulderL[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_SHOULDER_R: m_JoyShoulderR[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_A: m_JoyButtonA[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_B: m_JoyButtonB[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_X: m_JoyButtonX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_Y: m_JoyButtonY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_Z: m_JoyButtonZ[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTONSTART: m_JoyButtonStart[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTONHALFPRESS: m_JoyButtonHalfpress[controller]->SetValue(wxString::FromAscii(text)); break;
default: break;
}
}
// Get the text in the textbox for the buttons
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
wxString ConfigBox::GetButtonText(int id, int Page)
{
// Set controller value
int controller;
if (Page == -1) controller = notebookpage; else controller = Page;
switch(id)
{
// D-Pad
case IDB_DPAD_RIGHT: return m_JoyDpadRight[controller]->GetValue();
case IDB_DPAD_UP: return m_JoyDpadUp[controller]->GetValue();
case IDB_DPAD_DOWN: return m_JoyDpadDown[controller]->GetValue();
case IDB_DPAD_LEFT: return m_JoyDpadLeft[controller]->GetValue();
// Analog Stick
case IDB_ANALOG_MAIN_X: return m_JoyAnalogMainX[controller]->GetValue();
case IDB_ANALOG_MAIN_Y: return m_JoyAnalogMainY[controller]->GetValue();
case IDB_ANALOG_SUB_X: return m_JoyAnalogSubX[controller]->GetValue();
case IDB_ANALOG_SUB_Y: return m_JoyAnalogSubY[controller]->GetValue();
// Shoulder Buttons
case IDB_SHOULDER_L: return m_JoyShoulderL[controller]->GetValue();
case IDB_SHOULDER_R: return m_JoyShoulderR[controller]->GetValue();
// Buttons
case IDB_BUTTON_A: return m_JoyButtonA[controller]->GetValue();
case IDB_BUTTON_B: return m_JoyButtonB[controller]->GetValue();
case IDB_BUTTON_X: return m_JoyButtonX[controller]->GetValue();
case IDB_BUTTON_Y: return m_JoyButtonY[controller]->GetValue();
case IDB_BUTTON_Z: return m_JoyButtonZ[controller]->GetValue();
case IDB_BUTTONSTART: return m_JoyButtonStart[controller]->GetValue();
case IDB_BUTTONHALFPRESS: return m_JoyButtonHalfpress[controller]->GetValue();
default: return wxString();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Configure button mapping
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Wait for button press
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a
timer. The downside with the while() or for() loop is that there is no way to stop it if the user
should select to configure another button while we are still in an old loop. What will happen then
is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only
option to wait for the old loop to finish is with a new loop, and that will block the old loop for as
long as it's going on. Therefore a timer is easier to control. */
void ConfigBox::GetButtons(wxCommandEvent& event)
{
DoGetButtons(event.GetId());
}
void ConfigBox::DoGetButtons(int GetId)
{
// =============================================
// Collect the starting values
// ----------------
// Get the current controller
int Controller = notebookpage;
int PadID = PadMapping[Controller].ID;
// Create a shortcut for the pad handle
SDL_Joystick *joy = PadState[Controller].joy;
// Get the number of axes, hats and buttons
int Buttons = SDL_JoystickNumButtons(joy);
int Axes = SDL_JoystickNumAxes(joy);
int Hats = SDL_JoystickNumHats(joy);
Console::Print("PadID: %i Axes: %i\n", PadID, joyinfo[PadID].NumAxes, joyinfo[PadID].joy);
// Get the controller and trigger type
int ControllerType = PadMapping[Controller].controllertype;
int TriggerType = PadMapping[Controller].triggertype;
// Collect the accepted buttons for this slot
bool LeftRight = (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R);
bool Axis = (GetId >= IDB_ANALOG_MAIN_X && GetId <= IDB_SHOULDER_R)
// Don't allow SDL input for the triggers when XInput is selected
&& !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) );
bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT);
bool Button = (GetId >= IDB_BUTTON_A && GetId <= IDB_BUTTONHALFPRESS) // All digital buttons
|| (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) // both shoulder buttons
|| (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT && ControllerType == InputCommon::CTL_DPAD_CUSTOM); // Or the custom hat mode
bool Hat = (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT) // All DPads
&& (PadMapping[Controller].controllertype == InputCommon::CTL_DPAD_HAT); // Not with the hat option defined
bool NoTriggerFilter = g_Config.bNoTriggerFilter;
// Values used in this function
char format[128];
int Seconds = 4; // Seconds to wait for
int TimesPerSecond = 40; // How often to run the check
// Values returned from InputCommon::GetButton()
int value; // Axis value
int type; // Button type
int pressed = 0;
bool Succeed = false;
bool Stop = false; // Stop the timer
// =======================
//Console::Print("Before (%i) Id:%i %i IsRunning:%i\n",
// GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning());
// If the Id has changed or the timer is not running we should start one
if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() )
{
if(m_ButtonMappingTimer->IsRunning())
{
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
// Update the old textbox
SetButtonText(GetButtonWaitingID, "");
}
// Save the button Id
GetButtonWaitingID = GetId;
// Reset the key in case we happen to have an old one
g_Pressed = 0;
// Update the text box
sprintf(format, "[%d]", Seconds);
SetButtonText(GetId, format);
// Start the timer
#if wxUSE_TIMER
m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) );
#endif
}
// ===============================================
// Check for buttons
// ----------------
// If there is a timer but we should not create a new one
else
{
InputCommon::GetButton(
joy, PadID, Buttons, Axes, Hats,
g_Pressed, value, type, pressed, Succeed, Stop,
LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter);
}
// ========================= Check for keys
// ===============================================
// Process results
// ----------------
// Count each time
GetButtonWaitingTimer++;
// This is run every second
if(GetButtonWaitingTimer % TimesPerSecond == 0)
{
// Current time
int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond);
// Update text
sprintf(format, "[%d]", TmpTime);
SetButtonText(GetId, format);
}
// Time's up
if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds )
{
Stop = true;
// Leave a blank mapping
if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1");
}
// If we got a button
if(Succeed)
{
Stop = true;
// Write the number of the pressed button to the text box
sprintf(format, "%d", pressed);
if(g_Config.bSaveByID) SetButtonTextAll(GetId, format); else SetButtonText(GetId, format);
}
// Stop the timer
if(Stop)
{
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
/* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots
controlled by the same device, but several DirectInput instances of different but identical devices may possible
have the same id, I don't know. So we have to do this. The user may also have selected the same device for
several disabled slots. */
if(g_Config.bSaveByID) SaveButtonMappingAll(Controller); else SaveButtonMapping(Controller);
}
// If we got a bad button
if(g_Pressed == -1)
{
// Update text
if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1");
// Notify the user
wxMessageBox(wxString::Format(wxT(
"You selected a key with a to low key code (%i), please"
" select another key with a higher key code."), pressed)
, wxT("Notice"), wxICON_INFORMATION);
}
// ======================== Process results
// Debugging
/*
Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n",
PadMapping[0].halfpress, PadMapping[1].halfpress, PadMapping[2].halfpress, PadMapping[3].halfpress,
m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str()
);*/
}
/////////////////////////////////////////////////////////// Configure button mapping
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "math.h" // System
#include "ConfigBox.h" // Local
#include "../nJoy.h"
#include "Images/controller.xpm"
extern bool g_EmulatorRunning;
////////////////////////
// Set dialog items from saved values
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::UpdateGUIButtonMapping(int controller)
{
// http://wiki.wxwidgets.org/Converting_everything_to_and_from_wxString
wxString tmp;
// Update selected gamepad
m_Joyname[controller]->SetSelection(PadMapping[controller].ID);
// Update the enabled checkbox
m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false);
tmp << PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER]; m_JoyShoulderL[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER]; m_JoyShoulderR[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON]; m_JoyButtonA[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON]; m_JoyButtonB[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON]; m_JoyButtonX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON]; m_JoyButtonY[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER]; m_JoyButtonZ[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].buttons[InputCommon::CTL_START]; m_JoyButtonStart[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].halfpress; m_JoyButtonHalfpress[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_X]; m_JoyAnalogMainX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_MAIN_Y]; m_JoyAnalogMainY[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_X]; m_JoyAnalogSubX[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].axis[InputCommon::CTL_SUB_Y]; m_JoyAnalogSubY[controller]->SetValue(tmp); tmp.clear();
// Update the deadzone and controller type controls
m_ControlType[controller]->SetSelection(PadMapping[controller].controllertype);
m_TriggerType[controller]->SetSelection(PadMapping[controller].triggertype);
m_Deadzone[controller]->SetSelection(PadMapping[controller].deadzone);
m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str()));
m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle);
m_AdvancedMapFilter[controller]->SetValue(g_Config.bNoTriggerFilter);
#ifdef RERECORDING
m_CheckRecording[controller]->SetValue(g_Config.bRecording);
m_CheckPlayback[controller]->SetValue(g_Config.bPlayback);
#endif
//LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype);
// Update D-Pad
if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT)
{
tmp << PadMapping[controller].dpad; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear();
}
else
{
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP]; m_JoyDpadUp[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN]; m_JoyDpadDown[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT]; m_JoyDpadLeft[controller]->SetValue(tmp); tmp.clear();
tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT]; m_JoyDpadRight[controller]->SetValue(tmp); tmp.clear();
}
// Replace "-1" with "" in the GUI controls
//if(ControlsCreated) ToBlank();
}
/* Populate the PadMapping array with the dialog items settings (for example
selected joystick, enabled or disabled status and so on) */
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot)
{
// Temporary storage
wxString tmp;
long value;
// Save from or to the same or different slots
if (FromSlot == -1) FromSlot = controller;
// Replace "" with "-1" in the GUI controls
ToBlank(false);
// Set enabled or disable status and other settings
if(!DontChangeId) PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection();
if(FromSlot == controller) PadMapping[controller].enabled = m_Joyattach[FromSlot]->GetValue(); // Only enable one
PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection();
PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection();
PadMapping[controller].deadzone = m_Deadzone[FromSlot]->GetSelection();
PadMapping[controller].SDiagonal = m_CoBDiagonal[FromSlot]->GetLabel().mb_str();
PadMapping[controller].bSquareToCircle = m_CBS_to_C[FromSlot]->IsChecked();
// The analog buttons
m_JoyAnalogMainX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_X] = value; tmp.clear();
m_JoyAnalogMainY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_MAIN_Y] = value; tmp.clear();
m_JoyAnalogSubX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_X] = value; tmp.clear();
m_JoyAnalogSubY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].axis[InputCommon::CTL_SUB_Y] = value; tmp.clear();
// The shoulder buttons
m_JoyShoulderL[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_L_SHOULDER] = value;
m_JoyShoulderR[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_R_SHOULDER] = value;
// The digital buttons
m_JoyButtonA[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_A_BUTTON] = value; tmp.clear();
m_JoyButtonB[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_B_BUTTON] = value; tmp.clear();
m_JoyButtonX[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_X_BUTTON] = value; tmp.clear();
m_JoyButtonY[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Y_BUTTON] = value; tmp.clear();
m_JoyButtonZ[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_Z_TRIGGER] = value; tmp.clear();
m_JoyButtonStart[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].buttons[InputCommon::CTL_START] = value; tmp.clear();
//LogMsg("PadMapping[%i].triggertype = %i, m_TriggerType[%i]->GetSelection() = %i\n",
// controller, PadMapping[controller].triggertype, FromSlot, m_TriggerType[FromSlot]->GetSelection());
// The halfpress button
m_JoyButtonHalfpress[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].halfpress = value; tmp.clear();
// The digital pad
if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT)
{
m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad = value; tmp.clear();
}
else
{
m_JoyDpadUp[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_UP] = value; tmp.clear();
m_JoyDpadDown[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_DOWN] = value; tmp.clear();
m_JoyDpadLeft[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_LEFT] = value; tmp.clear();
m_JoyDpadRight[FromSlot]->GetValue().ToLong(&value); PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT] = value; tmp.clear();
}
// Replace "-1" with ""
ToBlank();
}
// Update the textbox for the buttons
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void ConfigBox::SetButtonText(int id, char text[128], int Page)
{
// Set controller value
int controller;
if (Page == -1) controller = notebookpage; else controller = Page;
switch(id)
{
case IDB_DPAD_RIGHT: m_JoyDpadRight[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_UP: m_JoyDpadUp[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_DOWN: m_JoyDpadDown[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_DPAD_LEFT: m_JoyDpadLeft[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_MAIN_X: m_JoyAnalogMainX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_MAIN_Y: m_JoyAnalogMainY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_SUB_X: m_JoyAnalogSubX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_ANALOG_SUB_Y: m_JoyAnalogSubY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_SHOULDER_L: m_JoyShoulderL[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_SHOULDER_R: m_JoyShoulderR[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_A: m_JoyButtonA[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_B: m_JoyButtonB[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_X: m_JoyButtonX[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_Y: m_JoyButtonY[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTON_Z: m_JoyButtonZ[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTONSTART: m_JoyButtonStart[controller]->SetValue(wxString::FromAscii(text)); break;
case IDB_BUTTONHALFPRESS: m_JoyButtonHalfpress[controller]->SetValue(wxString::FromAscii(text)); break;
default: break;
}
}
// Get the text in the textbox for the buttons
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
wxString ConfigBox::GetButtonText(int id, int Page)
{
// Set controller value
int controller;
if (Page == -1) controller = notebookpage; else controller = Page;
switch(id)
{
// D-Pad
case IDB_DPAD_RIGHT: return m_JoyDpadRight[controller]->GetValue();
case IDB_DPAD_UP: return m_JoyDpadUp[controller]->GetValue();
case IDB_DPAD_DOWN: return m_JoyDpadDown[controller]->GetValue();
case IDB_DPAD_LEFT: return m_JoyDpadLeft[controller]->GetValue();
// Analog Stick
case IDB_ANALOG_MAIN_X: return m_JoyAnalogMainX[controller]->GetValue();
case IDB_ANALOG_MAIN_Y: return m_JoyAnalogMainY[controller]->GetValue();
case IDB_ANALOG_SUB_X: return m_JoyAnalogSubX[controller]->GetValue();
case IDB_ANALOG_SUB_Y: return m_JoyAnalogSubY[controller]->GetValue();
// Shoulder Buttons
case IDB_SHOULDER_L: return m_JoyShoulderL[controller]->GetValue();
case IDB_SHOULDER_R: return m_JoyShoulderR[controller]->GetValue();
// Buttons
case IDB_BUTTON_A: return m_JoyButtonA[controller]->GetValue();
case IDB_BUTTON_B: return m_JoyButtonB[controller]->GetValue();
case IDB_BUTTON_X: return m_JoyButtonX[controller]->GetValue();
case IDB_BUTTON_Y: return m_JoyButtonY[controller]->GetValue();
case IDB_BUTTON_Z: return m_JoyButtonZ[controller]->GetValue();
case IDB_BUTTONSTART: return m_JoyButtonStart[controller]->GetValue();
case IDB_BUTTONHALFPRESS: return m_JoyButtonHalfpress[controller]->GetValue();
default: return wxString();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Configure button mapping
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Wait for button press
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a
timer. The downside with the while() or for() loop is that there is no way to stop it if the user
should select to configure another button while we are still in an old loop. What will happen then
is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only
option to wait for the old loop to finish is with a new loop, and that will block the old loop for as
long as it's going on. Therefore a timer is easier to control. */
void ConfigBox::GetButtons(wxCommandEvent& event)
{
DoGetButtons(event.GetId());
}
void ConfigBox::DoGetButtons(int GetId)
{
// =============================================
// Collect the starting values
// ----------------
// Get the current controller
int Controller = notebookpage;
int PadID = PadMapping[Controller].ID;
// Create a shortcut for the pad handle
SDL_Joystick *joy = PadState[Controller].joy;
// Get the number of axes, hats and buttons
int Buttons = SDL_JoystickNumButtons(joy);
int Axes = SDL_JoystickNumAxes(joy);
int Hats = SDL_JoystickNumHats(joy);
Console::Print("PadID: %i Axes: %i\n", PadID, joyinfo[PadID].NumAxes, joyinfo[PadID].joy);
// Get the controller and trigger type
int ControllerType = PadMapping[Controller].controllertype;
int TriggerType = PadMapping[Controller].triggertype;
// Collect the accepted buttons for this slot
bool LeftRight = (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R);
bool Axis = (GetId >= IDB_ANALOG_MAIN_X && GetId <= IDB_SHOULDER_R)
// Don't allow SDL input for the triggers when XInput is selected
&& !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) );
bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT);
bool Button = (GetId >= IDB_BUTTON_A && GetId <= IDB_BUTTONHALFPRESS) // All digital buttons
|| (GetId == IDB_SHOULDER_L || GetId == IDB_SHOULDER_R) // both shoulder buttons
|| (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT && ControllerType == InputCommon::CTL_DPAD_CUSTOM); // Or the custom hat mode
bool Hat = (GetId >= IDB_DPAD_UP && GetId <= IDB_DPAD_RIGHT) // All DPads
&& (PadMapping[Controller].controllertype == InputCommon::CTL_DPAD_HAT); // Not with the hat option defined
bool NoTriggerFilter = g_Config.bNoTriggerFilter;
// Values used in this function
char format[128];
int Seconds = 4; // Seconds to wait for
int TimesPerSecond = 40; // How often to run the check
// Values returned from InputCommon::GetButton()
int value; // Axis value
int type; // Button type
int pressed = 0;
bool Succeed = false;
bool Stop = false; // Stop the timer
// =======================
//Console::Print("Before (%i) Id:%i %i IsRunning:%i\n",
// GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning());
// If the Id has changed or the timer is not running we should start one
if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() )
{
if(m_ButtonMappingTimer->IsRunning())
{
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
// Update the old textbox
SetButtonText(GetButtonWaitingID, "");
}
// Save the button Id
GetButtonWaitingID = GetId;
// Reset the key in case we happen to have an old one
g_Pressed = 0;
// Update the text box
sprintf(format, "[%d]", Seconds);
SetButtonText(GetId, format);
// Start the timer
#if wxUSE_TIMER
m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) );
#endif
}
// ===============================================
// Check for buttons
// ----------------
// If there is a timer but we should not create a new one
else
{
InputCommon::GetButton(
joy, PadID, Buttons, Axes, Hats,
g_Pressed, value, type, pressed, Succeed, Stop,
LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter);
}
// ========================= Check for keys
// ===============================================
// Process results
// ----------------
// Count each time
GetButtonWaitingTimer++;
// This is run every second
if(GetButtonWaitingTimer % TimesPerSecond == 0)
{
// Current time
int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond);
// Update text
sprintf(format, "[%d]", TmpTime);
SetButtonText(GetId, format);
}
// Time's up
if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds )
{
Stop = true;
// Leave a blank mapping
if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1");
}
// If we got a button
if(Succeed)
{
Stop = true;
// Write the number of the pressed button to the text box
sprintf(format, "%d", pressed);
if(g_Config.bSaveByID) SetButtonTextAll(GetId, format); else SetButtonText(GetId, format);
}
// Stop the timer
if(Stop)
{
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
/* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots
controlled by the same device, but several DirectInput instances of different but identical devices may possible
have the same id, I don't know. So we have to do this. The user may also have selected the same device for
several disabled slots. */
if(g_Config.bSaveByID) SaveButtonMappingAll(Controller); else SaveButtonMapping(Controller);
}
// If we got a bad button
if(g_Pressed == -1)
{
// Update text
if(g_Config.bSaveByID) SetButtonTextAll(GetId, "-1"); else SetButtonText(GetId, "-1");
// Notify the user
wxMessageBox(wxString::Format(wxT(
"You selected a key with a to low key code (%i), please"
" select another key with a higher key code."), pressed)
, wxT("Notice"), wxICON_INFORMATION);
}
// ======================== Process results
// Debugging
/*
Console::Print("Change: %i %i %i %i '%s' '%s' '%s' '%s'\n",
PadMapping[0].halfpress, PadMapping[1].halfpress, PadMapping[2].halfpress, PadMapping[3].halfpress,
m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str()
);*/
}
/////////////////////////////////////////////////////////// Configure button mapping

View File

@ -1,195 +1,195 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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/
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// File description
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Rerecording options
////////////////////////*/
//////////////////////////////////////////////////////////////////////////////////////////
// Include
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
#include "FileUtil.h"
#include "ChunkFile.h"
/////////////////////////
#ifdef RERECORDING
namespace Recording
{
//////////////////////////////////////////////////////////////////////////////////////////
// Definitions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Pre defined maxium storage limit
#define RECORD_SIZE (1024 * 128)
SPADStatus RecordBuffer[RECORD_SIZE];
int count = 0;
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Recording functions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void RecordInput(const SPADStatus& _rPADStatus)
{
if (count >= RECORD_SIZE) return;
RecordBuffer[count++] = _rPADStatus;
// Logging
//u8 TmpData[sizeof(SPADStatus)];
//memcpy(TmpData, &RecordBuffer[count - 1], sizeof(SPADStatus));
//Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str());
// Auto save every ten seconds
if (count % (60 * 10) == 0) Save();
}
const SPADStatus& Play()
{
// Logging
//Console::Print("PlayRecord(%i)\n", count);
if (count >= RECORD_SIZE)
{
// Todo: Make the recording size unlimited?
//PanicAlert("The recording reached its end");
return(RecordBuffer[0]);
}
return(RecordBuffer[count++]);
}
void Load()
{
FILE* pStream = fopen("pad-record.bin", "rb");
if (pStream != NULL)
{
fread(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
fclose(pStream);
}
else
{
PanicAlert("SimplePad: Could not open pad-record.bin");
}
//Console::Print("LoadRecord()");
}
void Save()
{
// Open the file in a way that clears all old data
FILE* pStream = fopen("pad-record.bin", "wb");
if (pStream != NULL)
{
fwrite(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
fclose(pStream);
}
else
{
PanicAlert("NJoy: Could not save pad-record.bin");
}
//PanicAlert("SaveRecord()");
//Console::Print("SaveRecord()");
}
////////////////////////////////
void Initialize()
{
// -------------------------------------------
// Rerecording
// ----------------------
#ifdef RERECORDING
/* Check if we are starting the pad to record the input, and an old file exists. In that case ask
if we really want to start the recording and eventually overwrite the file */
if (g_Config.bRecording && File::Exists("pad-record.bin"))
{
if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can"
" now make a copy of it before you start a new recording and overwrite the file."
" Select Yes to continue and overwrite the file. Select No to turn off the input"
" recording and continue without recording anything.",
"pad-record.bin"))
{
// Turn off recording and continue
g_Config.bRecording = false;
}
}
// Load recorded input if we are to play it back, otherwise begin with a blank recording
if (g_Config.bPlayback) Recording::Load();
#endif
// ----------------------
}
void ShutDown()
{
// Save recording
if (g_Config.bRecording) Recording::Save();
// Reset the counter
count = 0;
}
void DoState(unsigned char **ptr, int mode)
{
// Load or save the counter
PointerWrap p(ptr, mode);
p.Do(count);
//Console::Print("count: %i\n", count);
// Update the frame counter for the sake of the status bar
if (mode == PointerWrap::MODE_READ)
{
#ifdef _WIN32
// This only works when rendering to the main window, I think
PostMessage(GetParent(g_PADInitialize->hWnd), WM_USER, INPUT_FRAME_COUNTER, count);
#endif
}
}
} // Recording
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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/
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// File description
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Rerecording options
////////////////////////*/
//////////////////////////////////////////////////////////////////////////////////////////
// Include
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
#include "FileUtil.h"
#include "ChunkFile.h"
/////////////////////////
#ifdef RERECORDING
namespace Recording
{
//////////////////////////////////////////////////////////////////////////////////////////
// Definitions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Pre defined maxium storage limit
#define RECORD_SIZE (1024 * 128)
SPADStatus RecordBuffer[RECORD_SIZE];
int count = 0;
////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Recording functions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void RecordInput(const SPADStatus& _rPADStatus)
{
if (count >= RECORD_SIZE) return;
RecordBuffer[count++] = _rPADStatus;
// Logging
//u8 TmpData[sizeof(SPADStatus)];
//memcpy(TmpData, &RecordBuffer[count - 1], sizeof(SPADStatus));
//Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str());
// Auto save every ten seconds
if (count % (60 * 10) == 0) Save();
}
const SPADStatus& Play()
{
// Logging
//Console::Print("PlayRecord(%i)\n", count);
if (count >= RECORD_SIZE)
{
// Todo: Make the recording size unlimited?
//PanicAlert("The recording reached its end");
return(RecordBuffer[0]);
}
return(RecordBuffer[count++]);
}
void Load()
{
FILE* pStream = fopen("pad-record.bin", "rb");
if (pStream != NULL)
{
fread(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
fclose(pStream);
}
else
{
PanicAlert("SimplePad: Could not open pad-record.bin");
}
//Console::Print("LoadRecord()");
}
void Save()
{
// Open the file in a way that clears all old data
FILE* pStream = fopen("pad-record.bin", "wb");
if (pStream != NULL)
{
fwrite(RecordBuffer, 1, RECORD_SIZE * sizeof(SPADStatus), pStream);
fclose(pStream);
}
else
{
PanicAlert("NJoy: Could not save pad-record.bin");
}
//PanicAlert("SaveRecord()");
//Console::Print("SaveRecord()");
}
////////////////////////////////
void Initialize()
{
// -------------------------------------------
// Rerecording
// ----------------------
#ifdef RERECORDING
/* Check if we are starting the pad to record the input, and an old file exists. In that case ask
if we really want to start the recording and eventually overwrite the file */
if (g_Config.bRecording && File::Exists("pad-record.bin"))
{
if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can"
" now make a copy of it before you start a new recording and overwrite the file."
" Select Yes to continue and overwrite the file. Select No to turn off the input"
" recording and continue without recording anything.",
"pad-record.bin"))
{
// Turn off recording and continue
g_Config.bRecording = false;
}
}
// Load recorded input if we are to play it back, otherwise begin with a blank recording
if (g_Config.bPlayback) Recording::Load();
#endif
// ----------------------
}
void ShutDown()
{
// Save recording
if (g_Config.bRecording) Recording::Save();
// Reset the counter
count = 0;
}
void DoState(unsigned char **ptr, int mode)
{
// Load or save the counter
PointerWrap p(ptr, mode);
p.Do(count);
//Console::Print("count: %i\n", count);
// Update the frame counter for the sake of the status bar
if (mode == PointerWrap::MODE_READ)
{
#ifdef _WIN32
// This only works when rendering to the main window, I think
PostMessage(GetParent(g_PADInitialize->hWnd), WM_USER, INPUT_FRAME_COUNTER, count);
#endif
}
}
} // Recording
#endif // RERECORDING

View File

@ -1,394 +1,394 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
//////////////////////////////////////////////////////////////////////////////////////////
// Enable or disable rumble. Set USE_RUMBLE_DINPUT_HACK in nJoy.h
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#ifdef USE_RUMBLE_DINPUT_HACK
bool g_rumbleEnable = FALSE;
#endif
// Rumble in windows
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
LPDIRECTINPUT8 g_pDI = NULL;
LPDIRECTINPUTDEVICE8 g_pDevice = NULL;
LPDIRECTINPUTEFFECT g_pEffect = NULL;
DWORD g_dwNumForceFeedbackAxis = 0;
INT g_nXForce = 0;
INT g_nYForce = 0;
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
HRESULT InitDirectInput(HWND hDlg);
//VOID FreeDirectInput();
BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext);
BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext);
HRESULT SetDeviceForcesXY();
#endif
#elif defined(__linux__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int fd;
char device_file_name[64];
struct ff_effect effect;
bool CanRumble = false;
#endif
//////////////////////
// Set PAD rumble. Explanation: Stop = 0, Rumble = 1
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
{
//if (_numPAD > 0)
// return;
// SDL can't rumble the gamepad so we need to use platform specific code
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
static int a = 0;
if ((_uType == 0) || (_uType == 2))
{
a = 0;
}
else if (_uType == 1)
{
a = _uStrength > 2 ? 8000 : 0;
}
a = int ((float)a * 0.96f);
if (!g_rumbleEnable)
{
a = 0;
}
else
{
g_nYForce = a;
SetDeviceForcesXY();
}
#endif
#elif defined(__linux__)
struct input_event event;
if (CanRumble)
{
if (_uType == 1)
{
event.type = EV_FF;
event.code = effect.id;
event.value = 1;
if (write(fd, (const void*) &event, sizeof(event)) == -1) {
perror("Play effect");
exit(1);
}
}
if ((_uType == 0) || (_uType == 2))
{
event.type = EV_FF;
event.code = effect.id;
event.value = 0;
if (write(fd, (const void*) &event, sizeof(event)) == -1) {
perror("Stop effect");
exit(1);
}
}
}
#endif
}
// Use PAD rumble
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus)
{
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
// Enable or disable rumble
if (PadState[_numPAD].halfpress)
if (!g_pDI)
if (FAILED(InitDirectInput(m_hWnd)))
{
MessageBox(NULL, SDL_GetError(), "Could not initialize DirectInput!", MB_ICONERROR);
g_rumbleEnable = FALSE;
//return;
}
else
{
g_rumbleEnable = TRUE;
}
if (g_rumbleEnable)
{
g_pDevice->Acquire();
if (g_pEffect) g_pEffect->Start(1, 0);
}
#endif
#elif defined(__linux__)
if (!fd)
{
sprintf(device_file_name, "/dev/input/event%d", PadMapping[_numPAD].eventnum); //TODO: Make dynamic //
/* Open device */
fd = open(device_file_name, O_RDWR);
if (fd == -1) {
perror("Open device file");
//Something wrong, probably permissions, just return now
return;
}
int n_effects = 0;
if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) {
perror("Ioctl number of effects");
}
if (n_effects > 0)
CanRumble = true;
else
return; // Return since we can't do any effects
/* a strong rumbling effect */
effect.type = FF_RUMBLE;
effect.id = -1;
effect.u.rumble.strong_magnitude = 0x8000;
effect.u.rumble.weak_magnitude = 0;
effect.replay.length = 5000; // Set to 5 seconds, if a Game needs more for a single rumble event, it is dumb and must be a demo
effect.replay.delay = 0;
if (ioctl(fd, EVIOCSFF, &effect) == -1) {
perror("Upload effect");
CanRumble = false; //We have effects but it doesn't support the rumble we are using. This is basic rumble, should work for most
}
}
#endif
}
#ifdef _WIN32
//////////////////////////////////////////////////////////////////////////////////////////
// Rumble stuff :D!
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//
#ifdef USE_RUMBLE_DINPUT_HACK
HRESULT InitDirectInput( HWND hDlg )
{
DIPROPDWORD dipdw;
HRESULT hr;
// Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use.
if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL)))
{
return hr;
}
// Look for a force feedback device we can use
if (FAILED(hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK)))
{
return hr;
}
if (NULL == g_pDevice)
{
MessageBox(NULL, "Force feedback device not found. nJoy will now disable rumble." ,"FFConst" , MB_ICONERROR | MB_OK);
g_rumbleEnable = FALSE;
return S_OK;
}
// Set the data format to "simple joystick" - a predefined data format. A
// data format specifies which controls on a device we are interested in,
// and how they should be reported.
//
// This tells DirectInput that we will be passing a DIJOYSTATE structure to
// IDirectInputDevice8::GetDeviceState(). Even though we won't actually do
// it in this sample. But setting the data format is important so that the
// DIJOFS_* values work properly.
if (FAILED(hr = g_pDevice->SetDataFormat(&c_dfDIJoystick)))
return hr;
// Set the cooperative level to let DInput know how this device should
// interact with the system and with other DInput applications.
// Exclusive access is required in order to perform force feedback.
//if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
{
return hr;
}
// Since we will be playing force feedback effects, we should disable the
// auto-centering spring.
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = FALSE;
if (FAILED(hr = g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph)))
return hr;
// Enumerate and count the axes of the joystick
if (FAILED(hr = g_pDevice->EnumObjects(EnumAxesCallback, (VOID*)&g_dwNumForceFeedbackAxis, DIDFT_AXIS)))
return hr;
// This simple sample only supports one or two axis joysticks
if (g_dwNumForceFeedbackAxis > 2)
g_dwNumForceFeedbackAxis = 2;
// This application needs only one effect: Applying raw forces.
DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y};
LONG rglDirection[2] = {0, 0};
DICONSTANTFORCE cf = {0};
DIEFFECT eff;
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwSamplePeriod = 0;
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.dwTriggerRepeatInterval = 0;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE );
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
// Create the prepared effect
if (FAILED(hr = g_pDevice->CreateEffect(GUID_ConstantForce, &eff, &g_pEffect, NULL)))
{
return hr;
}
if (NULL == g_pEffect)
return E_FAIL;
return S_OK;
}
VOID FreeDirectInput()
{
// Unacquire the device one last time just in case
// the app tried to exit while the device is still acquired.
if (g_pDevice)
g_pDevice->Unacquire();
// Release any DirectInput objects.
SAFE_RELEASE(g_pEffect);
SAFE_RELEASE(g_pDevice);
SAFE_RELEASE(g_pDI);
}
BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext )
{
LPDIRECTINPUTDEVICE8 pDevice;
HRESULT hr;
// Obtain an interface to the enumerated force feedback device.
hr = g_pDI->CreateDevice(pInst->guidInstance, &pDevice, NULL);
// If it failed, then we can't use this device for some bizarre reason.
// (Maybe the user unplugged it while we were in the middle of enumerating it.) So continue enumerating
if (FAILED(hr))
return DIENUM_CONTINUE;
// We successfully created an IDirectInputDevice8. So stop looking for another one.
g_pDevice = pDevice;
return DIENUM_STOP;
}
BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext)
{
DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext;
if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0)
(*pdwNumForceFeedbackAxis)++;
return DIENUM_CONTINUE;
}
HRESULT SetDeviceForcesXY()
{
// Modifying an effect is basically the same as creating a new one, except you need only specify the parameters you are modifying
LONG rglDirection[2] = { 0, 0 };
DICONSTANTFORCE cf;
if (g_dwNumForceFeedbackAxis == 1)
{
// If only one force feedback axis, then apply only one direction and keep the direction at zero
cf.lMagnitude = g_nXForce;
rglDirection[0] = 0;
}
else
{
// If two force feedback axis, then apply magnitude from both directions
rglDirection[0] = g_nXForce;
rglDirection[1] = g_nYForce;
cf.lMagnitude = (DWORD)sqrt((double)g_nXForce * (double)g_nXForce + (double)g_nYForce * (double)g_nYForce );
}
DIEFFECT eff;
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
// Now set the new parameters and start the effect immediately.
return g_pEffect->SetParameters(&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START);
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// Project description
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// Name: nJoy
// Description: A Dolphin Compatible Input Plugin
//
// Author: Falcon4ever (nJoy@falcon4ever.com)
// Site: www.multigesture.net
// Copyright (C) 2003-2008 Dolphin Project.
//
//////////////////////////////////////////////////////////////////////////////////////////
//
// Licensetype: GNU General Public License (GPL)
//
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "nJoy.h"
//////////////////////////////////////////////////////////////////////////////////////////
// Enable or disable rumble. Set USE_RUMBLE_DINPUT_HACK in nJoy.h
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#ifdef USE_RUMBLE_DINPUT_HACK
bool g_rumbleEnable = FALSE;
#endif
// Rumble in windows
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
LPDIRECTINPUT8 g_pDI = NULL;
LPDIRECTINPUTDEVICE8 g_pDevice = NULL;
LPDIRECTINPUTEFFECT g_pEffect = NULL;
DWORD g_dwNumForceFeedbackAxis = 0;
INT g_nXForce = 0;
INT g_nYForce = 0;
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
HRESULT InitDirectInput(HWND hDlg);
//VOID FreeDirectInput();
BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext);
BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext);
HRESULT SetDeviceForcesXY();
#endif
#elif defined(__linux__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int fd;
char device_file_name[64];
struct ff_effect effect;
bool CanRumble = false;
#endif
//////////////////////
// Set PAD rumble. Explanation: Stop = 0, Rumble = 1
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
{
//if (_numPAD > 0)
// return;
// SDL can't rumble the gamepad so we need to use platform specific code
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
static int a = 0;
if ((_uType == 0) || (_uType == 2))
{
a = 0;
}
else if (_uType == 1)
{
a = _uStrength > 2 ? 8000 : 0;
}
a = int ((float)a * 0.96f);
if (!g_rumbleEnable)
{
a = 0;
}
else
{
g_nYForce = a;
SetDeviceForcesXY();
}
#endif
#elif defined(__linux__)
struct input_event event;
if (CanRumble)
{
if (_uType == 1)
{
event.type = EV_FF;
event.code = effect.id;
event.value = 1;
if (write(fd, (const void*) &event, sizeof(event)) == -1) {
perror("Play effect");
exit(1);
}
}
if ((_uType == 0) || (_uType == 2))
{
event.type = EV_FF;
event.code = effect.id;
event.value = 0;
if (write(fd, (const void*) &event, sizeof(event)) == -1) {
perror("Stop effect");
exit(1);
}
}
}
#endif
}
// Use PAD rumble
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus)
{
#ifdef _WIN32
#ifdef USE_RUMBLE_DINPUT_HACK
// Enable or disable rumble
if (PadState[_numPAD].halfpress)
if (!g_pDI)
if (FAILED(InitDirectInput(m_hWnd)))
{
MessageBox(NULL, SDL_GetError(), "Could not initialize DirectInput!", MB_ICONERROR);
g_rumbleEnable = FALSE;
//return;
}
else
{
g_rumbleEnable = TRUE;
}
if (g_rumbleEnable)
{
g_pDevice->Acquire();
if (g_pEffect) g_pEffect->Start(1, 0);
}
#endif
#elif defined(__linux__)
if (!fd)
{
sprintf(device_file_name, "/dev/input/event%d", PadMapping[_numPAD].eventnum); //TODO: Make dynamic //
/* Open device */
fd = open(device_file_name, O_RDWR);
if (fd == -1) {
perror("Open device file");
//Something wrong, probably permissions, just return now
return;
}
int n_effects = 0;
if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) {
perror("Ioctl number of effects");
}
if (n_effects > 0)
CanRumble = true;
else
return; // Return since we can't do any effects
/* a strong rumbling effect */
effect.type = FF_RUMBLE;
effect.id = -1;
effect.u.rumble.strong_magnitude = 0x8000;
effect.u.rumble.weak_magnitude = 0;
effect.replay.length = 5000; // Set to 5 seconds, if a Game needs more for a single rumble event, it is dumb and must be a demo
effect.replay.delay = 0;
if (ioctl(fd, EVIOCSFF, &effect) == -1) {
perror("Upload effect");
CanRumble = false; //We have effects but it doesn't support the rumble we are using. This is basic rumble, should work for most
}
}
#endif
}
#ifdef _WIN32
//////////////////////////////////////////////////////////////////////////////////////////
// Rumble stuff :D!
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//
#ifdef USE_RUMBLE_DINPUT_HACK
HRESULT InitDirectInput( HWND hDlg )
{
DIPROPDWORD dipdw;
HRESULT hr;
// Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use.
if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL)))
{
return hr;
}
// Look for a force feedback device we can use
if (FAILED(hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK)))
{
return hr;
}
if (NULL == g_pDevice)
{
MessageBox(NULL, "Force feedback device not found. nJoy will now disable rumble." ,"FFConst" , MB_ICONERROR | MB_OK);
g_rumbleEnable = FALSE;
return S_OK;
}
// Set the data format to "simple joystick" - a predefined data format. A
// data format specifies which controls on a device we are interested in,
// and how they should be reported.
//
// This tells DirectInput that we will be passing a DIJOYSTATE structure to
// IDirectInputDevice8::GetDeviceState(). Even though we won't actually do
// it in this sample. But setting the data format is important so that the
// DIJOFS_* values work properly.
if (FAILED(hr = g_pDevice->SetDataFormat(&c_dfDIJoystick)))
return hr;
// Set the cooperative level to let DInput know how this device should
// interact with the system and with other DInput applications.
// Exclusive access is required in order to perform force feedback.
//if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
{
return hr;
}
// Since we will be playing force feedback effects, we should disable the
// auto-centering spring.
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = FALSE;
if (FAILED(hr = g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph)))
return hr;
// Enumerate and count the axes of the joystick
if (FAILED(hr = g_pDevice->EnumObjects(EnumAxesCallback, (VOID*)&g_dwNumForceFeedbackAxis, DIDFT_AXIS)))
return hr;
// This simple sample only supports one or two axis joysticks
if (g_dwNumForceFeedbackAxis > 2)
g_dwNumForceFeedbackAxis = 2;
// This application needs only one effect: Applying raw forces.
DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y};
LONG rglDirection[2] = {0, 0};
DICONSTANTFORCE cf = {0};
DIEFFECT eff;
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwSamplePeriod = 0;
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.dwTriggerRepeatInterval = 0;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE );
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
// Create the prepared effect
if (FAILED(hr = g_pDevice->CreateEffect(GUID_ConstantForce, &eff, &g_pEffect, NULL)))
{
return hr;
}
if (NULL == g_pEffect)
return E_FAIL;
return S_OK;
}
VOID FreeDirectInput()
{
// Unacquire the device one last time just in case
// the app tried to exit while the device is still acquired.
if (g_pDevice)
g_pDevice->Unacquire();
// Release any DirectInput objects.
SAFE_RELEASE(g_pEffect);
SAFE_RELEASE(g_pDevice);
SAFE_RELEASE(g_pDI);
}
BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext )
{
LPDIRECTINPUTDEVICE8 pDevice;
HRESULT hr;
// Obtain an interface to the enumerated force feedback device.
hr = g_pDI->CreateDevice(pInst->guidInstance, &pDevice, NULL);
// If it failed, then we can't use this device for some bizarre reason.
// (Maybe the user unplugged it while we were in the middle of enumerating it.) So continue enumerating
if (FAILED(hr))
return DIENUM_CONTINUE;
// We successfully created an IDirectInputDevice8. So stop looking for another one.
g_pDevice = pDevice;
return DIENUM_STOP;
}
BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext)
{
DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext;
if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0)
(*pdwNumForceFeedbackAxis)++;
return DIENUM_CONTINUE;
}
HRESULT SetDeviceForcesXY()
{
// Modifying an effect is basically the same as creating a new one, except you need only specify the parameters you are modifying
LONG rglDirection[2] = { 0, 0 };
DICONSTANTFORCE cf;
if (g_dwNumForceFeedbackAxis == 1)
{
// If only one force feedback axis, then apply only one direction and keep the direction at zero
cf.lMagnitude = g_nXForce;
rglDirection[0] = 0;
}
else
{
// If two force feedback axis, then apply magnitude from both directions
rglDirection[0] = g_nXForce;
rglDirection[1] = g_nYForce;
cf.lMagnitude = (DWORD)sqrt((double)g_nXForce * (double)g_nXForce + (double)g_nYForce * (double)g_nYForce );
}
DIEFFECT eff;
ZeroMemory(&eff, sizeof(eff));
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cAxes = g_dwNumForceFeedbackAxis;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
// Now set the new parameters and start the effect immediately.
return g_pEffect->SetParameters(&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START);
}
#endif
#endif