2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2009-02-23 07:23:34 +00:00
// 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/
2009-06-07 12:06:15 +00:00
2009-02-23 07:23:34 +00:00
# include "Globals.h"
2009-07-12 21:58:32 +00:00
# include "Thread.h"
2009-03-05 23:11:13 +00:00
2009-02-23 07:23:34 +00:00
# include <vector>
# include <cmath>
2009-03-28 21:07:16 +00:00
# include <cstdio>
2009-02-23 07:23:34 +00:00
# include "GLUtil.h"
# include <Cg/cg.h>
# include <Cg/cgGL.h>
# ifdef _WIN32
# include <mmsystem.h>
# endif
2009-03-28 21:07:16 +00:00
# include "CommonPaths.h"
2009-09-13 09:23:30 +00:00
# include "VideoConfig.h"
2009-02-23 07:23:34 +00:00
# include "Profiler.h"
# include "Statistics.h"
# include "ImageWrite.h"
# include "Render.h"
# include "OpcodeDecoding.h"
2009-06-22 09:31:30 +00:00
# include "BPStructs.h"
2009-02-23 07:23:34 +00:00
# include "TextureMngr.h"
2009-10-13 06:12:58 +00:00
# include "RasterFont.h"
2009-02-23 07:23:34 +00:00
# include "VertexShaderGen.h"
2009-08-09 11:03:58 +00:00
# include "DLCache.h"
2009-02-23 07:23:34 +00:00
# include "PixelShaderCache.h"
# include "PixelShaderManager.h"
2009-02-28 16:33:59 +00:00
# include "VertexShaderCache.h"
# include "VertexShaderManager.h"
2009-02-23 07:23:34 +00:00
# include "VertexLoaderManager.h"
# include "VertexLoader.h"
2009-06-08 19:42:25 +00:00
# include "PostProcessing.h"
2009-06-26 08:57:53 +00:00
# include "TextureConverter.h"
2009-02-23 07:23:34 +00:00
# include "XFB.h"
# include "OnScreenDisplay.h"
# include "Timer.h"
2009-06-06 13:36:33 +00:00
# include "StringUtil.h"
2009-06-28 23:35:08 +00:00
# include "FramebufferManager.h"
2009-07-11 02:34:16 +00:00
# include "Fifo.h"
2009-02-23 07:23:34 +00:00
# include "main.h" // Local
# ifdef _WIN32
# include "OS/Win32.h"
2009-03-28 21:07:16 +00:00
# include "AVIDump.h"
2009-02-23 07:23:34 +00:00
# endif
2009-02-27 03:56:34 +00:00
# if defined(HAVE_WX) && HAVE_WX
# include <wx/image.h>
# endif
2009-06-07 12:06:15 +00:00
// Declarations and definitions
2009-09-08 16:07:13 +00:00
// ----------------------------
2009-02-23 07:23:34 +00:00
CGcontext g_cgcontext ;
CGprofile g_cgvProf ;
CGprofile g_cgfProf ;
RasterFont * s_pfont = NULL ;
static bool s_bFullscreen = false ;
2009-03-28 21:07:16 +00:00
static bool s_bLastFrameDumped = false ;
# ifdef _WIN32
static bool s_bAVIDumping = false ;
# else
static FILE * f_pFrameDump ;
# endif
2009-03-08 19:19:51 +00:00
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
static int s_MSAASamples = 1 ;
2009-03-08 20:04:40 +00:00
static int s_MSAACoverageSamples = 0 ;
2009-03-05 23:11:13 +00:00
2009-06-29 21:54:42 +00:00
bool s_bHaveFramebufferBlit = false ; // export to FramebufferManager.cpp
2009-03-08 20:04:40 +00:00
static bool s_bHaveCoverageMSAA = false ;
2009-03-08 19:19:51 +00:00
static u32 s_blendMode ;
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
static volatile bool s_bScreenshot = false ;
2009-07-31 01:55:26 +00:00
static Common : : Thread * scrshotThread = 0 ;
2009-02-27 03:56:34 +00:00
static Common : : CriticalSection s_criticalScreenshot ;
static std : : string s_sScreenshotName ;
2009-02-23 07:23:34 +00:00
int frameCount ;
2009-02-28 16:33:59 +00:00
2009-09-06 15:11:21 +00:00
// The custom resolution
2009-03-05 23:11:13 +00:00
// TODO: Add functionality to reinit all the render targets when the window is resized.
2009-09-06 15:11:21 +00:00
static int m_CustomWidth ;
static int m_CustomHeight ;
// The framebuffer size
static int m_FrameBufferWidth ;
static int m_FrameBufferHeight ;
2009-02-28 16:33:59 +00:00
2009-06-29 20:54:47 +00:00
static GLuint s_tempScreenshotFramebuffer = 0 ;
2009-06-28 23:35:08 +00:00
2009-08-08 01:39:56 +00:00
static bool s_skipSwap = false ;
2009-06-09 21:29:54 +00:00
# ifndef _WIN32
int OSDChoice = 0 , OSDTime = 0 , OSDInternalW = 0 , OSDInternalH = 0 ;
# endif
2009-02-23 07:23:34 +00:00
2009-03-05 23:11:13 +00:00
namespace {
2009-02-23 07:23:34 +00:00
2009-07-31 01:55:26 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-07-29 03:11:35 +00:00
// Screenshot thread struct
typedef struct
{
int W , H ;
std : : string filename ;
wxImage * img ;
} ScrStrct ;
2009-07-31 01:55:26 +00:00
# endif
2009-07-29 03:11:35 +00:00
2009-02-23 07:23:34 +00:00
static const GLenum glSrcFactors [ 8 ] =
{
GL_ZERO ,
GL_ONE ,
GL_DST_COLOR ,
GL_ONE_MINUS_DST_COLOR ,
GL_SRC_ALPHA ,
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA
} ;
static const GLenum glDestFactors [ 8 ] = {
2009-10-25 02:35:21 +00:00
GL_ZERO ,
GL_ONE ,
GL_SRC_COLOR ,
GL_ONE_MINUS_SRC_COLOR ,
GL_SRC_ALPHA ,
GL_ONE_MINUS_SRC_ALPHA ,
GL_DST_ALPHA ,
GL_ONE_MINUS_DST_ALPHA
2009-02-23 07:23:34 +00:00
} ;
2009-11-27 19:42:27 +00:00
static const GLenum glCmpFuncs [ 8 ] = {
GL_NEVER , GL_LESS , GL_EQUAL , GL_LEQUAL , GL_GREATER , GL_NOTEQUAL , GL_GEQUAL , GL_ALWAYS
} ;
static const GLenum glLogicOpCodes [ 16 ] = {
GL_CLEAR , GL_AND , GL_AND_REVERSE , GL_COPY , GL_AND_INVERTED , GL_NOOP , GL_XOR ,
GL_OR , GL_NOR , GL_EQUIV , GL_INVERT , GL_OR_REVERSE , GL_COPY_INVERTED , GL_OR_INVERTED , GL_NAND , GL_SET
} ;
2009-03-05 23:11:13 +00:00
void SetDefaultRectTexParams ( )
{
// Set some standard texture filter modes.
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
if ( glGetError ( ) ! = GL_NO_ERROR ) {
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_S , GL_CLAMP ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_WRAP_T , GL_CLAMP ) ;
GL_REPORT_ERROR ( ) ;
}
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
}
2009-04-08 17:58:58 +00:00
void HandleCgError ( CGcontext ctx , CGerror err , void * appdata )
{
2009-06-09 19:40:47 +00:00
DEBUG_LOG ( VIDEO , " Cg error: %s " , cgGetErrorString ( err ) ) ;
2009-04-08 17:58:58 +00:00
const char * listing = cgGetLastListing ( g_cgcontext ) ;
if ( listing ! = NULL ) {
2009-06-09 19:40:47 +00:00
DEBUG_LOG ( VIDEO , " last listing: %s " , listing ) ;
2009-04-08 17:58:58 +00:00
}
}
2009-03-05 23:11:13 +00:00
2009-06-07 12:06:15 +00:00
} // namespace
2009-09-18 19:56:49 +00:00
void VideoConfig : : UpdateProjectionHack ( )
{
: : UpdateProjectionHack ( g_Config . iPhackvalue ) ;
}
2009-06-07 12:06:15 +00:00
2009-03-05 23:11:13 +00:00
2009-06-07 12:06:15 +00:00
// Init functions
2009-02-23 07:23:34 +00:00
bool Renderer : : Init ( )
{
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2009-02-23 07:23:34 +00:00
bool bSuccess = true ;
2009-02-28 16:33:59 +00:00
s_blendMode = 0 ;
2009-03-08 20:04:40 +00:00
s_MSAACoverageSamples = 0 ;
2009-09-13 08:21:35 +00:00
switch ( g_ActiveConfig . iMultisampleMode )
2009-03-08 20:04:40 +00:00
{
case MULTISAMPLE_OFF : s_MSAASamples = 1 ; break ;
case MULTISAMPLE_2X : s_MSAASamples = 2 ; break ;
case MULTISAMPLE_4X : s_MSAASamples = 4 ; break ;
case MULTISAMPLE_8X : s_MSAASamples = 8 ; break ;
case MULTISAMPLE_CSAA_8X : s_MSAASamples = 4 ; s_MSAACoverageSamples = 8 ; break ;
case MULTISAMPLE_CSAA_8XQ : s_MSAASamples = 8 ; s_MSAACoverageSamples = 8 ; break ;
case MULTISAMPLE_CSAA_16X : s_MSAASamples = 4 ; s_MSAACoverageSamples = 16 ; break ;
case MULTISAMPLE_CSAA_16XQ : s_MSAASamples = 8 ; s_MSAACoverageSamples = 16 ; break ;
default :
s_MSAASamples = 1 ;
}
2009-02-28 16:33:59 +00:00
GLint numvertexattribs = 0 ;
2009-02-23 07:23:34 +00:00
g_cgcontext = cgCreateContext ( ) ;
cgGetError ( ) ;
2009-03-08 19:19:51 +00:00
cgSetErrorHandler ( HandleCgError , NULL ) ;
2009-03-05 23:11:13 +00:00
2009-02-28 16:33:59 +00:00
// Look for required extensions.
const char * ptoken = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
if ( ! ptoken )
{
2009-04-03 21:32:10 +00:00
PanicAlert ( " Your OpenGL Driver seems to be not working. \n "
" Please make sure your drivers are up-to-date and \n "
2009-04-03 21:01:05 +00:00
" that your video hardware is OpenGL 2.x compatible "
) ;
2009-02-28 16:33:59 +00:00
return false ;
}
2009-07-31 01:55:26 +00:00
2009-03-21 20:07:56 +00:00
INFO_LOG ( VIDEO , " Supported OpenGL Extensions: " ) ;
2009-02-28 01:26:56 +00:00
INFO_LOG ( VIDEO , ptoken ) ; // write to the log file
2009-03-21 20:07:56 +00:00
INFO_LOG ( VIDEO , " " ) ;
2009-02-23 07:23:34 +00:00
2009-04-03 20:22:45 +00:00
OSD : : AddMessage ( StringFromFormat ( " Video Info: %s, %s, %s " , ( const char * ) glGetString ( GL_VENDOR ) ,
( const char * ) glGetString ( GL_RENDERER ) ,
( const char * ) glGetString ( GL_VERSION ) ) . c_str ( ) , 5000 ) ;
2009-09-13 08:21:35 +00:00
s_bFullscreen = g_ActiveConfig . bFullscreen ;
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
glGetIntegerv ( GL_MAX_VERTEX_ATTRIBS , & numvertexattribs ) ;
if ( numvertexattribs < 11 ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " ********* \n GPU: OGL ERROR: Number of attributes %d not enough \n GPU: *********Does your video card support OpenGL 2.x? " , numvertexattribs ) ;
2009-02-28 16:33:59 +00:00
bSuccess = false ;
}
// Init extension support.
if ( glewInit ( ) ! = GLEW_OK ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " glewInit() failed!Does your video card support OpenGL 2.x? " ) ;
2009-02-23 07:23:34 +00:00
return false ;
}
if ( ! GLEW_EXT_framebuffer_object ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " ********* \n GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets \n GPU: *********Does your video card support OpenGL 2.x? " ) ;
2009-02-23 07:23:34 +00:00
bSuccess = false ;
}
if ( ! GLEW_EXT_secondary_color ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " ********* \n GPU: OGL ERROR: Need GL_EXT_secondary_color \n GPU: *********Does your video card support OpenGL 2.x? " ) ;
2009-02-23 07:23:34 +00:00
bSuccess = false ;
}
2009-03-08 19:19:51 +00:00
s_bHaveFramebufferBlit = strstr ( ptoken , " GL_EXT_framebuffer_blit " ) ! = NULL ;
if ( ! s_bHaveFramebufferBlit )
{
// MSAA ain't gonna work. turn it off if enabled.
s_MSAASamples = 1 ;
}
2009-03-08 20:04:40 +00:00
s_bHaveCoverageMSAA = strstr ( ptoken , " GL_NV_framebuffer_multisample_coverage " ) ! = NULL ;
if ( ! s_bHaveCoverageMSAA )
{
s_MSAACoverageSamples = 0 ;
}
2009-02-23 07:23:34 +00:00
if ( ! bSuccess )
return false ;
2009-03-05 23:11:13 +00:00
// Handle VSync on/off
2009-09-09 20:47:11 +00:00
# if defined USE_WX && USE_WX
// TODO: FILL IN
# elif defined _WIN32
2009-02-28 16:33:59 +00:00
if ( WGLEW_EXT_swap_control )
2009-09-13 08:21:35 +00:00
wglSwapIntervalEXT ( g_ActiveConfig . bVSync ? 1 : 0 ) ;
2009-02-28 16:33:59 +00:00
else
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " no support for SwapInterval (framerate clamped to monitor refresh rate)Does your video card support OpenGL 2.x? " ) ;
2009-02-23 07:23:34 +00:00
# elif defined(HAVE_X11) && HAVE_X11
2009-02-28 16:33:59 +00:00
if ( glXSwapIntervalSGI )
2009-09-13 08:21:35 +00:00
glXSwapIntervalSGI ( g_ActiveConfig . bVSync ? 1 : 0 ) ;
2009-02-28 16:33:59 +00:00
else
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " no support for SwapInterval (framerate clamped to monitor refresh rate) " ) ;
2009-02-23 07:23:34 +00:00
# endif
// check the max texture width and height
GLint max_texture_size ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , ( GLint * ) & max_texture_size ) ;
if ( max_texture_size < 1024 ) {
2009-02-28 01:26:56 +00:00
ERROR_LOG ( VIDEO , " GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024 " , max_texture_size ) ;
2009-02-23 07:23:34 +00:00
}
2009-03-22 11:21:44 +00:00
if ( GL_REPORT_ERROR ( ) ! = GL_NO_ERROR )
bSuccess = false ;
2009-02-23 07:23:34 +00:00
if ( glDrawBuffers = = NULL & & ! GLEW_ARB_draw_buffers )
glDrawBuffers = glDrawBuffersARB ;
2009-03-22 11:21:44 +00:00
if ( ! GLEW_ARB_texture_non_power_of_two ) {
2010-01-18 21:11:50 +00:00
WARN_LOG ( VIDEO , " ARB_texture_non_power_of_two not supported. " ) ;
2009-03-22 11:21:44 +00:00
}
2009-02-23 07:23:34 +00:00
2009-09-05 05:42:51 +00:00
// Decide frambuffer size
int W = ( int ) OpenGL_GetBackbufferWidth ( ) , H = ( int ) OpenGL_GetBackbufferHeight ( ) ;
2009-10-22 20:22:50 +00:00
if ( g_ActiveConfig . b2xResolution )
2009-09-05 05:42:51 +00:00
{
2009-10-22 20:22:50 +00:00
m_FrameBufferWidth = ( 2 * EFB_HEIGHT > = W ) ? 2 * EFB_HEIGHT : W ;
m_FrameBufferHeight = ( 2 * EFB_HEIGHT > = H ) ? 2 * EFB_HEIGHT : H ;
2009-09-05 05:42:51 +00:00
}
2009-06-28 23:35:08 +00:00
else
{
// The size of the framebuffer targets should really NOT be the size of the OpenGL viewport.
// The EFB is larger than 640x480 - in fact, it's 640x528, give or take a couple of lines.
2009-09-06 15:11:21 +00:00
m_FrameBufferWidth = ( EFB_WIDTH > = W ) ? EFB_WIDTH : W ;
m_FrameBufferHeight = ( 480 > = H ) ? 480 : H ;
2009-06-08 20:07:20 +00:00
2009-09-06 13:36:05 +00:00
// Adjust all heights with this ratio, the resulting height will be the same as H or EFB_HEIGHT. I.e.
// 768 (-1) for 1024x768 etc.
2009-09-13 17:46:33 +00:00
m_FrameBufferHeight * = ( float ) EFB_HEIGHT / 480.0 ;
2009-09-05 05:42:51 +00:00
2009-09-06 13:36:05 +00:00
// Ensure a minimum target size so that the native res target always fits
2009-09-06 15:11:21 +00:00
if ( m_FrameBufferWidth < EFB_WIDTH ) m_FrameBufferWidth = EFB_WIDTH ;
if ( m_FrameBufferHeight < EFB_HEIGHT ) m_FrameBufferHeight = EFB_HEIGHT ;
2009-06-28 23:35:08 +00:00
}
2009-02-28 19:02:37 +00:00
2009-09-06 15:11:21 +00:00
// Save the custom resolution
m_CustomWidth = ( int ) OpenGL_GetBackbufferWidth ( ) ;
m_CustomHeight = ( int ) OpenGL_GetBackbufferHeight ( ) ;
// Because of the fixed framebuffer size we need to disable the resolution options while running
2009-10-22 20:22:50 +00:00
g_Config . bRunning = true ;
2009-02-28 16:33:59 +00:00
2009-03-22 11:21:44 +00:00
if ( GL_REPORT_ERROR ( ) ! = GL_NO_ERROR )
bSuccess = false ;
2009-06-28 23:35:08 +00:00
// Initialize the FramebufferManager
2009-09-06 15:11:21 +00:00
g_framebufferManager . Init ( m_FrameBufferWidth , m_FrameBufferHeight , s_MSAASamples , s_MSAACoverageSamples ) ;
2009-09-06 13:36:05 +00:00
2009-03-08 19:19:51 +00:00
glDrawBuffer ( GL_COLOR_ATTACHMENT0_EXT ) ;
2009-02-23 07:23:34 +00:00
2009-03-22 11:21:44 +00:00
if ( GL_REPORT_ERROR ( ) ! = GL_NO_ERROR )
2009-02-23 07:23:34 +00:00
bSuccess = false ;
s_pfont = new RasterFont ( ) ;
// load the effect, find the best profiles (if any)
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBVP1 ) ! = CG_TRUE ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " arbvp1 not supported " ) ;
2009-02-23 07:23:34 +00:00
return false ;
}
if ( cgGLIsProfileSupported ( CG_PROFILE_ARBFP1 ) ! = CG_TRUE ) {
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " arbfp1 not supported " ) ;
2009-02-23 07:23:34 +00:00
return false ;
}
g_cgvProf = cgGLGetLatestProfile ( CG_GL_VERTEX ) ;
g_cgfProf = cgGLGetLatestProfile ( CG_GL_FRAGMENT ) ;
cgGLSetOptimalOptions ( g_cgvProf ) ;
cgGLSetOptimalOptions ( g_cgfProf ) ;
2009-03-21 20:07:56 +00:00
INFO_LOG ( VIDEO , " Max buffer sizes: %d %d " , cgGetProgramBufferMaxSize ( g_cgvProf ) , cgGetProgramBufferMaxSize ( g_cgfProf ) ) ;
2009-02-23 07:23:34 +00:00
int nenvvertparams , nenvfragparams , naddrregisters [ 2 ] ;
2009-03-05 23:11:13 +00:00
glGetProgramivARB ( GL_VERTEX_PROGRAM_ARB , GL_MAX_PROGRAM_ENV_PARAMETERS_ARB , ( GLint * ) & nenvvertparams ) ;
glGetProgramivARB ( GL_FRAGMENT_PROGRAM_ARB , GL_MAX_PROGRAM_ENV_PARAMETERS_ARB , ( GLint * ) & nenvfragparams ) ;
glGetProgramivARB ( GL_VERTEX_PROGRAM_ARB , GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB , ( GLint * ) & naddrregisters [ 0 ] ) ;
2009-02-23 07:23:34 +00:00
glGetProgramivARB ( GL_FRAGMENT_PROGRAM_ARB , GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB , ( GLint * ) & naddrregisters [ 1 ] ) ;
2009-03-21 20:07:56 +00:00
DEBUG_LOG ( VIDEO , " Max program env parameters: vert=%d, frag=%d " , nenvvertparams , nenvfragparams ) ;
DEBUG_LOG ( VIDEO , " Max program address register parameters: vert=%d, frag=%d " , naddrregisters [ 0 ] , naddrregisters [ 1 ] ) ;
2009-02-23 07:23:34 +00:00
if ( nenvvertparams < 238 )
2009-03-21 20:07:56 +00:00
ERROR_LOG ( VIDEO , " Not enough vertex shader environment constants!! " ) ;
2009-02-23 07:23:34 +00:00
# ifndef _DEBUG
cgGLSetDebugMode ( GL_FALSE ) ;
# endif
glStencilFunc ( GL_ALWAYS , 0 , 0 ) ;
glBlendFunc ( GL_ONE , GL_ONE ) ;
glViewport ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ; // Reset The Current Viewport
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
glShadeModel ( GL_SMOOTH ) ;
glClearColor ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
glClearDepth ( 1.0f ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDisable ( GL_LIGHTING ) ;
glDepthFunc ( GL_LEQUAL ) ;
glPixelStorei ( GL_UNPACK_ALIGNMENT , 4 ) ; // 4-byte pixel alignment
glDisable ( GL_STENCIL_TEST ) ;
glEnable ( GL_SCISSOR_TEST ) ;
2009-03-05 23:11:13 +00:00
glScissor ( 0 , 0 , GetTargetWidth ( ) , GetTargetHeight ( ) ) ;
2009-02-23 07:23:34 +00:00
glBlendColorEXT ( 0 , 0 , 0 , 0.5f ) ;
glClearDepth ( 1.0f ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
// legacy multitexturing: select texture channel only.
glActiveTexture ( GL_TEXTURE0 ) ;
glClientActiveTexture ( GL_TEXTURE0 ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2009-09-03 19:24:16 +00:00
return glGetError ( ) = = GL_NO_ERROR & & bSuccess ;
2009-02-23 07:23:34 +00:00
}
2009-09-03 19:24:16 +00:00
void Renderer : : Shutdown ( void )
{
2009-09-06 15:11:21 +00:00
g_Config . bRunning = false ;
2009-09-13 08:21:35 +00:00
UpdateActiveConfig ( ) ;
2009-09-03 19:24:16 +00:00
delete s_pfont ;
s_pfont = 0 ;
if ( g_cgcontext ) {
cgDestroyContext ( g_cgcontext ) ;
g_cgcontext = 0 ;
}
glDeleteFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer ) ;
s_tempScreenshotFramebuffer = 0 ;
2009-09-03 20:37:35 +00:00
g_framebufferManager . Shutdown ( ) ;
2009-09-03 19:24:16 +00:00
# ifdef _WIN32
if ( s_bAVIDumping ) {
AVIDump : : Stop ( ) ;
}
# else
if ( f_pFrameDump ! = NULL ) {
fclose ( f_pFrameDump ) ;
}
# endif
}
2009-02-23 07:23:34 +00:00
2009-09-06 15:11:21 +00:00
// For the OSD menu's live resolution change
bool Renderer : : Allow2x ( )
{
if ( GetFrameBufferWidth ( ) > = 1280 & & GetFrameBufferHeight ( ) > = 960 )
return true ;
else
return false ;
}
bool Renderer : : AllowCustom ( )
{
if ( GetCustomWidth ( ) < = GetFrameBufferWidth ( ) & & GetCustomHeight ( ) < = GetFrameBufferHeight ( ) )
return true ;
else
return false ;
}
// Return the framebuffer size
int Renderer : : GetFrameBufferWidth ( )
{
return m_FrameBufferWidth ;
}
int Renderer : : GetFrameBufferHeight ( )
{
return m_FrameBufferHeight ;
}
// Return the custom resolution
int Renderer : : GetCustomWidth ( )
{
return m_CustomWidth ;
}
int Renderer : : GetCustomHeight ( )
{
return m_CustomHeight ;
}
// Return the rendering target width and height
2009-02-23 07:23:34 +00:00
int Renderer : : GetTargetWidth ( )
{
2009-09-13 08:21:35 +00:00
return ( g_ActiveConfig . bNativeResolution | | g_ActiveConfig . b2xResolution ) ?
( g_ActiveConfig . bNativeResolution ? EFB_WIDTH : EFB_WIDTH * 2 ) : m_CustomWidth ;
2009-02-23 07:23:34 +00:00
}
int Renderer : : GetTargetHeight ( )
{
2009-09-13 08:21:35 +00:00
return ( g_ActiveConfig . bNativeResolution | | g_ActiveConfig . b2xResolution ) ?
( g_ActiveConfig . bNativeResolution ? EFB_HEIGHT : EFB_HEIGHT * 2 ) : m_CustomHeight ;
2009-02-28 16:33:59 +00:00
}
float Renderer : : GetTargetScaleX ( )
{
2009-02-28 19:02:37 +00:00
return ( float ) GetTargetWidth ( ) / ( float ) EFB_WIDTH ;
2009-02-28 16:33:59 +00:00
}
float Renderer : : GetTargetScaleY ( )
{
2009-02-28 19:02:37 +00:00
return ( float ) GetTargetHeight ( ) / ( float ) EFB_HEIGHT ;
2009-02-23 07:23:34 +00:00
}
2009-07-15 00:51:24 +00:00
TargetRectangle Renderer : : ConvertEFBRectangle ( const EFBRectangle & rc )
{
2009-09-03 20:37:35 +00:00
return g_framebufferManager . ConvertEFBRectangle ( rc ) ;
2009-02-23 07:23:34 +00:00
}
2009-09-03 19:24:16 +00:00
void Renderer : : ResetAPIState ( )
2009-02-23 07:23:34 +00:00
{
2009-02-28 19:02:37 +00:00
// Gets us to a reasonably sane state where it's possible to do things like
// image copies with textured quads, etc.
2009-09-26 12:39:12 +00:00
VertexShaderCache : : DisableShader ( ) ;
PixelShaderCache : : DisableShader ( ) ;
2009-07-15 00:51:24 +00:00
2009-02-23 07:23:34 +00:00
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
glDepthMask ( GL_FALSE ) ;
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
}
2009-06-26 08:57:53 +00:00
void UpdateViewport ( ) ;
2009-09-03 20:37:35 +00:00
void Renderer : : ReinitView ( )
{
}
2009-09-03 19:24:16 +00:00
void Renderer : : RestoreAPIState ( )
2009-02-23 07:23:34 +00:00
{
2009-02-28 19:02:37 +00:00
// Gets us back into a more game-like state.
2009-06-26 08:57:53 +00:00
UpdateViewport ( ) ;
2009-06-22 09:31:30 +00:00
if ( bpmem . genMode . cullmode > 0 ) glEnable ( GL_CULL_FACE ) ;
if ( bpmem . zmode . testenable ) glEnable ( GL_DEPTH_TEST ) ;
if ( bpmem . zmode . updateenable ) glDepthMask ( GL_TRUE ) ;
2009-02-23 07:23:34 +00:00
2009-03-05 23:11:13 +00:00
glEnable ( GL_SCISSOR_TEST ) ;
SetScissorRect ( ) ;
2009-02-23 07:23:34 +00:00
SetColorMask ( ) ;
SetBlendMode ( true ) ;
2009-03-05 23:11:13 +00:00
2009-09-26 12:39:12 +00:00
VertexShaderCache : : EnableShader ( 0 ) ;
PixelShaderCache : : EnableShader ( 0 ) ;
2009-02-23 07:23:34 +00:00
}
void Renderer : : SetColorMask ( )
{
2009-10-25 02:35:21 +00:00
GLenum ColorMask = ( bpmem . blendmode . colorupdate ) ? GL_TRUE : GL_FALSE ;
GLenum AlphaMask = ( bpmem . blendmode . alphaupdate ) ? GL_TRUE : G L_FALSE ;
glColorMask ( ColorMask , ColorMask , ColorMask , AlphaMask ) ;
2009-02-23 07:23:34 +00:00
}
void Renderer : : SetBlendMode ( bool forceUpdate )
{
// blend mode bit mask
// 0 - blend enable
// 2 - reverse subtract enable (else add)
// 3-5 - srcRGB function
// 6-8 - dstRGB function
2009-06-22 09:31:30 +00:00
u32 newval = bpmem . blendmode . subtract < < 2 ;
2009-02-23 07:23:34 +00:00
2009-06-22 09:31:30 +00:00
if ( bpmem . blendmode . subtract ) {
2009-03-16 02:47:48 +00:00
newval | = 0x0049 ; // enable blending src 1 dst 1
2009-06-22 09:31:30 +00:00
} else if ( bpmem . blendmode . blendenable ) {
2009-03-16 02:47:48 +00:00
newval | = 1 ; // enable blending
2009-06-22 09:31:30 +00:00
newval | = bpmem . blendmode . srcfactor < < 3 ;
newval | = bpmem . blendmode . dstfactor < < 6 ;
2009-02-23 07:23:34 +00:00
}
2009-03-16 02:47:48 +00:00
2009-02-23 07:23:34 +00:00
u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode ;
if ( changes & 1 ) {
2009-03-16 02:47:48 +00:00
// blend enable change
2009-03-05 23:11:13 +00:00
( newval & 1 ) ? glEnable ( GL_BLEND ) : glDisable ( GL_BLEND ) ;
2009-02-23 07:23:34 +00:00
}
2009-03-16 02:47:48 +00:00
if ( changes & 4 ) {
// subtract enable change
glBlendEquation ( newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD ) ;
2009-02-23 07:23:34 +00:00
}
2009-03-16 02:47:48 +00:00
if ( changes & 0x1F8 ) {
// blend RGB change
glBlendFunc ( glSrcFactors [ ( newval > > 3 ) & 7 ] , glDestFactors [ ( newval > > 6 ) & 7 ] ) ;
2009-02-23 07:23:34 +00:00
}
s_blendMode = newval ;
}
2009-07-15 00:51:24 +00:00
u32 Renderer : : AccessEFB ( EFBAccessType type , int x , int y )
{
2010-01-07 20:01:41 +00:00
if ( ! g_ActiveConfig . bEFBAccessEnable )
return 0 ;
2009-07-15 00:51:24 +00:00
// Get the rectangular target region covered by the EFB pixel.
EFBRectangle efbPixelRc ;
efbPixelRc . left = x ;
efbPixelRc . top = y ;
efbPixelRc . right = x + 1 ;
efbPixelRc . bottom = y + 1 ;
TargetRectangle targetPixelRc = Renderer : : ConvertEFBRectangle ( efbPixelRc ) ;
2009-08-22 13:22:35 +00:00
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
2009-07-15 00:51:24 +00:00
switch ( type )
{
case PEEK_Z :
{
if ( s_MSAASamples > 1 )
{
2009-07-16 09:06:16 +00:00
// Resolve our rectangle.
2009-09-03 20:37:35 +00:00
g_framebufferManager . GetEFBDepthTexture ( efbPixelRc ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetResolvedFramebuffer ( ) ) ;
2009-07-15 00:51:24 +00:00
}
// Sample from the center of the target region.
int srcX = ( targetPixelRc . left + targetPixelRc . right ) / 2 ;
int srcY = ( targetPixelRc . top + targetPixelRc . bottom ) / 2 ;
2009-07-15 15:09:20 +00:00
u32 z = 0 ;
2009-07-15 00:51:24 +00:00
glReadPixels ( srcX , srcY , 1 , 1 , GL_DEPTH_COMPONENT , GL_UNSIGNED_INT , & z ) ;
GL_REPORT_ERRORD ( ) ;
// Scale the 32-bit value returned by glReadPixels to a 24-bit
// value (GC uses a 24-bit Z-buffer).
2009-08-25 18:30:15 +00:00
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
2009-07-15 00:51:24 +00:00
return z > > 8 ;
}
case POKE_Z :
// TODO: Implement
break ;
2009-08-22 13:22:35 +00:00
case PEEK_COLOR : // GXPeekARGB
2009-07-16 09:06:16 +00:00
{
2009-08-22 13:22:35 +00:00
// Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
// Tested in Killer 7, the first 8bits represent the alpha value which is used to
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
// Wind Waker is also using it for the pictograph to determine the color of each pixel
2009-07-16 22:45:18 +00:00
2009-07-16 09:06:16 +00:00
if ( s_MSAASamples > 1 )
{
// Resolve our rectangle.
2009-09-03 20:37:35 +00:00
g_framebufferManager . GetEFBColorTexture ( efbPixelRc ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetResolvedFramebuffer ( ) ) ;
2009-07-16 09:06:16 +00:00
}
2009-07-15 15:09:20 +00:00
2009-07-16 09:06:16 +00:00
// Sample from the center of the target region.
int srcX = ( targetPixelRc . left + targetPixelRc . right ) / 2 ;
int srcY = ( targetPixelRc . top + targetPixelRc . bottom ) / 2 ;
2009-07-15 15:09:20 +00:00
2009-08-22 13:22:35 +00:00
// Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format.
2009-07-16 09:06:16 +00:00
u32 color = 0 ;
2009-08-22 13:22:35 +00:00
glReadPixels ( srcX , srcY , 1 , 1 , GL_BGRA , GL_UNSIGNED_INT_8_8_8_8_REV , & color ) ;
2009-07-16 09:06:16 +00:00
GL_REPORT_ERRORD ( ) ;
2009-07-15 15:09:20 +00:00
2009-08-22 13:22:35 +00:00
return color ;
2009-07-16 09:06:16 +00:00
}
2009-07-15 00:51:24 +00:00
case POKE_COLOR :
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
// the exact location. Note: EFB pokes are susceptible to Z-buffering
// and perhaps blending.
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
break ;
}
return 0 ;
}
2009-06-07 12:06:15 +00:00
// Function: This function handles the OpenGL glScissor() function
2009-09-08 16:07:13 +00:00
// ----------------------------
2009-02-23 07:23:34 +00:00
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
// case 0x52 > SetScissorRect()
2009-09-08 16:07:13 +00:00
// ----------------------------
2009-06-22 09:31:30 +00:00
// bpmem.scissorTL.x, y = 342x342
// bpmem.scissorBR.x, y = 981x821
2009-02-23 07:23:34 +00:00
// Renderer::GetTargetHeight() = the fixed ini file setting
// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
// therefore the width and height are (scissorBR + 1) - scissorTL
bool Renderer : : SetScissorRect ( )
{
2009-06-22 09:31:30 +00:00
int xoff = bpmem . scissorOffset . x * 2 - 342 ;
int yoff = bpmem . scissorOffset . y * 2 - 342 ;
2009-02-28 16:33:59 +00:00
float MValueX = GetTargetScaleX ( ) ;
float MValueY = GetTargetScaleY ( ) ;
2009-06-22 09:31:30 +00:00
float rc_left = ( float ) bpmem . scissorTL . x - xoff - 342 ; // left = 0
2009-02-23 07:23:34 +00:00
rc_left * = MValueX ;
if ( rc_left < 0 ) rc_left = 0 ;
2009-06-22 09:31:30 +00:00
float rc_top = ( float ) bpmem . scissorTL . y - yoff - 342 ; // right = 0
2009-02-23 07:23:34 +00:00
rc_top * = MValueY ;
if ( rc_top < 0 ) rc_top = 0 ;
2009-06-22 09:31:30 +00:00
float rc_right = ( float ) bpmem . scissorBR . x - xoff - 341 ; // right = 640
2009-02-23 07:23:34 +00:00
rc_right * = MValueX ;
2009-02-28 19:02:37 +00:00
if ( rc_right > EFB_WIDTH * MValueX ) rc_right = EFB_WIDTH * MValueX ;
2009-02-23 07:23:34 +00:00
2009-06-22 09:31:30 +00:00
float rc_bottom = ( float ) bpmem . scissorBR . y - yoff - 341 ; // bottom = 480
2009-02-23 07:23:34 +00:00
rc_bottom * = MValueY ;
2009-02-28 19:02:37 +00:00
if ( rc_bottom > EFB_HEIGHT * MValueY ) rc_bottom = EFB_HEIGHT * MValueY ;
2009-02-23 07:23:34 +00:00
2009-11-23 14:08:08 +00:00
if ( rc_left > rc_right )
{
int temp = rc_right ;
rc_right = rc_left ;
rc_left = temp ;
}
if ( rc_top > rc_bottom )
{
int temp = rc_bottom ;
rc_bottom = rc_top ;
rc_top = temp ;
}
2009-02-23 07:23:34 +00:00
// Check that the coordinates are good
if ( rc_right > = rc_left & & rc_bottom > = rc_top )
{
glScissor (
( int ) rc_left , // x = 0 for example
Renderer : : GetTargetHeight ( ) - ( int ) ( rc_bottom ) , // y = 0 for example
2009-03-05 23:11:13 +00:00
( int ) ( rc_right - rc_left ) , // width = 640 for example
( int ) ( rc_bottom - rc_top ) // height = 480 for example
2009-02-23 07:23:34 +00:00
) ;
return true ;
}
return false ;
}
2009-07-15 00:51:24 +00:00
void Renderer : : ClearScreen ( const EFBRectangle & rc , bool colorEnable , bool alphaEnable , bool zEnable , u32 color , u32 z )
{
// Update the view port for clearing the picture
glViewport ( 0 , 0 , Renderer : : GetTargetWidth ( ) , Renderer : : GetTargetHeight ( ) ) ;
TargetRectangle targetRc = Renderer : : ConvertEFBRectangle ( rc ) ;
// Always set the scissor in case it was set by the game and has not been reset
glScissor ( targetRc . left , targetRc . bottom , targetRc . GetWidth ( ) , targetRc . GetHeight ( ) ) ;
VertexShaderManager : : SetViewportChanged ( ) ;
GLbitfield bits = 0 ;
if ( colorEnable )
{
bits | = GL_COLOR_BUFFER_BIT ;
glClearColor (
( ( color > > 16 ) & 0xFF ) / 255.0f ,
( ( color > > 8 ) & 0xFF ) / 255.0f ,
( color & 0xFF ) / 255.0f ,
( alphaEnable ? ( ( color > > 24 ) & 0xFF ) / 255.0f : 1.0f )
) ;
}
if ( zEnable )
{
bits | = GL_DEPTH_BUFFER_BIT ;
glClearDepth ( ( z & 0xFFFFFF ) / float ( 0xFFFFFF ) ) ;
}
glDrawBuffer ( GL_COLOR_ATTACHMENT0_EXT ) ;
glClear ( bits ) ;
}
void Renderer : : RenderToXFB ( u32 xfbAddr , u32 fbWidth , u32 fbHeight , const EFBRectangle & sourceRc )
2009-06-26 08:57:53 +00:00
{
2009-08-08 01:39:56 +00:00
s_skipSwap = g_bSkipCurrentFrame ;
2009-07-11 02:34:16 +00:00
// If we're about to write to a requested XFB, make sure the previous
2009-06-29 07:30:48 +00:00
// contents make it to the screen first.
2009-07-11 02:34:16 +00:00
VideoFifo_CheckSwapRequestAt ( xfbAddr , fbWidth , fbHeight ) ;
2009-09-03 20:37:35 +00:00
g_framebufferManager . CopyToXFB ( xfbAddr , fbWidth , fbHeight , sourceRc ) ;
2009-08-04 22:36:50 +00:00
// XXX: Without the VI, how would we know what kind of field this is? So
// just use progressive.
2009-09-13 08:21:35 +00:00
if ( ! g_ActiveConfig . bUseXFB )
2009-08-31 17:47:17 +00:00
{
// TODO: Find better name for this because I don't know if it means what it says.
g_VideoInitialize . pCopiedToXFB ( false ) ;
2009-08-25 18:30:15 +00:00
Renderer : : Swap ( xfbAddr , FIELD_PROGRESSIVE , fbWidth , fbHeight ) ;
2009-08-31 17:47:17 +00:00
}
2009-06-26 08:57:53 +00:00
}
2009-06-29 07:30:48 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2009-07-11 02:34:16 +00:00
void Renderer : : Swap ( u32 xfbAddr , FieldType field , u32 fbWidth , u32 fbHeight )
2009-02-28 16:33:59 +00:00
{
2009-09-13 08:21:35 +00:00
if ( s_skipSwap )
2009-08-08 01:39:56 +00:00
return ;
2009-09-03 20:37:35 +00:00
const XFBSource * xfbSource = g_framebufferManager . GetXFBSource ( xfbAddr , fbWidth , fbHeight ) ;
2009-06-29 07:30:48 +00:00
if ( ! xfbSource )
{
WARN_LOG ( VIDEO , " Failed to get video for this frame " ) ;
return ;
}
2009-02-28 16:33:59 +00:00
OpenGL_Update ( ) ; // just updates the render window position and the backbuffer size
DVSTARTPROFILE ( ) ;
2009-02-23 07:23:34 +00:00
2009-09-03 19:24:16 +00:00
ResetAPIState ( ) ;
2009-02-28 16:33:59 +00:00
2009-07-15 00:51:24 +00:00
TargetRectangle back_rc ;
2009-09-13 08:21:35 +00:00
ComputeDrawRectangle ( OpenGL_GetBackbufferWidth ( ) , OpenGL_GetBackbufferHeight ( ) , true , & back_rc ) ;
2009-02-23 07:23:34 +00:00
2009-07-15 00:51:24 +00:00
TargetRectangle sourceRc ;
2009-07-02 01:49:28 +00:00
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bAutoScale | | g_ActiveConfig . bUseXFB )
2009-03-08 19:19:51 +00:00
{
2009-07-15 00:51:24 +00:00
sourceRc = xfbSource - > sourceRc ;
2009-03-08 19:19:51 +00:00
}
else
{
2009-07-15 00:51:24 +00:00
sourceRc . left = 0 ;
sourceRc . top = xfbSource - > texHeight ;
sourceRc . right = xfbSource - > texWidth ;
sourceRc . bottom = 0 ;
2009-02-28 16:33:59 +00:00
}
2009-07-02 01:49:28 +00:00
2009-09-13 08:21:35 +00:00
int yOffset = ( g_ActiveConfig . bUseXFB & & field = = FIELD_LOWER ) ? - 1 : 0 ;
2009-07-15 00:51:24 +00:00
sourceRc . top - = yOffset ;
sourceRc . bottom - = yOffset ;
2009-02-23 07:23:34 +00:00
2009-06-08 02:48:38 +00:00
// Tell the OSD Menu about the current internal resolution
2009-06-29 20:54:47 +00:00
OSDInternalW = xfbSource - > sourceRc . GetWidth ( ) ; OSDInternalH = xfbSource - > sourceRc . GetHeight ( ) ;
2009-06-08 02:48:38 +00:00
2009-06-08 18:34:24 +00:00
// Make sure that the wireframe setting doesn't screw up the screen copy.
2009-03-22 13:25:05 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
2009-06-26 08:57:53 +00:00
// Textured triangles are necessary because of post-processing shaders
2009-02-28 19:02:37 +00:00
2009-06-26 08:57:53 +00:00
// Disable all other stages
for ( int i = 1 ; i < 8 ; + + i )
TextureMngr : : DisableStage ( i ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// Update GLViewPort
2009-07-15 00:51:24 +00:00
glViewport ( back_rc . left , back_rc . bottom , back_rc . GetWidth ( ) , back_rc . GetHeight ( ) ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
GL_REPORT_ERRORD ( ) ;
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// Copy the framebuffer to screen.
// Render to the real buffer now.
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , 0 ) ; // switch to the window backbuffer
2009-03-08 19:19:51 +00:00
2009-06-26 08:57:53 +00:00
// Texture map s_xfbTexture onto the main buffer
glActiveTexture ( GL_TEXTURE0 ) ;
glEnable ( GL_TEXTURE_RECTANGLE_ARB ) ;
2009-06-29 07:30:48 +00:00
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB , xfbSource - > texture ) ;
2009-06-26 08:57:53 +00:00
// Use linear filtering.
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
// We must call ApplyShader here even if no post proc is selected - it takes
// care of disabling it in that case. It returns false in case of no post processing.
2009-07-15 00:51:24 +00:00
if ( PostProcessing : : ApplyShader ( ) )
2009-06-26 08:57:53 +00:00
{
glBegin ( GL_QUADS ) ;
2009-07-15 00:51:24 +00:00
glTexCoord2f ( sourceRc . left , sourceRc . bottom ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 0 ) ; glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( sourceRc . left , sourceRc . top ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 1 ) ; glVertex2f ( - 1 , 1 ) ;
glTexCoord2f ( sourceRc . right , sourceRc . top ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 1 ) ; glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( sourceRc . right , sourceRc . bottom ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 0 ) ; glVertex2f ( 1 , - 1 ) ;
2009-06-26 08:57:53 +00:00
glEnd ( ) ;
2009-09-26 12:39:12 +00:00
PixelShaderCache : : DisableShader ( ) ; ;
2009-03-08 19:19:51 +00:00
}
2009-07-15 00:51:24 +00:00
else
2009-06-26 08:57:53 +00:00
{
glBegin ( GL_QUADS ) ;
2009-07-15 00:51:24 +00:00
glTexCoord2f ( sourceRc . left , sourceRc . bottom ) ; glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( sourceRc . left , sourceRc . top ) ; glVertex2f ( - 1 , 1 ) ;
glTexCoord2f ( sourceRc . right , sourceRc . top ) ; glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( sourceRc . right , sourceRc . bottom ) ; glVertex2f ( 1 , - 1 ) ;
2009-06-26 08:57:53 +00:00
glEnd ( ) ;
}
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB , 0 ) ;
TextureMngr : : DisableStage ( 0 ) ;
2009-02-23 07:23:34 +00:00
2009-03-22 13:25:05 +00:00
// Wireframe
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bWireFrame )
2009-03-22 13:25:05 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
2009-06-08 00:44:48 +00:00
// Save screenshot
if ( s_bScreenshot )
2009-06-07 11:51:53 +00:00
{
2009-06-29 20:54:47 +00:00
if ( ! s_tempScreenshotFramebuffer )
glGenFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_tempScreenshotFramebuffer ) ;
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , xfbSource - > texture , 0 ) ;
2009-06-07 11:51:53 +00:00
2009-06-08 00:44:48 +00:00
s_criticalScreenshot . Enter ( ) ;
2009-06-07 11:51:53 +00:00
// Save screenshot
2009-07-15 00:51:24 +00:00
SaveRenderTarget ( s_sScreenshotName . c_str ( ) , xfbSource - > sourceRc . GetWidth ( ) , xfbSource - > sourceRc . GetHeight ( ) , yOffset ) ;
2009-06-07 11:51:53 +00:00
// Reset settings
s_sScreenshotName = " " ;
s_bScreenshot = false ;
s_criticalScreenshot . Leave ( ) ;
2009-06-29 20:54:47 +00:00
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , 0 , 0 ) ;
2009-09-03 20:37:35 +00:00
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetEFBFramebuffer ( ) ) ;
2009-06-07 11:51:53 +00:00
}
2009-03-28 21:07:16 +00:00
// Frame dumps are handled a little differently in Windows
# ifdef _WIN32
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bDumpFrames )
2009-06-08 10:16:08 +00:00
{
2009-06-29 20:54:47 +00:00
if ( ! s_tempScreenshotFramebuffer )
glGenFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_tempScreenshotFramebuffer ) ;
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , xfbSource - > texture , 0 ) ;
2009-06-08 10:16:08 +00:00
2009-03-28 21:07:16 +00:00
s_criticalScreenshot . Enter ( ) ;
2009-06-29 20:54:47 +00:00
int w = xfbSource - > sourceRc . GetWidth ( ) ;
int h = xfbSource - > sourceRc . GetHeight ( ) ;
2009-07-29 00:49:12 +00:00
2009-03-28 21:07:16 +00:00
u8 * data = ( u8 * ) malloc ( 3 * w * h ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2009-07-29 00:49:12 +00:00
glReadPixels ( 0 , Renderer : : GetTargetHeight ( ) - h + yOffset , w , h , GL_BGR , GL_UNSIGNED_BYTE , data ) ;
2010-01-20 12:26:47 +00:00
if ( glGetError ( ) = = GL_NO_ERROR & & w > 0 & & h > 0 )
2009-04-03 14:35:49 +00:00
{
if ( ! s_bLastFrameDumped )
{
2009-09-06 19:30:24 +00:00
s_bAVIDumping = AVIDump : : Start ( EmuWindow : : GetParentWnd ( ) , w , h ) ;
2009-04-03 14:35:49 +00:00
if ( ! s_bAVIDumping )
2009-06-08 10:16:08 +00:00
OSD : : AddMessage ( " AVIDump Start failed " , 2000 ) ;
2009-04-03 14:35:49 +00:00
else
{
2009-06-08 10:16:08 +00:00
OSD : : AddMessage ( StringFromFormat (
" Dumping Frames to \" %s/framedump0.avi \" (%dx%d RGB24) " , FULL_FRAMES_DIR , w , h ) . c_str ( ) , 2000 ) ;
2009-03-28 21:07:16 +00:00
}
}
2009-04-03 14:35:49 +00:00
if ( s_bAVIDumping )
2009-03-28 21:07:16 +00:00
AVIDump : : AddFrame ( ( char * ) data ) ;
2009-04-03 14:35:49 +00:00
2009-03-28 21:07:16 +00:00
s_bLastFrameDumped = true ;
}
2009-06-08 10:16:08 +00:00
else
{
NOTICE_LOG ( VIDEO , " Error reading framebuffer " ) ;
}
2009-03-28 21:07:16 +00:00
free ( data ) ;
s_criticalScreenshot . Leave ( ) ;
2009-06-29 20:54:47 +00:00
glFramebufferTexture2DEXT ( GL_READ_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT , GL_TEXTURE_RECTANGLE_ARB , 0 , 0 ) ;
2009-09-03 20:37:35 +00:00
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , g_framebufferManager . GetEFBFramebuffer ( ) ) ;
2009-04-03 14:35:49 +00:00
}
else
{
if ( s_bLastFrameDumped & & s_bAVIDumping )
{
2009-03-28 21:07:16 +00:00
AVIDump : : Stop ( ) ;
s_bAVIDumping = false ;
2009-06-08 10:16:08 +00:00
OSD : : AddMessage ( " Stop dumping frames to AVI " , 2000 ) ;
2009-03-28 21:07:16 +00:00
}
s_bLastFrameDumped = false ;
}
# else
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bDumpFrames ) {
2009-03-28 21:07:16 +00:00
s_criticalScreenshot . Enter ( ) ;
char movie_file_name [ 255 ] ;
int w = OpenGL_GetBackbufferWidth ( ) ;
int h = OpenGL_GetBackbufferHeight ( ) ;
u8 * data = ( u8 * ) malloc ( 3 * w * h ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2009-07-29 00:49:12 +00:00
glReadPixels ( 0 , Renderer : : GetTargetHeight ( ) - h , w , h , GL_RGB , GL_UNSIGNED_BYTE , data ) ;
2009-03-28 21:07:16 +00:00
if ( glGetError ( ) = = GL_NO_ERROR ) {
if ( ! s_bLastFrameDumped ) {
sprintf ( movie_file_name , " %s/framedump.raw " , FULL_FRAMES_DIR ) ;
f_pFrameDump = fopen ( movie_file_name , " wb " ) ;
if ( f_pFrameDump = = NULL ) {
PanicAlert ( " Error opening framedump.raw for writing. " ) ;
} else {
char msg [ 255 ] ;
sprintf ( msg , " Dumping Frames to \" %s \" (%dx%d RGB24) " , movie_file_name , w , h ) ;
OSD : : AddMessage ( msg , 2000 ) ;
}
}
if ( f_pFrameDump ! = NULL ) {
FlipImageData ( data , w , h ) ;
fwrite ( data , w * 3 , h , f_pFrameDump ) ;
fflush ( f_pFrameDump ) ;
}
s_bLastFrameDumped = true ;
}
free ( data ) ;
s_criticalScreenshot . Leave ( ) ;
} else {
2009-09-13 10:18:01 +00:00
if ( s_bLastFrameDumped & & f_pFrameDump ! = NULL ) {
2009-03-28 21:07:16 +00:00
fclose ( f_pFrameDump ) ;
f_pFrameDump = NULL ;
}
s_bLastFrameDumped = false ;
}
# endif
2009-02-23 07:23:34 +00:00
// Place messages on the picture, then copy it to the screen
2009-06-07 12:06:15 +00:00
// ---------------------------------------------------------------------
// Count FPS.
2009-09-08 16:07:13 +00:00
// -------------
2009-06-07 12:06:15 +00:00
static int fpscount = 0 ;
static unsigned long lasttime ;
+ + fpscount ;
2010-01-21 21:27:52 +00:00
if ( Common : : Timer : : GetTimeMs ( ) - lasttime > 1000 )
2009-06-07 12:06:15 +00:00
{
2010-01-21 21:27:52 +00:00
lasttime = Common : : Timer : : GetTimeMs ( ) ;
2009-06-07 12:06:15 +00:00
s_fps = fpscount - 1 ;
fpscount = 0 ;
}
// ---------------------------------------------------------------------
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-10-25 02:35:21 +00:00
2009-06-07 12:06:15 +00:00
DrawDebugText ( ) ;
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-09-03 20:37:35 +00:00
// Get the status of the Blend mode
GLboolean blend_enabled = glIsEnabled ( GL_BLEND ) ;
glDisable ( GL_BLEND ) ;
2009-06-07 12:06:15 +00:00
OSD : : DrawMessages ( ) ;
2009-09-03 20:37:35 +00:00
if ( blend_enabled )
glEnable ( GL_BLEND ) ;
2009-09-26 12:39:12 +00:00
GL_REPORT_ERRORD ( ) ;
2009-06-07 12:06:15 +00:00
# if defined(DVPROFILE)
if ( g_bWriteProfile ) {
//g_bWriteProfile = 0;
static int framenum = 0 ;
const int UPDATE_FRAMES = 8 ;
if ( + + framenum > = UPDATE_FRAMES ) {
DVProfWrite ( " prof.txt " , UPDATE_FRAMES ) ;
DVProfClear ( ) ;
framenum = 0 ;
}
}
# endif
2009-08-08 01:39:56 +00:00
// Copy the rendered frame to the real window
2009-06-07 12:06:15 +00:00
OpenGL_SwapBuffers ( ) ;
2009-08-08 01:39:56 +00:00
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-08-08 01:39:56 +00:00
2009-06-08 20:07:20 +00:00
// Clear framebuffer
2009-10-21 00:01:07 +00:00
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
2009-06-07 12:06:15 +00:00
2009-08-08 01:39:56 +00:00
GL_REPORT_ERRORD ( ) ;
2009-06-07 12:06:15 +00:00
2010-01-17 17:44:09 +00:00
// Clean out old stuff from caches. It's not worth it to clean out the shader caches.
2009-08-09 11:03:58 +00:00
DLCache : : ProgressiveCleanup ( ) ;
2009-06-07 12:06:15 +00:00
TextureMngr : : ProgressiveCleanup ( ) ;
frameCount + + ;
// New frame
stats . ResetFrame ( ) ;
// Render to the framebuffer.
2009-09-03 20:37:35 +00:00
g_framebufferManager . SetFramebuffer ( 0 ) ;
2009-06-07 12:06:15 +00:00
GL_REPORT_ERRORD ( ) ;
2009-02-23 07:23:34 +00:00
2009-09-13 17:46:33 +00:00
RestoreAPIState ( ) ;
GL_REPORT_ERRORD ( ) ;
g_Config . iSaveTargetId = 0 ;
bool last_copy_efb_to_ram = g_ActiveConfig . bCopyEFBToRAM ;
UpdateActiveConfig ( ) ;
if ( last_copy_efb_to_ram ! = g_ActiveConfig . bCopyEFBToRAM )
TextureMngr : : ClearRenderTargets ( ) ;
// For testing zbuffer targets.
// Renderer::SetZBufferRender();
// SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, GetTargetWidth(), GetTargetHeight());
}
2009-06-07 12:06:15 +00:00
// Create On-Screen-Messages
2009-02-28 16:33:59 +00:00
void Renderer : : DrawDebugText ( )
2009-02-23 07:23:34 +00:00
{
2009-03-08 19:19:51 +00:00
// Reset viewport for drawing text
glViewport ( 0 , 0 , OpenGL_GetBackbufferWidth ( ) , OpenGL_GetBackbufferHeight ( ) ) ;
2009-02-28 16:33:59 +00:00
// Draw various messages on the screen, like FPS, statistics, etc.
2009-02-23 07:23:34 +00:00
char debugtext_buffer [ 8192 ] ;
char * p = debugtext_buffer ;
p [ 0 ] = 0 ;
2009-04-03 14:35:49 +00:00
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bShowFPS )
2009-02-23 07:23:34 +00:00
p + = sprintf ( p , " FPS: %d \n " , s_fps ) ;
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bShowEFBCopyRegions )
2009-03-16 07:54:44 +00:00
{
2009-03-17 06:04:57 +00:00
// Store Line Size
2009-03-21 16:04:44 +00:00
GLfloat lSize ;
glGetFloatv ( GL_LINE_WIDTH , & lSize ) ;
2009-03-17 06:04:57 +00:00
// Set Line Size
2009-04-03 21:32:10 +00:00
glLineWidth ( 3.0f ) ;
2009-03-16 07:54:44 +00:00
glBegin ( GL_LINES ) ;
2009-03-17 06:04:57 +00:00
// Draw EFB copy regions rectangles
2009-07-15 00:51:24 +00:00
for ( std : : vector < EFBRectangle > : : const_iterator it = stats . efb_regions . begin ( ) ; it ! = stats . efb_regions . end ( ) ; + + it )
2009-03-16 07:54:44 +00:00
{
2009-07-28 05:02:47 +00:00
GLfloat halfWidth = EFB_WIDTH / 2.0f ;
GLfloat halfHeight = EFB_HEIGHT / 2.0f ;
2009-03-21 16:04:44 +00:00
GLfloat x = ( GLfloat ) - 1.0f + ( ( GLfloat ) it - > left / halfWidth ) ;
GLfloat y = ( GLfloat ) 1.0f - ( ( GLfloat ) it - > top / halfHeight ) ;
GLfloat x2 = ( GLfloat ) - 1.0f + ( ( GLfloat ) it - > right / halfWidth ) ;
GLfloat y2 = ( GLfloat ) 1.0f - ( ( GLfloat ) it - > bottom / halfHeight ) ;
2009-03-16 07:54:44 +00:00
2009-03-17 06:04:57 +00:00
// Draw shadow of rect
2009-03-16 07:54:44 +00:00
glColor3f ( 0.0f , 0.0f , 0.0f ) ;
2009-04-03 21:32:10 +00:00
glVertex2f ( x , y - 0.01 ) ; glVertex2f ( x2 , y - 0.01 ) ;
glVertex2f ( x , y2 - 0.01 ) ; glVertex2f ( x2 , y2 - 0.01 ) ;
glVertex2f ( x + 0.005 , y ) ; glVertex2f ( x + 0.005 , y2 ) ;
glVertex2f ( x2 + 0.005 , y ) ; glVertex2f ( x2 + 0.005 , y2 ) ;
2009-03-16 07:54:44 +00:00
2009-03-17 06:04:57 +00:00
// Draw rect
2009-03-16 07:54:44 +00:00
glColor3f ( 0.0f , 1.0f , 1.0f ) ;
2009-04-03 21:32:10 +00:00
glVertex2f ( x , y ) ; glVertex2f ( x2 , y ) ;
glVertex2f ( x , y2 ) ; glVertex2f ( x2 , y2 ) ;
glVertex2f ( x , y ) ; glVertex2f ( x , y2 ) ;
glVertex2f ( x2 , y ) ; glVertex2f ( x2 , y2 ) ;
2009-03-16 07:54:44 +00:00
}
glEnd ( ) ;
2009-03-17 06:04:57 +00:00
// Restore Line Size
2009-03-21 16:04:44 +00:00
glLineWidth ( lSize ) ;
2009-03-17 06:04:57 +00:00
// Clear stored regions
2009-03-16 07:54:44 +00:00
stats . efb_regions . clear ( ) ;
}
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bOverlayStats )
2009-03-16 07:54:44 +00:00
{
2009-09-13 08:21:35 +00:00
p = Statistics : : ToString ( p ) ;
2009-02-23 07:23:34 +00:00
}
2009-09-13 08:21:35 +00:00
if ( g_ActiveConfig . bOverlayProjStats )
2009-02-23 07:23:34 +00:00
{
2009-09-13 08:21:35 +00:00
p = Statistics : : ToStringProj ( p ) ;
2009-02-23 07:23:34 +00:00
}
// Render a shadow, and then the text.
2009-09-13 08:21:35 +00:00
if ( p ! = debugtext_buffer )
{
Renderer : : RenderText ( debugtext_buffer , 21 , 21 , 0xDD000000 ) ;
Renderer : : RenderText ( debugtext_buffer , 20 , 20 , 0xFF00FFFF ) ;
}
2009-06-08 02:48:38 +00:00
// OSD Menu messages
2009-10-22 20:22:50 +00:00
if ( g_ActiveConfig . bOSDHotKey )
2009-06-08 02:48:38 +00:00
{
2009-10-22 20:22:50 +00:00
if ( OSDChoice > 0 )
{
2010-01-21 21:27:52 +00:00
OSDTime = Common : : Timer : : GetTimeMs ( ) + 3000 ;
2009-10-22 20:22:50 +00:00
OSDChoice = - OSDChoice ;
}
2010-01-21 21:27:52 +00:00
if ( ( u32 ) OSDTime > Common : : Timer : : GetTimeMs ( ) )
2009-10-22 20:22:50 +00:00
{
std : : string T1 = " " , T2 = " " ;
std : : vector < std : : string > T0 ;
int W , H ;
sscanf ( g_ActiveConfig . cInternalRes , " %dx%d " , & W , & H ) ;
std : : string OSDM1 =
g_ActiveConfig . bNativeResolution | | g_ActiveConfig . b2xResolution ?
( g_ActiveConfig . bNativeResolution ?
StringFromFormat ( " %i x %i (native) " , OSDInternalW , OSDInternalH )
: StringFromFormat ( " %i x %i (2x) " , OSDInternalW , OSDInternalH ) )
: StringFromFormat ( " %i x %i (custom) " , W , H ) ;
2010-01-13 21:11:02 +00:00
std : : string OSDM21 = " " ;
// !(g_ActiveConfig.bKeepAR43 || g_ActiveConfig.bKeepAR169) ? "-": (g_ActiveConfig.bKeepAR43 ? "4:3" : "16:9");
2009-10-22 20:22:50 +00:00
std : : string OSDM22 =
g_ActiveConfig . bCrop ? " (crop) " : " " ;
std : : string OSDM31 =
g_ActiveConfig . bCopyEFBToRAM ? " RAM " : " Texture " ;
std : : string OSDM32 =
g_ActiveConfig . bEFBCopyDisable ? " No " : " Yes " ;
// If there is more text than this we will have a collission
if ( g_ActiveConfig . bShowFPS )
{ T1 + = " \n \n " ; T2 + = " \n \n " ; }
// The rows
T0 . push_back ( StringFromFormat ( " 3: Internal Resolution: %s \n " , OSDM1 . c_str ( ) ) ) ;
T0 . push_back ( StringFromFormat ( " 4: Lock Aspect Ratio: %s%s \n " , OSDM21 . c_str ( ) , OSDM22 . c_str ( ) ) ) ;
T0 . push_back ( StringFromFormat ( " 5: Copy Embedded Framebuffer to %s: %s \n " , OSDM31 . c_str ( ) , OSDM32 . c_str ( ) ) ) ;
T0 . push_back ( StringFromFormat ( " 6: Fog: %s \n " , g_ActiveConfig . bDisableFog ? " Disabled " : " Enabled " ) ) ;
T0 . push_back ( StringFromFormat ( " 7: Material Lighting: %s \n " , g_ActiveConfig . bDisableLighting ? " Disabled " : " Enabled " ) ) ;
// The latest changed setting in yellow
T1 + = ( OSDChoice = = - 1 ) ? T0 . at ( 0 ) : " \n " ;
T1 + = ( OSDChoice = = - 2 ) ? T0 . at ( 1 ) : " \n " ;
T1 + = ( OSDChoice = = - 3 ) ? T0 . at ( 2 ) : " \n " ;
T1 + = ( OSDChoice = = - 4 ) ? T0 . at ( 3 ) : " \n " ;
T1 + = ( OSDChoice = = - 5 ) ? T0 . at ( 4 ) : " \n " ;
// The other settings in cyan
T2 + = ( OSDChoice ! = - 1 ) ? T0 . at ( 0 ) : " \n " ;
T2 + = ( OSDChoice ! = - 2 ) ? T0 . at ( 1 ) : " \n " ;
T2 + = ( OSDChoice ! = - 3 ) ? T0 . at ( 2 ) : " \n " ;
T2 + = ( OSDChoice ! = - 4 ) ? T0 . at ( 3 ) : " \n " ;
T2 + = ( OSDChoice ! = - 5 ) ? T0 . at ( 4 ) : " \n " ;
// Render a shadow, and then the text
Renderer : : RenderText ( T1 . c_str ( ) , 21 , 21 , 0xDD000000 ) ;
Renderer : : RenderText ( T1 . c_str ( ) , 20 , 20 , 0xFFffff00 ) ;
Renderer : : RenderText ( T2 . c_str ( ) , 21 , 21 , 0xDD000000 ) ;
Renderer : : RenderText ( T2 . c_str ( ) , 20 , 20 , 0xFF00FFFF ) ;
}
2009-06-08 02:48:38 +00:00
}
2009-02-28 16:33:59 +00:00
}
2009-02-23 07:23:34 +00:00
void Renderer : : RenderText ( const char * pstr , int left , int top , u32 color )
{
2009-02-28 16:33:59 +00:00
int nBackbufferWidth = ( int ) OpenGL_GetBackbufferWidth ( ) ;
int nBackbufferHeight = ( int ) OpenGL_GetBackbufferHeight ( ) ;
2009-02-23 07:23:34 +00:00
glColor4f ( ( ( color > > 16 ) & 0xff ) / 255.0f , ( ( color > > 8 ) & 0xff ) / 255.0f ,
( ( color > > 0 ) & 0xff ) / 255.0f , ( ( color > > 24 ) & 0xFF ) / 255.0f ) ;
s_pfont - > printMultilineText ( pstr ,
left * 2.0f / ( float ) nBackbufferWidth - 1 ,
1 - top * 2.0f / ( float ) nBackbufferHeight ,
0 , nBackbufferWidth , nBackbufferHeight ) ;
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-02-23 07:23:34 +00:00
}
2009-06-07 11:51:53 +00:00
// Save screenshot
2009-02-27 03:56:34 +00:00
void Renderer : : SetScreenshot ( const char * filename )
2009-02-23 07:23:34 +00:00
{
2009-02-27 03:56:34 +00:00
s_criticalScreenshot . Enter ( ) ;
s_sScreenshotName = filename ;
s_bScreenshot = true ;
s_criticalScreenshot . Leave ( ) ;
}
2009-02-23 07:23:34 +00:00
2009-07-31 01:55:26 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-07-29 03:11:35 +00:00
THREAD_RETURN TakeScreenshot ( void * pArgs )
{
ScrStrct * threadStruct = ( ScrStrct * ) pArgs ;
// These will contain the final image size
float FloatW = ( float ) threadStruct - > W ;
float FloatH = ( float ) threadStruct - > H ;
// Handle aspect ratio for the final ScrStrct to look exactly like what's on screen.
2010-01-13 21:11:02 +00:00
if ( g_ActiveConfig . iAspectRatio ! = ASPECT_STRETCH )
2009-07-29 03:11:35 +00:00
{
2010-01-13 21:11:02 +00:00
bool use16_9 = g_VideoInitialize . bAutoAspectIs16_9 ;
// Check for force-settings and override.
if ( g_ActiveConfig . iAspectRatio = = ASPECT_FORCE_16_9 )
use16_9 = true ;
else if ( g_ActiveConfig . iAspectRatio = = ASPECT_FORCE_4_3 )
use16_9 = false ;
float Ratio = ( FloatW / FloatH ) / ( ! use16_9 ? ( 4.0f / 3.0f ) : ( 16.0f / 9.0f ) ) ;
2009-07-29 03:11:35 +00:00
// If ratio > 1 the picture is too wide and we have to limit the width.
if ( Ratio > 1 )
FloatW / = Ratio ;
// ratio == 1 or the image is too high, we have to limit the height.
else
FloatH * = Ratio ;
2009-07-31 01:55:26 +00:00
// This is a bit expensive on high resolutions
2009-07-29 03:11:35 +00:00
threadStruct - > img - > Rescale ( ( int ) FloatW , ( int ) FloatH , wxIMAGE_QUALITY_HIGH ) ;
}
// Save the screenshot and finally kill the wxImage object
2009-07-31 01:55:26 +00:00
// This is really expensive when saving to PNG, but not at all when using BMP
2009-07-29 03:11:35 +00:00
threadStruct - > img - > SaveFile ( wxString : : FromAscii ( threadStruct - > filename . c_str ( ) ) , wxBITMAP_TYPE_PNG ) ;
threadStruct - > img - > Destroy ( ) ;
// Show success messages
OSD : : AddMessage ( StringFromFormat ( " Saved %i x %i %s " , ( int ) FloatW , ( int ) FloatH , threadStruct - > filename . c_str ( ) ) . c_str ( ) , 2000 ) ;
2009-07-31 01:55:26 +00:00
delete threadStruct ;
2009-07-29 03:11:35 +00:00
return 0 ;
}
2009-07-31 01:55:26 +00:00
# endif
2009-07-29 03:11:35 +00:00
2009-06-06 13:36:33 +00:00
bool Renderer : : SaveRenderTarget ( const char * filename , int W , int H , int YOffset )
2009-02-27 03:56:34 +00:00
{
2009-06-06 13:36:33 +00:00
u8 * data = ( u8 * ) malloc ( 3 * W * H ) ;
2009-02-27 03:56:34 +00:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2009-07-28 23:38:49 +00:00
glReadPixels ( 0 , Renderer : : GetTargetHeight ( ) - H + YOffset , W , H , GL_RGB , GL_UNSIGNED_BYTE , data ) ;
2009-06-07 21:10:02 +00:00
2009-06-06 17:34:54 +00:00
// Show failure message
2009-02-27 03:56:34 +00:00
if ( glGetError ( ) ! = GL_NO_ERROR )
2009-06-06 17:34:54 +00:00
{
2009-06-06 13:36:33 +00:00
OSD : : AddMessage ( " Error capturing or saving screenshot. " , 2000 ) ;
2009-06-06 17:34:54 +00:00
return false ;
}
2009-06-07 21:10:02 +00:00
2009-06-06 13:36:33 +00:00
// Turn image upside down
FlipImageData ( data , W , H ) ;
2009-06-07 21:10:02 +00:00
2009-03-28 21:07:16 +00:00
# if defined(HAVE_WX) && HAVE_WX
2009-06-06 13:36:33 +00:00
// Create wxImage
2009-07-29 03:11:35 +00:00
wxImage * a = new wxImage ( W , H , data ) ;
2009-07-28 23:38:49 +00:00
2009-07-29 03:11:35 +00:00
if ( scrshotThread )
2009-07-28 23:38:49 +00:00
{
2009-07-29 03:11:35 +00:00
delete scrshotThread ;
scrshotThread = NULL ;
2009-06-07 21:10:02 +00:00
}
2009-06-06 13:36:33 +00:00
2009-07-29 03:11:35 +00:00
ScrStrct * threadStruct = new ScrStrct ;
threadStruct - > filename = std : : string ( filename ) ;
threadStruct - > img = a ;
threadStruct - > H = H ; threadStruct - > W = W ;
scrshotThread = new Common : : Thread ( TakeScreenshot , threadStruct ) ;
2009-07-31 01:55:26 +00:00
# ifdef _WIN32
scrshotThread - > SetPriority ( THREAD_PRIORITY_BELOW_NORMAL ) ;
# endif
2009-03-28 21:07:16 +00:00
bool result = true ;
2009-06-06 13:36:33 +00:00
2009-07-29 03:11:35 +00:00
OSD : : AddMessage ( " Saving Screenshot... " , 2000 ) ;
2009-06-06 13:36:33 +00:00
2009-03-28 21:07:16 +00:00
# else
2009-07-13 06:34:12 +00:00
bool result = SaveTGA ( filename , W , H , data ) ;
2009-07-28 23:38:49 +00:00
free ( data ) ;
2009-07-29 00:49:12 +00:00
# endif
2009-07-28 23:38:49 +00:00
2009-03-28 21:07:16 +00:00
return result ;
}
2009-06-07 11:51:53 +00:00
2009-03-28 21:07:16 +00:00
void Renderer : : FlipImageData ( u8 * data , int w , int h )
{
2009-02-28 16:33:59 +00:00
// Flip image upside down. Damn OpenGL.
for ( int y = 0 ; y < h / 2 ; y + + )
{
for ( int x = 0 ; x < w ; x + + )
{
std : : swap ( data [ ( y * w + x ) * 3 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 ] ) ;
std : : swap ( data [ ( y * w + x ) * 3 + 1 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 + 1 ] ) ;
std : : swap ( data [ ( y * w + x ) * 3 + 2 ] , data [ ( ( h - 1 - y ) * w + x ) * 3 + 2 ] ) ;
2009-02-27 03:56:34 +00:00
}
}
2009-02-23 07:23:34 +00:00
}
2009-09-13 08:21:35 +00:00
// Called from VertexShaderManager
2009-02-23 07:23:34 +00:00
void UpdateViewport ( )
{
2009-11-23 14:08:08 +00:00
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
2009-09-03 19:24:16 +00:00
int scissorXOff = bpmem . scissorOffset . x * 2 ; // 342
int scissorYOff = bpmem . scissorOffset . y * 2 ; // 342
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
float MValueX = Renderer : : GetTargetScaleX ( ) ;
float MValueY = Renderer : : GetTargetScaleY ( ) ;
2009-04-03 14:35:49 +00:00
2009-02-23 07:23:34 +00:00
// Stretch picture with increased internal resolution
2009-09-03 19:24:16 +00:00
int GLx = ( int ) ceil ( ( xfregs . rawViewport [ 3 ] - xfregs . rawViewport [ 0 ] - scissorXOff ) * MValueX ) ;
int GLy = ( int ) ceil ( Renderer : : GetTargetHeight ( ) - ( ( int ) ( xfregs . rawViewport [ 4 ] - xfregs . rawViewport [ 1 ] - scissorYOff ) ) * MValueY ) ;
2009-11-23 14:08:08 +00:00
int GLWidth = ( int ) ceil ( ( int ) ( 2 * xfregs . rawViewport [ 0 ] ) * MValueX ) ;
int GLHeight = ( int ) ceil ( ( int ) ( - 2 * xfregs . rawViewport [ 1 ] ) * MValueY ) ;
2009-10-26 02:38:23 +00:00
double GLNear = ( xfregs . rawViewport [ 5 ] - xfregs . rawViewport [ 2 ] ) / 16777216.0f ;
2009-11-23 14:08:08 +00:00
double GLFar = xfregs . rawViewport [ 5 ] / 16777216.0f ;
if ( GLWidth < 0 )
{
GLx + = GLWidth ;
GLWidth * = - 1 ;
}
if ( GLHeight < 0 )
{
GLy + = GLHeight ;
GLHeight * = - 1 ;
}
2009-02-23 07:23:34 +00:00
// Update the view port
2009-02-28 16:33:59 +00:00
glViewport ( GLx , GLy , GLWidth , GLHeight ) ;
2009-02-23 07:23:34 +00:00
glDepthRange ( GLNear , GLFar ) ;
}
2009-11-27 19:42:27 +00:00
void Renderer : : SetGenerationMode ( )
{
// none, ccw, cw, ccw
if ( bpmem . genMode . cullmode > 0 )
{
glEnable ( GL_CULL_FACE ) ;
glFrontFace ( bpmem . genMode . cullmode = = 2 ? GL_CCW : GL_CW ) ;
}
else
glDisable ( GL_CULL_FACE ) ;
}
void Renderer : : SetDepthMode ( )
{
if ( bpmem . zmode . testenable )
{
glEnable ( GL_DEPTH_TEST ) ;
glDepthMask ( bpmem . zmode . updateenable ? GL_TRUE : GL_FALSE ) ;
glDepthFunc ( glCmpFuncs [ bpmem . zmode . func ] ) ;
}
else
{
// if the test is disabled write is disabled too
glDisable ( GL_DEPTH_TEST ) ;
glDepthMask ( GL_FALSE ) ;
}
}
void Renderer : : SetLogicOpMode ( )
{
2009-12-09 13:51:28 +00:00
if ( bpmem . blendmode . logicopenable & & bpmem . blendmode . logicmode ! = 3 )
2009-11-27 19:42:27 +00:00
{
glEnable ( GL_COLOR_LOGIC_OP ) ;
glLogicOp ( glLogicOpCodes [ bpmem . blendmode . logicmode ] ) ;
}
else
glDisable ( GL_COLOR_LOGIC_OP ) ;
}
void Renderer : : SetDitherMode ( )
{
if ( bpmem . blendmode . dither )
glEnable ( GL_DITHER ) ;
else
glDisable ( GL_DITHER ) ;
}
void Renderer : : SetLineWidth ( )
{
float fratio = xfregs . rawViewport [ 0 ] ! = 0 ? ( ( float ) Renderer : : GetTargetWidth ( ) / EFB_WIDTH ) : 1.0f ;
if ( bpmem . lineptwidth . linesize > 0 )
glLineWidth ( ( float ) bpmem . lineptwidth . linesize * fratio / 6.0f ) ; // scale by ratio of widths
if ( bpmem . lineptwidth . pointsize > 0 )
glPointSize ( ( float ) bpmem . lineptwidth . pointsize * fratio / 6.0f ) ;
}
void Renderer : : SetSamplerState ( int stage , int texindex )
{
// TODO
}
void Renderer : : SetInterlacingMode ( )
{
// TODO
}