2009-04-03 14:35:49 +00:00
// Copyright (C) 2003-2009 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-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-02-23 07:23:34 +00:00
# include "Config.h"
# 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"
# include "rasterfont.h"
# include "VertexShaderGen.h"
# 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-02-23 07:23:34 +00:00
# ifdef _WIN32
# include "Win32Window.h" // warning: crapcode
# else
# endif
2009-06-07 12:06:15 +00:00
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
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-03-08 21:42:27 +00:00
static bool s_bNativeResolution = false ;
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
static volatile bool s_bScreenshot = false ;
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
static int s_fps = 0 ;
2009-03-08 19:19:51 +00:00
// These STAY CONSTANT during execution, no matter how much you resize the game window.
2009-03-05 23:11:13 +00:00
// TODO: Add functionality to reinit all the render targets when the window is resized.
2009-02-28 16:33:59 +00:00
static int s_targetwidth ; // Size of render buffer FBO.
static int s_targetheight ;
2009-06-28 23:35:08 +00:00
static FramebufferManager s_framebufferManager ;
2009-06-29 20:54:47 +00:00
static GLuint s_tempScreenshotFramebuffer = 0 ;
2009-06-28 23:35:08 +00:00
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
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 ] = {
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-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-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 ( )
{
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-03-08 21:42:27 +00:00
s_bNativeResolution = g_Config . bNativeResolution ;
2009-03-08 20:04:40 +00:00
switch ( g_Config . iMultisampleMode )
{
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-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-02-23 07:23:34 +00:00
s_bFullscreen = g_Config . bFullscreen ;
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-02-23 07:23:34 +00:00
# ifdef _WIN32
2009-02-28 16:33:59 +00:00
if ( WGLEW_EXT_swap_control )
2009-03-05 23:11:13 +00:00
wglSwapIntervalEXT ( g_Config . 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-03-05 23:11:13 +00:00
glXSwapIntervalSGI ( g_Config . 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 ) {
WARN_LOG ( VIDEO , " ARB_texture_non_power_of_two not supported. This extension is not yet used, though. " ) ;
}
2009-02-23 07:23:34 +00:00
2009-06-28 23:35:08 +00:00
if ( g_Config . bNativeResolution )
{
s_targetwidth = g_Config . b2xResolution ? EFB_WIDTH * 2 : EFB_WIDTH ;
s_targetheight = g_Config . b2xResolution ? EFB_HEIGHT * 2 : EFB_HEIGHT ;
}
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.
// So the below is wrong.
// This should really be grabbed from config rather than from OpenGL.
// JP: Set these to the biggest of the 2x mode and the custom resolution so that the framebuffer
// does not get to be too small
int W = ( int ) OpenGL_GetBackbufferWidth ( ) , H = ( int ) OpenGL_GetBackbufferHeight ( ) ;
s_targetwidth = ( 1280 > = W ) ? 1280 : W ;
s_targetheight = ( 960 > = H ) ? 960 : H ;
2009-06-08 20:07:20 +00:00
2009-06-28 23:35:08 +00:00
// Compensate height of render target for scaling, so that we get something close to the correct number of
// vertical pixels.
s_targetheight * = 528.0 / 480.0 ;
}
2009-02-28 19:02:37 +00:00
// Ensure a minimum target size so that the native res target always fits.
if ( s_targetwidth < EFB_WIDTH )
s_targetwidth = EFB_WIDTH ;
if ( s_targetheight < EFB_HEIGHT )
s_targetheight = EFB_HEIGHT ;
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
s_framebufferManager . Init ( s_targetwidth , s_targetheight , s_MSAASamples , s_MSAACoverageSamples ) ;
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
if ( ! InitializeGL ( ) )
return false ;
return glGetError ( ) = = GL_NO_ERROR & & bSuccess ;
}
2009-02-28 16:33:59 +00:00
2009-02-23 07:23:34 +00:00
void Renderer : : Shutdown ( void )
{
delete s_pfont ;
s_pfont = 0 ;
if ( g_cgcontext ) {
cgDestroyContext ( g_cgcontext ) ;
g_cgcontext = 0 ;
2009-06-26 08:57:53 +00:00
}
2009-06-29 20:54:47 +00:00
glDeleteFramebuffersEXT ( 1 , & s_tempScreenshotFramebuffer ) ;
s_tempScreenshotFramebuffer = 0 ;
2009-06-28 23:35:08 +00:00
s_framebufferManager . Shutdown ( ) ;
2009-06-26 08:57:53 +00:00
2009-03-28 21:07: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
}
bool Renderer : : InitializeGL ( )
{
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-03-22 11:21:44 +00:00
return GL_REPORT_ERROR ( ) = = GL_NO_ERROR ;
2009-02-23 07:23:34 +00:00
}
// Return the rendering window width and height
int Renderer : : GetTargetWidth ( )
{
2009-06-28 23:35:08 +00:00
return s_targetwidth ;
2009-02-23 07:23:34 +00:00
}
int Renderer : : GetTargetHeight ( )
{
2009-06-28 23:35:08 +00:00
return s_targetheight ;
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
}
void Renderer : : SetFramebuffer ( GLuint fb )
{
2009-06-28 23:35:08 +00:00
glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT , fb ! = 0 ? fb : s_framebufferManager . GetEFBFramebuffer ( ) ) ;
2009-02-23 07:23:34 +00:00
}
void Renderer : : ResetGLState ( )
{
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-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 ) ;
glDisable ( GL_VERTEX_PROGRAM_ARB ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
}
2009-06-26 08:57:53 +00:00
void UpdateViewport ( ) ;
2009-02-23 07:23:34 +00:00
void Renderer : : RestoreGLState ( )
{
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
glEnable ( GL_VERTEX_PROGRAM_ARB ) ;
glEnable ( GL_FRAGMENT_PROGRAM_ARB ) ;
2009-02-23 07:23:34 +00:00
}
void Renderer : : SetColorMask ( )
{
2009-06-22 09:31:30 +00:00
if ( bpmem . blendmode . alphaupdate & & bpmem . blendmode . colorupdate )
2009-02-28 19:02:37 +00:00
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
2009-06-22 09:31:30 +00:00
else if ( bpmem . blendmode . alphaupdate )
2009-02-28 19:02:37 +00:00
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_TRUE ) ;
2009-06-22 09:31:30 +00:00
else if ( bpmem . blendmode . colorupdate )
2009-02-28 19:02:37 +00:00
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_FALSE ) ;
else
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
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-06-08 00:44:48 +00:00
// Apply AA if enabled
GLuint Renderer : : ResolveAndGetRenderTarget ( const TRectangle & source_rect )
{
2009-06-28 23:35:08 +00:00
return s_framebufferManager . GetEFBColorTexture ( source_rect ) ;
2009-06-08 00:44:48 +00:00
}
GLuint Renderer : : ResolveAndGetDepthTarget ( const TRectangle & source_rect )
{
2009-06-28 23:35:08 +00:00
return s_framebufferManager . GetEFBDepthTexture ( source_rect ) ;
2009-06-08 00:44:48 +00:00
}
2009-06-09 21:29:54 +00:00
/////////////////////////////////////////////////////////////////////////////
2009-06-07 12:06:15 +00:00
// Function: This function handles the OpenGL glScissor() function
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
2009-02-23 07:23:34 +00:00
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
// case 0x52 > SetScissorRect()
2009-06-07 12:06:15 +00:00
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
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-02-28 01:26:56 +00:00
/*LOG(VIDEO, "Scissor: lt=(%d,%d), rb=(%d,%d,%i), off=(%d,%d)\n",
2009-02-23 07:23:34 +00:00
rc_left , rc_top ,
rc_right , rc_bottom , Renderer : : GetTargetHeight ( ) ,
xoff , yoff
) ; */
// 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-06-07 12:06:15 +00:00
// Aspect ratio functions
2009-02-28 16:33:59 +00:00
void ComputeBackbufferRectangle ( TRectangle * rc )
2009-02-23 07:23:34 +00:00
{
2009-02-28 16:33:59 +00:00
float FloatGLWidth = ( float ) OpenGL_GetBackbufferWidth ( ) ;
float FloatGLHeight = ( float ) OpenGL_GetBackbufferHeight ( ) ;
float FloatXOffset = 0 ;
float FloatYOffset = 0 ;
2009-02-23 07:23:34 +00:00
// The rendering window size
2009-02-28 16:33:59 +00:00
const float WinWidth = FloatGLWidth ;
const float WinHeight = FloatGLHeight ;
// Handle aspect ratio.
if ( g_Config . bKeepAR43 | | g_Config . bKeepAR169 )
2009-02-23 07:23:34 +00:00
{
2009-02-28 16:33:59 +00:00
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
float Ratio = ( WinWidth / WinHeight ) / ( g_Config . bKeepAR43 ? ( 4.0f / 3.0f ) : ( 16.0f / 9.0f ) ) ;
2009-02-23 07:23:34 +00:00
// Check if height or width is the limiting factor. If ratio > 1 the picture is to wide and have to limit the width.
if ( Ratio > 1 )
{
2009-02-28 16:33:59 +00:00
// Scale down and center in the X direction.
FloatGLWidth / = Ratio ;
FloatXOffset = ( WinWidth - FloatGLWidth ) / 2.0f ;
2009-02-23 07:23:34 +00:00
}
2009-02-28 16:33:59 +00:00
// The window is too high, we have to limit the height
2009-02-23 07:23:34 +00:00
else
{
2009-02-28 16:33:59 +00:00
// Scale down and center in the Y direction.
FloatGLHeight * = Ratio ;
FloatYOffset = FloatYOffset + ( WinHeight - FloatGLHeight ) / 2.0f ;
2009-02-23 07:23:34 +00:00
}
}
2009-02-25 05:54:36 +00:00
// -----------------------------------------------------------------------
2009-03-05 23:11:13 +00:00
// Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10.
2009-02-25 05:54:36 +00:00
// Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset
// ------------------
2009-02-28 16:33:59 +00:00
if ( ( g_Config . bKeepAR43 | | g_Config . bKeepAR169 ) & & g_Config . bCrop )
2009-02-25 05:54:36 +00:00
{
float Ratio = g_Config . bKeepAR43 ? ( ( 4.0 / 3.0 ) / ( 5.0 / 4.0 ) ) : ( ( ( 16.0 / 9.0 ) / ( 16.0 / 10.0 ) ) ) ;
2009-02-26 00:11:51 +00:00
// The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted)
2009-02-25 05:54:36 +00:00
float IncreasedWidth = ( Ratio - 1.0 ) * FloatGLWidth ;
float IncreasedHeight = ( Ratio - 1.0 ) * FloatGLHeight ;
2009-02-26 00:11:51 +00:00
// The new width and height
2009-02-25 05:54:36 +00:00
FloatGLWidth = FloatGLWidth * Ratio ;
FloatGLHeight = FloatGLHeight * Ratio ;
// Adjust the X and Y offset
2009-06-08 03:17:15 +00:00
FloatXOffset = FloatXOffset - ( IncreasedWidth / 2.0 ) ;
FloatYOffset = FloatYOffset - ( IncreasedHeight / 2.0 ) ;
//NOTICE_LOG(OSREPORT, "Crop Ratio:%1.2f IncreasedHeight:%3.0f YOffset:%3.0f", Ratio, IncreasedHeight, FloatYOffset);
//NOTICE_LOG(OSREPORT, "Crop FloatGLWidth:%1.2f FloatGLHeight:%3.0f", (float)FloatGLWidth, (float)FloatGLHeight);
//NOTICE_LOG(OSREPORT, "");
2009-02-25 05:54:36 +00:00
}
2009-03-05 23:11:13 +00:00
// round(float) = floor(float + 0.5)
2009-02-28 16:33:59 +00:00
int XOffset = floor ( FloatXOffset + 0.5 ) ;
int YOffset = floor ( FloatYOffset + 0.5 ) ;
rc - > left = XOffset ;
rc - > top = YOffset ;
rc - > right = XOffset + ceil ( FloatGLWidth ) ;
rc - > bottom = YOffset + ceil ( FloatGLHeight ) ;
}
2009-02-25 05:54:36 +00:00
2009-07-11 02:34:16 +00:00
void Renderer : : RenderToXFB ( u32 xfbAddr , u32 fbWidth , u32 fbHeight , const TRectangle & sourceRc )
2009-06-26 08:57:53 +00:00
{
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-06-26 08:57:53 +00:00
2009-07-11 02:34:16 +00:00
s_framebufferManager . CopyToXFB ( xfbAddr , fbWidth , fbHeight , sourceRc ) ;
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-07-11 02:34:16 +00:00
const XFBSource * xfbSource = s_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-03-06 00:03:33 +00:00
ResetGLState ( ) ;
2009-02-28 16:33:59 +00:00
2009-03-06 00:03:33 +00:00
TRectangle back_rc ;
ComputeBackbufferRectangle ( & back_rc ) ;
2009-02-23 07:23:34 +00:00
2009-02-28 16:33:59 +00:00
float u_max ;
2009-06-29 07:30:48 +00:00
float v_min ;
2009-02-28 16:33:59 +00:00
float v_max ;
2009-07-02 01:49:28 +00:00
2009-06-29 07:30:48 +00:00
if ( g_Config . bAutoScale )
2009-03-08 19:19:51 +00:00
{
2009-06-29 07:30:48 +00:00
u_max = ( xfbSource - > sourceRc . right - xfbSource - > sourceRc . left ) ;
v_min = ( float ) xfbSource - > texHeight - ( xfbSource - > sourceRc . bottom - xfbSource - > sourceRc . top ) ;
v_max = ( float ) xfbSource - > texHeight ;
2009-03-08 19:19:51 +00:00
}
else
{
2009-06-29 07:30:48 +00:00
u_max = ( float ) xfbSource - > texWidth ;
2009-07-03 23:53:20 +00:00
v_min = 0.f ;
2009-06-29 07:30:48 +00:00
v_max = ( float ) xfbSource - > texHeight ;
2009-02-28 16:33:59 +00:00
}
2009-07-02 01:49:28 +00:00
2009-07-11 02:34:16 +00:00
int yOffset = ( g_Config . bUseXFB & & field = = FIELD_LOWER ) ? - 1 : 0 ;
2009-06-29 07:30:48 +00:00
v_min - = yOffset ;
v_max - = 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
glViewport ( back_rc . left , back_rc . top ,
back_rc . right - back_rc . left , back_rc . bottom - back_rc . top ) ;
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.
if ( PostProcessing : : ApplyShader ( ) )
{
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0 , v_min ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 0 ) ; glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( 0 , v_max ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 0 , 1 ) ; glVertex2f ( - 1 , 1 ) ;
glTexCoord2f ( u_max , v_max ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 1 ) ; glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( u_max , v_min ) ; glMultiTexCoord2fARB ( GL_TEXTURE1 , 1 , 0 ) ; glVertex2f ( 1 , - 1 ) ;
glEnd ( ) ;
glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB , 0 ) ;
glDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
2009-03-08 19:19:51 +00:00
}
2009-06-26 08:57:53 +00:00
else
{
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0 , v_min ) ; glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( 0 , v_max ) ; glVertex2f ( - 1 , 1 ) ;
glTexCoord2f ( u_max , v_max ) ; glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( u_max , v_min ) ; glVertex2f ( 1 , - 1 ) ;
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
if ( g_Config . bWireFrame )
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-06-29 20:54:47 +00:00
SaveRenderTarget ( s_sScreenshotName . c_str ( ) , xfbSource - > sourceRc . GetWidth ( ) , xfbSource - > sourceRc . GetHeight ( ) , ( int ) ( v_min ) ) ;
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 ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_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-06-08 10:16:08 +00:00
if ( g_Config . bDumpFrames )
{
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-06-08 10:16:08 +00:00
int t = ( int ) ( v_min ) ;
2009-03-28 21:07:16 +00:00
u8 * data = ( u8 * ) malloc ( 3 * w * h ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2009-06-08 10:16:08 +00:00
glReadPixels ( 0 , t , w , h , GL_BGR , GL_UNSIGNED_BYTE , data ) ;
2009-04-03 14:35:49 +00:00
if ( glGetError ( ) = = GL_NO_ERROR )
{
if ( ! s_bLastFrameDumped )
{
2009-03-28 21:07:16 +00:00
s_bAVIDumping = AVIDump : : Start ( EmuWindow : : GetChildParentWnd ( ) , 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 ) ;
glBindFramebufferEXT ( GL_READ_FRAMEBUFFER_EXT , s_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
if ( g_Config . bDumpFrames ) {
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 ) ;
glReadPixels ( 0 , 0 , w , h , GL_RGB , GL_UNSIGNED_BYTE , data ) ;
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 {
if ( s_bLastFrameDumped & & f_pFrameDump ! = NULL ) {
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
SwapBuffers ( ) ;
2009-07-02 01:49:28 +00:00
2009-06-08 20:07:20 +00:00
// Why save this as s_bNativeResolution if we updated it every frame?
2009-03-08 21:42:27 +00:00
s_bNativeResolution = g_Config . bNativeResolution ;
2009-02-23 07:23:34 +00:00
RestoreGLState ( ) ;
2009-02-28 16:33:59 +00:00
GL_REPORT_ERRORD ( ) ;
2009-02-23 07:23:34 +00:00
g_Config . iSaveTargetId = 0 ;
2009-02-28 16:33:59 +00:00
// For testing zbuffer targets.
// Renderer::SetZBufferRender();
2009-03-05 23:11:13 +00:00
// SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, GetTargetWidth(), GetTargetHeight());
2009-02-23 07:23:34 +00:00
}
2009-06-07 12:06:15 +00:00
//////////////////////////////////////////////////////////////////////////////////////////
// We can now draw whatever we want on top of the picture. Then we copy the final picture to the output.
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
void Renderer : : SwapBuffers ( )
{
// ---------------------------------------------------------------------
// Count FPS.
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
static int fpscount = 0 ;
static unsigned long lasttime ;
+ + fpscount ;
if ( timeGetTime ( ) - lasttime > 1000 )
{
lasttime = timeGetTime ( ) ;
s_fps = fpscount - 1 ;
fpscount = 0 ;
}
// ---------------------------------------------------------------------
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-06-07 12:06:15 +00:00
for ( int i = 0 ; i < 8 ; i + + ) {
glActiveTexture ( GL_TEXTURE0 + i ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_TEXTURE_RECTANGLE_ARB ) ;
}
glActiveTexture ( GL_TEXTURE0 ) ;
DrawDebugText ( ) ;
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-06-07 12:06:15 +00:00
OSD : : DrawMessages ( ) ;
2009-06-13 22:08:01 +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
// Copy the rendered frame to the real window
OpenGL_SwapBuffers ( ) ;
2009-06-13 22:08:01 +00:00
GL_REPORT_ERRORD ( ) ;
2009-06-08 20:07:20 +00:00
// Clear framebuffer
2009-06-07 12:06:15 +00:00
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
GL_REPORT_ERRORD ( ) ;
// Clean out old stuff from caches
VertexShaderCache : : ProgressiveCleanup ( ) ;
PixelShaderCache : : ProgressiveCleanup ( ) ;
TextureMngr : : ProgressiveCleanup ( ) ;
frameCount + + ;
// New frame
stats . ResetFrame ( ) ;
// Render to the framebuffer.
2009-06-26 08:57:53 +00:00
SetFramebuffer ( 0 ) ;
2009-06-07 12:06:15 +00:00
GL_REPORT_ERRORD ( ) ;
}
2009-02-23 07:23:34 +00:00
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-02-23 07:23:34 +00:00
if ( g_Config . bShowFPS )
p + = sprintf ( p , " FPS: %d \n " , s_fps ) ;
2009-03-16 07:54:44 +00:00
if ( g_Config . bShowEFBCopyRegions )
{
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-03-16 07:54:44 +00:00
for ( std : : vector < TRectangle > : : const_iterator it = stats . efb_regions . begin ( ) ; it ! = stats . efb_regions . end ( ) ; + + it )
{
2009-03-21 16:04:44 +00:00
GLfloat halfWidth = Renderer : : GetTargetWidth ( ) / 2.0f ;
GLfloat halfHeight = Renderer : : GetTargetHeight ( ) / 2.0f ;
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 ( ) ;
}
if ( g_Config . bOverlayStats )
{
2009-02-23 07:23:34 +00:00
p + = sprintf ( p , " textures created: %i \n " , stats . numTexturesCreated ) ;
p + = sprintf ( p , " textures alive: %i \n " , stats . numTexturesAlive ) ;
p + = sprintf ( p , " pshaders created: %i \n " , stats . numPixelShadersCreated ) ;
p + = sprintf ( p , " pshaders alive: %i \n " , stats . numPixelShadersAlive ) ;
p + = sprintf ( p , " vshaders created: %i \n " , stats . numVertexShadersCreated ) ;
p + = sprintf ( p , " vshaders alive: %i \n " , stats . numVertexShadersAlive ) ;
p + = sprintf ( p , " dlists called: %i \n " , stats . numDListsCalled ) ;
p + = sprintf ( p , " dlists called(f): %i \n " , stats . thisFrame . numDListsCalled ) ;
// not used.
//p+=sprintf(p,"dlists created: %i\n",stats.numDListsCreated);
//p+=sprintf(p,"dlists alive: %i\n",stats.numDListsAlive);
//p+=sprintf(p,"strip joins: %i\n",stats.numJoins);
p + = sprintf ( p , " primitives: %i \n " , stats . thisFrame . numPrims ) ;
p + = sprintf ( p , " primitive joins: %i \n " , stats . thisFrame . numPrimitiveJoins ) ;
p + = sprintf ( p , " buffer splits: %i \n " , stats . thisFrame . numBufferSplits ) ;
p + = sprintf ( p , " draw calls: %i \n " , stats . thisFrame . numDrawCalls ) ;
p + = sprintf ( p , " primitives (DL): %i \n " , stats . thisFrame . numDLPrims ) ;
p + = sprintf ( p , " XF loads: %i \n " , stats . thisFrame . numXFLoads ) ;
p + = sprintf ( p , " XF loads (DL): %i \n " , stats . thisFrame . numXFLoadsInDL ) ;
p + = sprintf ( p , " CP loads: %i \n " , stats . thisFrame . numCPLoads ) ;
p + = sprintf ( p , " CP loads (DL): %i \n " , stats . thisFrame . numCPLoadsInDL ) ;
p + = sprintf ( p , " BP loads: %i \n " , stats . thisFrame . numBPLoads ) ;
p + = sprintf ( p , " BP loads (DL): %i \n " , stats . thisFrame . numBPLoadsInDL ) ;
p + = sprintf ( p , " vertex loaders: %i \n " , stats . numVertexLoaders ) ;
std : : string text1 ;
VertexLoaderManager : : AppendListToString ( & text1 ) ;
2009-02-28 16:33:59 +00:00
// TODO: Check for buffer overflow
2009-02-23 07:23:34 +00:00
p + = sprintf ( p , " %s " , text1 . c_str ( ) ) ;
}
if ( g_Config . bOverlayProjStats )
{
p + = sprintf ( p , " Projection #: X for Raw 6=0 (X for Raw 6!=0) \n \n " ) ;
p + = sprintf ( p , " Projection 0: %f (%f) Raw 0: %f \n " , stats . gproj_0 , stats . g2proj_0 , stats . proj_0 ) ;
p + = sprintf ( p , " Projection 1: %f (%f) \n " , stats . gproj_1 , stats . g2proj_1 ) ;
p + = sprintf ( p , " Projection 2: %f (%f) Raw 1: %f \n " , stats . gproj_2 , stats . g2proj_2 , stats . proj_1 ) ;
p + = sprintf ( p , " Projection 3: %f (%f) \n \n " , stats . gproj_3 , stats . g2proj_3 ) ;
p + = sprintf ( p , " Projection 4: %f (%f) \n " , stats . gproj_4 , stats . g2proj_4 ) ;
p + = sprintf ( p , " Projection 5: %f (%f) Raw 2: %f \n " , stats . gproj_5 , stats . g2proj_5 , stats . proj_2 ) ;
p + = sprintf ( p , " Projection 6: %f (%f) Raw 3: %f \n " , stats . gproj_6 , stats . g2proj_6 , stats . proj_3 ) ;
p + = sprintf ( p , " Projection 7: %f (%f) \n \n " , stats . gproj_7 , stats . g2proj_7 ) ;
p + = sprintf ( p , " Projection 8: %f (%f) \n " , stats . gproj_8 , stats . g2proj_8 ) ;
p + = sprintf ( p , " Projection 9: %f (%f) \n " , stats . gproj_9 , stats . g2proj_9 ) ;
p + = sprintf ( p , " Projection 10: %f (%f) Raw 4: %f \n \n " , stats . gproj_10 , stats . g2proj_10 , stats . proj_4 ) ;
p + = sprintf ( p , " Projection 11: %f (%f) Raw 5: %f \n \n " , stats . gproj_11 , stats . g2proj_11 , stats . proj_5 ) ;
p + = sprintf ( p , " Projection 12: %f (%f) \n " , stats . gproj_12 , stats . g2proj_12 ) ;
p + = sprintf ( p , " Projection 13: %f (%f) \n " , stats . gproj_13 , stats . g2proj_13 ) ;
p + = sprintf ( p , " Projection 14: %f (%f) \n " , stats . gproj_14 , stats . g2proj_14 ) ;
p + = sprintf ( p , " Projection 15: %f (%f) \n " , stats . gproj_15 , stats . g2proj_15 ) ;
}
// Render a shadow, and then the text.
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
if ( OSDChoice > 0 & & g_Config . bEFBCopyDisableHotKey )
{
OSDTime = timeGetTime ( ) + 3000 ;
OSDChoice = - OSDChoice ;
}
2009-06-10 01:15:41 +00:00
if ( ( u32 ) OSDTime > timeGetTime ( ) & & g_Config . bEFBCopyDisableHotKey )
2009-06-08 02:48:38 +00:00
{
std : : string T1 = " " ;
std : : string T2 = " " ;
int W , H ;
sscanf ( g_Config . iInternalRes , " %dx%d " , & W , & H ) ;
std : : string OSDM1 =
2009-06-08 06:05:09 +00:00
g_Config . bNativeResolution | | g_Config . b2xResolution ?
( g_Config . bNativeResolution ?
StringFromFormat ( " %i x %i (native) " , OSDInternalW , OSDInternalH )
: StringFromFormat ( " %i x %i (2x) " , OSDInternalW , OSDInternalH ) )
: StringFromFormat ( " %i x %i (custom) " , W , H ) ;
2009-06-08 02:48:38 +00:00
std : : string OSDM21 =
! ( g_Config . bKeepAR43 | | g_Config . bKeepAR169 ) ? " - " : ( g_Config . bKeepAR43 ? " 4:3 " : " 16:9 " ) ;
std : : string OSDM22 =
g_Config . bCrop ? " (crop) " : " " ;
std : : string OSDM31 =
g_Config . bCopyEFBToRAM ? " RAM " : " Texture " ;
std : : string OSDM32 =
2009-06-08 20:07:20 +00:00
g_Config . bEFBCopyDisable ? " No " : " Yes " ;
2009-06-08 02:48:38 +00:00
// If there is more text than this we will have a collission
if ( g_Config . bShowFPS )
{ T1 + = " \n \n " ; T2 + = " \n \n " ; }
// The latest changed setting in yellow
T1 + = ( OSDChoice = = - 1 ) ? StringFromFormat ( " 3: Internal Resolution: %s \n " , OSDM1 . c_str ( ) ) : " \n " ;
T1 + = ( OSDChoice = = - 2 ) ? StringFromFormat ( " 4: Lock Aspect Ratio: %s%s \n " , OSDM21 . c_str ( ) , OSDM22 . c_str ( ) ) : " \n " ;
T1 + = ( OSDChoice = = - 3 ) ? StringFromFormat ( " 5: Copy Embedded Framebuffer to %s: %s \n " , OSDM31 . c_str ( ) , OSDM32 . c_str ( ) ) : " \n " ;
// The other settings in cyan
T2 + = ! ( OSDChoice = = - 1 ) ? StringFromFormat ( " 3: Internal Resolution: %s \n " , OSDM1 . c_str ( ) ) : " \n " ;
T2 + = ! ( OSDChoice = = - 2 ) ? StringFromFormat ( " 4: Lock Aspect Ratio: %s \n " , OSDM21 . c_str ( ) , OSDM22 . c_str ( ) ) : " \n " ;
T2 + = ! ( OSDChoice = = - 3 ) ? StringFromFormat ( " 5: Copy Embedded Framebuffer to %s: %s \n " , OSDM31 . c_str ( ) , OSDM32 . c_str ( ) ) : " \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-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-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-08 00:44:48 +00:00
// The height seemed to often be one less than the setting (but sometimes not),
2009-06-22 09:31:30 +00:00
// perhaps the source is the (bpmem.copyTexSrcWH.y + 1) in BPStructs.cpp that I'm guessing
2009-06-08 00:44:48 +00:00
// is there because of how some GL function works. But the buffer we are reading from here
// seems to have the necessary pixels for a complete height so we use the complete height
// from the settings.
2009-06-08 06:05:09 +00:00
if ( ! ( g_Config . bNativeResolution | | g_Config . b2xResolution ) )
2009-06-08 00:44:48 +00:00
sscanf ( g_Config . iInternalRes , " %dx%d " , & W , & H ) ;
2009-06-06 13:36:33 +00:00
2009-06-08 20:07:20 +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-06-06 13:36:33 +00:00
glReadPixels ( 0 , 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
wxImage a ( W , H , data ) ;
2009-06-08 00:44:48 +00:00
// ---------------------------------------------------------------------
// To get past the problem of non-4:3 and non-16:9 native resolution pictures (for example
// in RE1 some pictures have non-4:3 resolutions like 640 x 448 and 512 x 448 and such that
// are meant to be rescaled to 4:3, and most Wii games use 640 x 480 even for the 16:9 mode)
// we let the user use the keep aspect ratio functions to control the resulting aspect ratio.
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
// We don't adjust non-native resolutions to avoid blurring the picture.
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
2009-06-08 20:07:20 +00:00
float Ratio = ( float ) W / ( float ) ( H ) , TargetRatio ;
if ( ( g_Config . bNativeResolution | | g_Config . b2xResolution ) & & ( g_Config . bKeepAR169 | | g_Config . bKeepAR43 )
2009-06-08 00:44:48 +00:00
& & Ratio ! = 4.0 / 3.0 & & Ratio ! = 16.0 / 9.0 )
{
if ( g_Config . bKeepAR43 )
TargetRatio = 4.0 / 3.0 ;
else
TargetRatio = 16.0 / 9.0 ;
// Check if the height or width should be changed (we only increase the picture size, not
// the other way around)
if ( Ratio < TargetRatio )
2009-06-06 13:36:33 +00:00
{
2009-06-08 00:44:48 +00:00
float fW = ( float ) H * TargetRatio ;
W = ( int ) fW ;
2009-06-06 13:36:33 +00:00
}
2009-06-08 00:44:48 +00:00
else
2009-06-06 13:36:33 +00:00
{
2009-06-08 00:44:48 +00:00
float fH = ( float ) W * ( 1 / TargetRatio ) ;
H = ( int ) fH ;
2009-06-06 13:36:33 +00:00
}
a . Rescale ( W , H , wxIMAGE_QUALITY_HIGH ) ;
2009-06-07 21:10:02 +00:00
}
2009-06-08 00:44:48 +00:00
// ---------------------------------------------------------------------
2009-06-06 13:36:33 +00:00
2009-03-28 21:07:16 +00:00
a . SaveFile ( wxString : : FromAscii ( filename ) , wxBITMAP_TYPE_BMP ) ;
bool result = true ;
2009-06-06 13:36:33 +00:00
// Show success messages
OSD : : AddMessage ( StringFromFormat ( " Saved %i x %i %s \n " , W , H , s_sScreenshotName . c_str ( ) ) . c_str ( ) , 2000 ) ;
2009-03-28 21:07:16 +00:00
# else
bool result = SaveTGA ( filename , w , h , data ) ;
free ( data ) ;
# endif
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-06-07 11:51:53 +00:00
//////////////////////////////////////////////////////////////////////////////////////////
2009-02-23 07:23:34 +00:00
2009-06-07 12:06:15 +00:00
//////////////////////////////////////////////////////////////////////////////////////////
2009-02-23 07:23:34 +00:00
// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture.
// Call schedule: Called from VertexShaderManager
2009-06-07 12:06:15 +00:00
// <20> <> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD> <EFBFBD>
2009-02-23 07:23:34 +00:00
void UpdateViewport ( )
{
2009-04-03 14:35:49 +00:00
// ---------
2009-02-23 07:23:34 +00:00
// Logging
2009-04-03 14:35:49 +00:00
// ---------
2009-02-23 07:23:34 +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-03-21 20:07:56 +00:00
/*INFO_LOG(VIDEO, "view: topleft=(%f,%f), wh=(%f,%f), z=(%f,%f)",
2009-02-23 07:23:34 +00:00
rawViewport [ 3 ] - rawViewport [ 0 ] - 342 , rawViewport [ 4 ] + rawViewport [ 1 ] - 342 ,
2 * rawViewport [ 0 ] , 2 * rawViewport [ 1 ] ,
( rawViewport [ 5 ] - rawViewport [ 2 ] ) / 16777215.0f , rawViewport [ 5 ] / 16777215.0f ) ; */
2009-04-03 14:35:49 +00:00
// --------
2009-02-23 07:23:34 +00:00
2009-06-22 09:31:30 +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-02-28 16:33:59 +00:00
int GLx = ( int ) ceil ( ( xfregs . rawViewport [ 3 ] - xfregs . rawViewport [ 0 ] - 342 - scissorXOff ) * MValueX ) ;
int GLy = ( int ) ceil ( Renderer : : GetTargetHeight ( ) - ( ( int ) ( xfregs . rawViewport [ 4 ] - xfregs . rawViewport [ 1 ] - 342 - scissorYOff ) ) * MValueY ) ;
int GLWidth = ( int ) ceil ( abs ( ( int ) ( 2 * xfregs . rawViewport [ 0 ] ) ) * MValueX ) ;
int GLHeight = ( int ) ceil ( abs ( ( int ) ( 2 * xfregs . rawViewport [ 1 ] ) ) * MValueY ) ;
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
2009-02-28 16:33:59 +00:00
// GLDepthRange - this could be a source of trouble - see the viewport hacks.
2009-02-23 07:23:34 +00:00
double GLNear = ( xfregs . rawViewport [ 5 ] - xfregs . rawViewport [ 2 ] ) / 16777215.0f ;
double GLFar = xfregs . rawViewport [ 5 ] / 16777215.0f ;
glDepthRange ( GLNear , GLFar ) ;
2009-02-28 16:33:59 +00:00
2009-02-23 07:23:34 +00:00
// -------------------------------------
// Logging
/*
RECT RcTop , RcParent , RcChild ;
HWND Child = EmuWindow : : GetWnd ( ) ;
HWND Parent = GetParent ( Child ) ;
HWND Top = GetParent ( Parent ) ;
GetWindowRect ( Top , & RcTop ) ;
GetWindowRect ( Parent , & RcParent ) ;
GetWindowRect ( Child , & RcChild ) ;
//Console::ClearScreen();
2009-03-21 20:07:56 +00:00
DEBUG_LOG ( CONSOLE , " ---------------------------------------------------------------- " ) ;
DEBUG_LOG ( CONSOLE , " Top window: X:%03i Y:%03i Width:%03i Height:%03i " , RcTop . left , RcTop . top , RcTop . right - RcTop . left , RcTop . bottom - RcTop . top ) ;
DEBUG_LOG ( CONSOLE , " Parent window: X:%03i Y:%03i Width:%03i Height:%03i " , RcParent . left , RcParent . top , RcParent . right - RcParent . left , RcParent . bottom - RcParent . top ) ;
DEBUG_LOG ( CONSOLE , " Child window: X:%03i Y:%03i Width:%03i Height:%03i " , RcChild . left , RcChild . top , RcChild . right - RcChild . left , RcChild . bottom - RcChild . top ) ;
DEBUG_LOG ( CONSOLE , " ---------------------------------------------------------------- " ) ;
DEBUG_LOG ( CONSOLE , " Res. MValue: X:%f Y:%f XOffs:%f YOffs:%f " , OpenGL_GetXmax ( ) , OpenGL_GetYmax ( ) , OpenGL_GetXoff ( ) , OpenGL_GetYoff ( ) ) ;
DEBUG_LOG ( CONSOLE , " GLViewPort: X:%03i Y:%03i Width:%03i Height:%03i " , GLx , GLy , GLWidth , GLHeight ) ;
DEBUG_LOG ( CONSOLE , " GLDepthRange: Near:%f Far:%f " , GLNear , GLFar ) ;
DEBUG_LOG ( CONSOLE , " GLScissor: X:%03i Y:%03i Width:%03i Height:%03i " , GLScissorX , GLScissorY , GLScissorW , GLScissorH ) ;
DEBUG_LOG ( CONSOLE , " ---------------------------------------------------------------- " ) ;
2009-02-23 07:23:34 +00:00
*/
}
2009-06-07 21:10:02 +00:00