diff options
| author | John Peterson <jpeterson57@gmail.com> | 2009-02-23 07:23:34 +0000 |
|---|---|---|
| committer | John Peterson <jpeterson57@gmail.com> | 2009-02-23 07:23:34 +0000 |
| commit | 366e2ad2762d059e25abc811e67e6d4b8bb35781 (patch) | |
| tree | a22acdc8e6a1aa4b028733f0a87939e5beb65c07 /Source | |
| parent | 69a35cc60a5009fe07cb2dc1e6c1380d82726334 (diff) | |
OpenGL: Changed the end of line style for Render.cpp to. I had to change the whole document to CRLF line endings in Visual Studio.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2388 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source')
| -rw-r--r-- | Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 2656 |
1 files changed, 1328 insertions, 1328 deletions
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 158cc6b657..b6e2cda6fc 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -1,1335 +1,1335 @@ -// Copyright (C) 2003-2008 Dolphin Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-
-#include "Globals.h"
-#include <vector>
-#include <cmath>
-
-#include "GLUtil.h"
-
-#include <Cg/cg.h>
-#include <Cg/cgGL.h>
-
-#ifdef _WIN32
-#include <mmsystem.h>
-#endif
-
-#include "Config.h"
-#include "Profiler.h"
-#include "Statistics.h"
-#include "ImageWrite.h"
-#include "Render.h"
-#include "OpcodeDecoding.h"
-#include "BPStructs.h"
-#include "TextureMngr.h"
-#include "rasterfont.h"
-#include "VertexShaderGen.h"
-#include "PixelShaderCache.h"
-#include "PixelShaderManager.h"
-#include "VertexLoaderManager.h"
-#include "VertexLoader.h"
-#include "XFB.h"
-#include "OnScreenDisplay.h"
-#include "Timer.h"
-
-#include "main.h" // Local
-#ifdef _WIN32
-#include "OS/Win32.h"
-#endif
-
-#ifdef _WIN32
- #include "Win32Window.h" // warning: crapcode
-#else
-#endif
-
-
-CGcontext g_cgcontext;
-CGprofile g_cgvProf;
-CGprofile g_cgfProf;
-
-RasterFont* s_pfont = NULL;
-
-static bool s_bFullscreen = false;
-
-static int nZBufferRender = 0; // if > 0, then use zbuffer render, and count down.
-
-// A framebuffer is a set of render targets: a color and a z buffer. They can be either RenderBuffers or Textures.
-static GLuint s_uFramebuffer = 0;
-
-// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn'.t
-static GLuint s_RenderTarget = 0;
-static GLuint s_DepthTarget = 0;
-static GLuint s_ZBufferTarget = 0;
-
-static bool s_bATIDrawBuffers = false;
-static bool s_bHaveStencilBuffer = false;
-
-static Renderer::RenderMode s_RenderMode = Renderer::RM_Normal;
-bool g_bBlendSeparate = false;
-int frameCount;
-
-void HandleCgError(CGcontext ctx, CGerror err, void *appdata);
-
-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
-};
-
-static u32 s_blendMode;
-
-bool Renderer::Init()
-{
- bool bSuccess = true;
- int numvertexattribs = 0;
- GLenum err = GL_NO_ERROR;
- g_cgcontext = cgCreateContext();
-
- cgGetError();
- cgSetErrorHandler(HandleCgError, NULL);
-
- // fill the opengl extension map
- const char* ptoken = (const char*)glGetString(GL_EXTENSIONS);
- if (ptoken == NULL) return false;
-
- INFO_LOG("Supported OpenGL Extensions:\n");
- INFO_LOG(ptoken); // write to the log file
- INFO_LOG("\n");
-
- if (GLEW_EXT_blend_func_separate && GLEW_EXT_blend_equation_separate)
- g_bBlendSeparate = true;
-
- //Checks if it ONLY has the ATI_draw_buffers extension, some have both
- if (GLEW_ATI_draw_buffers && !GLEW_ARB_draw_buffers)
- s_bATIDrawBuffers = true;
-
- s_bFullscreen = g_Config.bFullscreen;
-
- if (glewInit() != GLEW_OK) {
- ERROR_LOG("glewInit() failed!\nDoes your video card support OpenGL 2.x?");
- return false;
- }
-
- if (!GLEW_EXT_framebuffer_object) {
- ERROR_LOG("*********\nGPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nGPU: *********\nDoes your video card support OpenGL 2.x?");
- bSuccess = false;
- }
-
- if (!GLEW_EXT_secondary_color) {
- ERROR_LOG("*********\nGPU: OGL ERROR: Need GL_EXT_secondary_color\nGPU: *********\nDoes your video card support OpenGL 2.x?");
- bSuccess = false;
- }
-
- glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, (GLint *)&numvertexattribs);
-
- if (numvertexattribs < 11) {
- ERROR_LOG("*********\nGPU: OGL ERROR: Number of attributes %d not enough\nGPU: *********\nDoes your video card support OpenGL 2.x?", numvertexattribs);
- bSuccess = false;
- }
-
- if (!bSuccess)
- return false;
-
-#ifdef _WIN32
- if (WGLEW_EXT_swap_control)
- wglSwapIntervalEXT(0);
- else
- ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\nDoes your video card support OpenGL 2.x?");
-#elif defined(HAVE_X11) && HAVE_X11
- if (glXSwapIntervalSGI)
- glXSwapIntervalSGI(0);
- else
- ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n");
-#else
-
- //TODO
-
-#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) {
- ERROR_LOG("GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024", max_texture_size);
- }
-
- GL_REPORT_ERROR();
- if (err != GL_NO_ERROR) bSuccess = false;
-
- if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers)
- glDrawBuffers = glDrawBuffersARB;
-
- glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer);
- if (s_uFramebuffer == 0) {
- ERROR_LOG("failed to create the renderbuffer\nDoes your video card support OpenGL 2.x?");
- }
-
- _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
-
- // 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.
- int nBackbufferWidth = (int)OpenGL_GetWidth();
- int nBackbufferHeight = (int)OpenGL_GetHeight();
-
- // Create the framebuffer target
- glGenTextures(1, (GLuint *)&s_RenderTarget);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
-
- // Setup the texture params
- // initialize to default
- glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- 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);
-
- GL_REPORT_ERROR();
-
- int nMaxMRT = 0;
- glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, (GLint *)&nMaxMRT);
-
- if (nMaxMRT > 1)
- {
- // create zbuffer target
- glGenTextures(1, (GLuint *)&s_ZBufferTarget);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget);
- glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
- 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);
- }
-
- // create the depth buffer
- glGenRenderbuffersEXT(1, (GLuint *)&s_DepthTarget);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget);
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, nBackbufferWidth, nBackbufferHeight);
-
- if (glGetError() != GL_NO_ERROR)
- {
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, nBackbufferWidth, nBackbufferHeight);
- s_bHaveStencilBuffer = false;
- }
- else
- {
- s_bHaveStencilBuffer = true;
- }
-
- GL_REPORT_ERROR();
-
- // set as render targets
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0);
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget);
-
- GL_REPORT_ERROR();
-
- if (s_ZBufferTarget != 0) {
- // test to make sure it works
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0);
- bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT;
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
-
- if (bFailed) {
- glDeleteTextures(1, (GLuint *)&s_ZBufferTarget);
- s_ZBufferTarget = 0;
- }
- }
-
- if (s_ZBufferTarget == 0)
- ERROR_LOG("disabling ztarget mrt feature (max mrt=%d)\n", nMaxMRT);
-
- // Why is this left here?
- //glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget);
-
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- nZBufferRender = 0;
-
- GL_REPORT_ERROR();
- if (err != GL_NO_ERROR)
- bSuccess = false;
-
- s_pfont = new RasterFont();
-
- // load the effect, find the best profiles (if any)
- if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE) {
- ERROR_LOG("arbvp1 not supported\n");
- return false;
- }
-
- if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE) {
- ERROR_LOG("arbfp1 not supported\n");
- return false;
- }
-
- g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX);
- g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
- cgGLSetOptimalOptions(g_cgvProf);
- cgGLSetOptimalOptions(g_cgfProf);
-
- //ERROR_LOG("max buffer sizes: %d %d\n", cgGetProgramBufferMaxSize(g_cgvProf), cgGetProgramBufferMaxSize(g_cgfProf));
- int nenvvertparams, nenvfragparams, naddrregisters[2];
- 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]);
- glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, (GLint *)&naddrregisters[1]);
- DEBUG_LOG("max program env parameters: vert=%d, frag=%d\n", nenvvertparams, nenvfragparams);
- DEBUG_LOG("max program address register parameters: vert=%d, frag=%d\n", naddrregisters[0], naddrregisters[1]);
-
- if (nenvvertparams < 238)
- ERROR_LOG("not enough vertex shader environment constants!!\n");
-
-#ifndef _DEBUG
- cgGLSetDebugMode(GL_FALSE);
-#endif
-
- if (cgGetError() != CG_NO_ERROR) {
- ERROR_LOG("cg error\n");
- return false;
- }
-
- s_RenderMode = Renderer::RM_Normal;
-
- if (!InitializeGL())
- return false;
-
- XFB_Init();
- return glGetError() == GL_NO_ERROR && bSuccess;
-}
-void Renderer::Shutdown(void)
-{
- delete s_pfont;
- s_pfont = 0;
-
- XFB_Shutdown();
-
- if (g_cgcontext) {
- cgDestroyContext(g_cgcontext);
- g_cgcontext = 0;
- }
- if (s_RenderTarget) {
- glDeleteTextures(1, &s_RenderTarget);
- s_RenderTarget = 0;
- }
- if (s_DepthTarget) {
- glDeleteRenderbuffersEXT(1, &s_DepthTarget);
- s_DepthTarget = 0;
- }
- if (s_uFramebuffer) {
- glDeleteFramebuffersEXT(1, &s_uFramebuffer);
- s_uFramebuffer = 0;
- }
-}
-
-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
-
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // perspective correct interpolation of colors and tex coords
- glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
- glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
-
- glDisable(GL_STENCIL_TEST);
- glEnable(GL_SCISSOR_TEST);
- // Do we really need to set this initial glScissor() value? Wont it be called all the time while the game is running?
- //glScissor(0, 0, (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight());
- 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);
-
- GLenum err = GL_NO_ERROR;
- GL_REPORT_ERROR();
-
- return err == GL_NO_ERROR;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// Return the rendering window width and height
-// ------------------------
-int Renderer::GetTargetWidth()
-{
- return (g_Config.bStretchToFit ? 640 : (int)OpenGL_GetWidth());
-}
-
-int Renderer::GetTargetHeight()
-{
- return (g_Config.bStretchToFit ? 480 : (int)OpenGL_GetHeight());
-}
-/////////////////////////////
-
-
-void Renderer::SetRenderTarget(GLuint targ)
-{
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
- targ != 0 ? targ : s_RenderTarget, 0);
-}
-
-void Renderer::SetDepthTarget(GLuint targ)
-{
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
- targ != 0 ? targ : s_DepthTarget);
-}
-
-void Renderer::SetFramebuffer(GLuint fb)
-{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,
- fb != 0 ? fb : s_uFramebuffer);
-}
-
-GLuint Renderer::GetRenderTarget()
-{
- return s_RenderTarget;
-}
-GLuint Renderer::GetZBufferTarget()
-{
- return nZBufferRender > 0 ? s_ZBufferTarget : 0;
-}
-
-void Renderer::ResetGLState()
-{
- 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);
-}
-
-void Renderer::RestoreGLState()
-{
- glEnable(GL_SCISSOR_TEST);
-
- if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
- if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
- if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
-
- glEnable(GL_VERTEX_PROGRAM_ARB);
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
- SetColorMask();
- SetBlendMode(true);
-}
-
-void Renderer::SetColorMask()
-{
- if (bpmem.blendmode.alphaupdate && bpmem.blendmode.colorupdate)
- glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
- else if (bpmem.blendmode.alphaupdate)
- glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_TRUE);
- else if (bpmem.blendmode.colorupdate)
- glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
-}
-
-void Renderer::SetBlendMode(bool forceUpdate)
-{
- // blend mode bit mask
- // 0 - blend enable
- // 1 - dst alpha enable
- // 2 - reverse subtract enable (else add)
- // 3-5 - srcRGB function
- // 6-8 - dstRGB function
- // 9-16 - dstAlpha
-
- u32 newval = bpmem.blendmode.subtract << 2;
-
- if (g_bBlendSeparate) {
- newval |= bpmem.dstalpha.enable ? 3 : 0;
- newval |= bpmem.dstalpha.alpha << 9;
- }
-
- if (bpmem.blendmode.blendenable) {
- newval |= 1;
-
- if (bpmem.blendmode.subtract) {
- newval |= 0x0048; // src 1 dst 1
- } else {
- newval |= bpmem.blendmode.srcfactor << 3;
- newval |= bpmem.blendmode.dstfactor << 6;
- }
- } else {
- newval |= 0x0008; // src 1 dst 0
- }
-
- u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
-
- if (changes & 1) {
- newval & 1 ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
- }
-
- bool dstAlphaEnable = g_bBlendSeparate && newval & 2;
-
- if (changes & 6) {
- // dst alpha enable or subtract enable change
- if (dstAlphaEnable)
- glBlendEquationSeparate(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD, GL_FUNC_ADD);
- else
- glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD);
- }
-
- if (changes & 0x1FA) {
- // dst alpha enable or blend RGB change
- if (dstAlphaEnable)
- glBlendFuncSeparate(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7], GL_CONSTANT_ALPHA, GL_ZERO);
- else
- glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]);
- }
-
- if (dstAlphaEnable && changes & 0x1FE00) {
- // dst alpha color change
- glBlendColor(0, 0, 0, (float)bpmem.dstalpha.alpha / 255.0f);
- }
-
- s_blendMode = newval;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////
-// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
-// case 0x52 > SetScissorRect()
-// ---------------
-// This function handles the OpenGL glScissor() function
-// ---------------
-// bpmem.scissorTL.x, y = 342x342
-// bpmem.scissorBR.x, y = 981x821
-// 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()
-{
- int xoff = bpmem.scissorOffset.x * 2 - 342;
- int yoff = bpmem.scissorOffset.y * 2 - 342;
- float MValueX = OpenGL_GetXmax();
- float MValueY = OpenGL_GetYmax();
- float rc_left = (float)bpmem.scissorTL.x - xoff - 342; // left = 0
- rc_left *= MValueX;
- if (rc_left < 0) rc_left = 0;
-
- float rc_top = (float)bpmem.scissorTL.y - yoff - 342; // right = 0
- rc_top *= MValueY;
- if (rc_top < 0) rc_top = 0;
-
- float rc_right = (float)bpmem.scissorBR.x - xoff - 341; // right = 640
- rc_right *= MValueX;
- if (rc_right > 640 * MValueX) rc_right = 640 * MValueX;
-
- float rc_bottom = (float)bpmem.scissorBR.y - yoff - 341; // bottom = 480
- rc_bottom *= MValueY;
- if (rc_bottom > 480 * MValueY) rc_bottom = 480 * MValueY;
-
- /*LOG("Scissor: lt=(%d,%d), rb=(%d,%d,%i), off=(%d,%d)\n",
- 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
- (int)(rc_right-rc_left), // width = 640 for example
- (int)(rc_bottom-rc_top) // height = 480 for example
- );
- return true;
- }
-
- return false;
-}
-
-bool Renderer::IsUsingATIDrawBuffers()
-{
- return s_bATIDrawBuffers;
-}
-
-bool Renderer::HaveStencilBuffer()
-{
- return s_bHaveStencilBuffer;
-}
-
-void Renderer::SetZBufferRender()
-{
- nZBufferRender = 10; // give it 10 frames
- GLenum s_drawbuffers[2] = {
- GL_COLOR_ATTACHMENT0_EXT,
- GL_COLOR_ATTACHMENT1_EXT
- };
- glDrawBuffers(2, s_drawbuffers);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0);
- _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT);
-}
-
-void Renderer::FlushZBufferAlphaToTarget()
-{
- ResetGLState();
-
- SetRenderTarget(0);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
-
- glViewport(0, 0, GetTargetWidth(), GetTargetHeight());
-
- // texture map s_RenderTargets[s_curtarget] onto the main buffer
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget);
- TextureMngr::EnableTexRECT(0);
- // disable all other stages
- for (int i = 1; i < 8; ++i)
- TextureMngr::DisableStage(i);
- GL_REPORT_ERRORD();
-
- // setup the stencil to only accept pixels that have been written
- glStencilFunc(GL_EQUAL, 1, 0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
- // TODO: This code should not have to bother with stretchtofit checking -
- // all necessary scale initialization should be done elsewhere.
- // TODO: Investigate BlitFramebufferEXT.
- if (g_Config.bStretchToFit)
- {
- //TODO: Do Correctly in a bit
- float FactorW = 640.f / (float)OpenGL_GetWidth();
- float FactorH = 480.f / (float)OpenGL_GetHeight();
-
- float Max = (FactorW < FactorH) ? FactorH : FactorW;
- float Temp = 1.0f / Max;
- FactorW *= Temp;
- FactorH *= Temp;
-
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(-FactorW,-FactorH);
- glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-FactorW,FactorH);
- glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(FactorW,FactorH);
- glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(FactorW,-FactorH);
- glEnd();
- }
- else
- {
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(-1,-1);
- glTexCoord2f(0, (float)(GetTargetHeight())); glVertex2f(-1,1);
- glTexCoord2f((float)(GetTargetWidth()), (float)(GetTargetHeight())); glVertex2f(1,1);
- glTexCoord2f((float)(GetTargetWidth()), 0); glVertex2f(1,-1);
- glEnd();
- }
-
- GL_REPORT_ERRORD();
-
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
- RestoreGLState();
-}
-
-void Renderer::SetRenderMode(RenderMode mode)
-{
- if (!s_bHaveStencilBuffer && mode == RM_ZBufferAlpha)
- mode = RM_ZBufferOnly;
-
- if (s_RenderMode == mode)
- return;
-
- if (mode == RM_Normal) {
- // flush buffers
- if (s_RenderMode == RM_ZBufferAlpha) {
- FlushZBufferAlphaToTarget();
- glDisable(GL_STENCIL_TEST);
- }
- SetColorMask();
- SetRenderTarget(0);
- SetZBufferRender();
- GL_REPORT_ERRORD();
- }
- else if (s_RenderMode == RM_Normal) {
- // setup buffers
- _assert_(GetZBufferTarget() && bpmem.zmode.updateenable);
-
- if (mode == RM_ZBufferAlpha) {
- glEnable(GL_STENCIL_TEST);
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
- glStencilFunc(GL_ALWAYS, 1, 0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- }
-
- glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- GL_REPORT_ERRORD();
- }
- else {
- _assert_(GetZBufferTarget());
- _assert_(s_bHaveStencilBuffer);
-
- if (mode == RM_ZBufferOnly) {
- // flush and remove stencil
- _assert_(s_RenderMode==RM_ZBufferAlpha);
- FlushZBufferAlphaToTarget();
- glDisable(GL_STENCIL_TEST);
-
- SetRenderTarget(s_ZBufferTarget);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- GL_REPORT_ERRORD();
- }
- else {
- _assert_(mode == RM_ZBufferAlpha && s_RenderMode == RM_ZBufferOnly);
-
- // setup stencil
- glEnable(GL_STENCIL_TEST);
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
- glStencilFunc(GL_ALWAYS, 1, 0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- }
- }
-
- s_RenderMode = mode;
-}
-
-Renderer::RenderMode Renderer::GetRenderMode()
-{
- return s_RenderMode;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// This function has the final picture if the XFB functions are not used. We adjust the aspect ratio here.
-// ----------------------
-void Renderer::Swap(const TRectangle& rc)
-{
- OpenGL_Update(); // just updates the render window position and the backbuffer size
-
- DVSTARTPROFILE();
-
- Renderer::SetRenderMode(Renderer::RM_Normal);
-
-#if 0
- // Blit the FBO to do Anti-Aliasing
- // Not working?
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
- glBlitFramebufferEXT(0, 0, 640, 480, 0, 0, OpenGL_GetWidth(), OpenGL_GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
-
-#else
- // render to the real buffer now
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer
-
- // -----------------------------------------------------------------------
- // GLViewPort variables
- // ------------------
- /* Work with float values for the XFB supplement and aspect ratio functions. These are default
- values that are used if the XFB supplement and the keep aspect ratio function are unused */
- float FloatGLWidth = (float)OpenGL_GetWidth();
- float FloatGLHeight = (float)OpenGL_GetHeight();
- float FloatXOffset = 0, FloatYOffset = 0;
- // -------------------------------------
-
-
- // -----------------------------------------------------------------------
- // XFB supplement, fix the black borders problem
- // ------------------
- /* I'm limiting it to the stretch to fit option because I don't know how the other mode works. The reason
- I don't allow this option together with UseXFB is that they are supplements and the XFB function
- should be able to produce the same result */
- if(g_Config.bStretchToFit && !g_Config.bUseXFB)
- {
- // The rendering window size
- float WinWidth = (float)OpenGL_GetWidth();
- float WinHeight = (float)OpenGL_GetHeight();
-
- // The fraction of the screen that the image occupies
- // Rc.right and rc.bottom is the original picture pixel size
- /* There is a +1 in Rc (earlier called multirc, the input to this function), but these
- adjustments seems to work better without it. */
- float WidthRatio = (float)(rc.right - 1) / 640.0f;
- float HeightRatio = (float)(rc.bottom - 1) / 480.0f;
-
- // The pixel size of the image on the screen, adjusted for the actual window size
- float OldWidth = WidthRatio * (float)WinWidth;
- float OldHeight = HeightRatio * (float)WinHeight;
-
- // The adjusted width and height
- FloatGLWidth = ceil((float)WinWidth / WidthRatio);
- FloatGLHeight = ceil((float)WinHeight / HeightRatio);
-
- // The width and height deficit in actual pixels
- float WidthDeficit = (float)WinWidth - OldWidth;
- float HeightDeficit = (float)WinHeight - OldHeight;
-
- // The picture will be drawn from the bottom so we need this YOffset
- // The X-axis needs no adjustment because the picture begins from the left
- FloatYOffset = -HeightDeficit / HeightRatio;
-
- // -----------------------------------------------------------------------
- // Logging
- // ------------------
- /*
- Console::ClearScreen();
- Console::Print("Bpmem L:%i T:%i X:%i Y:%i\n", bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bpmem.copyTexSrcWH.x, bpmem.copyTexSrcWH.y);
- Console::Print("Input Left:%i Top:%i Right:%i Bottom:%i\n", rc.left, rc.top, rc.right, rc.bottom);
- Console::Print("Old picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f\n", WidthRatio, OldWidth, HeightRatio, OldHeight);
- Console::Print("New picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f YOffset:%4.0f YDeficit:%4.0f\n", WidthRatio, WinWidth, HeightRatio, WinHeight, FloatYOffset, HeightDeficit);
- Console::Print("----------------------------------------------------------------\n");
- */
- // ------------------------------
- }
- // ------------------------------
-
-
-
- // -----------------------------------------------------------------------
- /* Keep aspect ratio at 4:3. This may be interesting if you for example have a 5:4 screen but don't like
- the stretching, and would rather have a letterbox. */
- // Output: GLWidth, GLHeight, XOffset, YOffset
- // ------------------
-
- // The rendering window size
- float WinWidth = (float)OpenGL_GetWidth();
- float WinHeight = (float)OpenGL_GetHeight();
- // The rendering window aspect ratio as a fraction of the 4:3 ratio
- float Ratio = WinWidth / WinHeight / (4.0f / 3.0f);
- float wAdj, hAdj;
- // Actual pixel size of the picture after adjustment
- float PictureWidth = WinWidth, PictureHeight = WinHeight;
-
- // This function currently only works together with the Stretch To Fit option
- if (g_Config.bKeepAR && g_Config.bStretchToFit)
- {
- // 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)
- {
- // ------------------------------------------------
- // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
- // ----------------
- wAdj = Ratio;
- hAdj = 1.0;
- FloatGLWidth = FloatGLWidth / wAdj;
- FloatGLHeight = FloatGLHeight / hAdj;
- // --------------------
-
- // ------------------------------------------------
- // Calculate the new X offset
- // ----------------
- // The picture width
- PictureWidth = WinWidth / Ratio;
- // Move the left of the picture to the middle of the screen
- FloatXOffset = FloatXOffset + WinWidth / 2.0f;
- // Then remove half the picture height to move it to the horizontal center
- FloatXOffset = FloatXOffset - PictureWidth / 2.0f;
- // --------------------
- }
- // The window is to high, we have to limit the height
- else
- {
- // ------------------------------------------------
- // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
- // ----------------
- // Invert the ratio to make it > 1
- Ratio = 1.0f / Ratio;
- wAdj = 1.0f;
- hAdj = Ratio;
- FloatGLWidth = FloatGLWidth / wAdj;
- FloatGLHeight = FloatGLHeight / hAdj;
- // --------------------
-
- // ------------------------------------------------
- // Calculate the new Y offset
- // ----------------
- // The picture height
- PictureHeight = WinHeight / Ratio;
- // Keep the picture on the bottom of the screen, this is needed because YOffset may not be 0 here
- FloatYOffset = FloatYOffset / hAdj;
- // Move the bottom of the picture to the middle of the screen
- FloatYOffset = FloatYOffset + WinHeight / 2.0f;
- // Then remove half the picture height to move it to the vertical center
- FloatYOffset = FloatYOffset - PictureHeight / 2.0f;
- // --------------------
- }
-
- // -----------------------------------------------------------------------
- // Logging
- // ------------------
- /*
- Console::Print("Screen Width:%4.0f Height:%4.0f Ratio:%1.2f\n", WinWidth, WinHeight, Ratio);
- Console::Print("GL Width:%4.1f Height:%4.1f\n", FloatGLWidth, FloatGLHeight);
- Console::Print("Picture Width:%4.1f Height:%4.1f YOffset:%4.0f\n", PictureWidth, PictureHeight, FloatYOffset);
- Console::Print("----------------------------------------------------------------\n");
- */
- // ------------------------------
- }
- // -------------------------------------
-
- // -----------------------------------------------------------------------
- /* Adjustments to
- FloatGLWidth
- FloatGLHeight
- XOffset
- YOffset
- are done. Calculate the new new windows width and height. */
- // --------------------
- int GLx = OpenGL_GetXoff(); // These two are zero
- int GLy = OpenGL_GetYoff();
- int GLWidth = ceil(FloatGLWidth);
- int GLHeight = ceil(FloatGLHeight);
-
- // Because there is no round() function we use round(float) = floor(float + 0.5) instead
- int YOffset = floor(FloatYOffset + 0.5);
- int XOffset = floor(FloatXOffset+ 0.5);
- // -------------------------------------
-
-
- // Update GLViewPort
- glViewport(
- GLx + XOffset,
- GLy + YOffset,
- GLWidth,
- GLHeight
- );
-
- // -----------------------------------------------------------------------
- // Show the finished picture
- // --------------------
- // Reset GL state
- ResetGLState();
-
- // Texture map s_RenderTargets[s_curtarget] onto the main buffer
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
- TextureMngr::EnableTexRECT(0);
-
- // Disable all other stages
- for (int i = 1; i < 8; ++i)
- TextureMngr::DisableStage(i);
-
- GL_REPORT_ERRORD();
-
- // Place the texture
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex2f(-1,-1);
- glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-1,1);
- glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(1,1);
- glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(1,-1);
- glEnd();
-
- // Wireframe
- if (g_Config.bWireFrame)
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
- TextureMngr::DisableStage(0);
- // -------------------------------------
-
-
- // -----------------------------------------------------------------------
- /* Blacken out the borders in the 4:3 or the coming 16:9 aspect ratio modes. Somewhere in BPStructs
- 0x52 or elsewhere the area outside the actual picture, that we now show with the aspect ratio option
- has been filled with either for example white, or have copies of old renderings on it. So we replace
- that with blacknes. */
- // --------------------
- if(g_Config.bKeepAR)
- {
- // Set current drawing color to red
- glColor3f(0.0, 0.0, 0.0); // Black
-
- /* This doesn't work
- glRecti, glRectf(
- (float)Left,
- (float)Right,
- (float)Top,
- (float)Bottom); */
-
- /* The glVertex3f() coordinates are:
- Top: 1 to -1 from top to bottom
- Left: 1 to -1 from right to left
- Height and width is therefore 2.0, zero is the center of the screen
- */
- // The fraction of the screen that the image occupies
- /* It's hard to make a border that always exactly begin where the screen ends. The ( -1) here will
- sometimes hide one pixel to many, but if we use (- 0) we will on the other hand sometimes show
- one line of pixels that we should not show. But a -0.5 adjustment seemed just right, it never hid
- one pixel to much, and never one to little. So I settle with a -0.5 adjustment here. */
- float HeightRatio = (((float)(rc.bottom)) - 0.5) / 480.0f;
-
- // Bottom border
+// Copyright (C) 2003-2008 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +#include "Globals.h" +#include <vector> +#include <cmath> + +#include "GLUtil.h" + +#include <Cg/cg.h> +#include <Cg/cgGL.h> + +#ifdef _WIN32 +#include <mmsystem.h> +#endif + +#include "Config.h" +#include "Profiler.h" +#include "Statistics.h" +#include "ImageWrite.h" +#include "Render.h" +#include "OpcodeDecoding.h" +#include "BPStructs.h" +#include "TextureMngr.h" +#include "rasterfont.h" +#include "VertexShaderGen.h" +#include "PixelShaderCache.h" +#include "PixelShaderManager.h" +#include "VertexLoaderManager.h" +#include "VertexLoader.h" +#include "XFB.h" +#include "OnScreenDisplay.h" +#include "Timer.h" + +#include "main.h" // Local +#ifdef _WIN32 +#include "OS/Win32.h" +#endif + +#ifdef _WIN32 + #include "Win32Window.h" // warning: crapcode +#else +#endif + + +CGcontext g_cgcontext; +CGprofile g_cgvProf; +CGprofile g_cgfProf; + +RasterFont* s_pfont = NULL; + +static bool s_bFullscreen = false; + +static int nZBufferRender = 0; // if > 0, then use zbuffer render, and count down. + +// A framebuffer is a set of render targets: a color and a z buffer. They can be either RenderBuffers or Textures. +static GLuint s_uFramebuffer = 0; + +// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn'.t +static GLuint s_RenderTarget = 0; +static GLuint s_DepthTarget = 0; +static GLuint s_ZBufferTarget = 0; + +static bool s_bATIDrawBuffers = false; +static bool s_bHaveStencilBuffer = false; + +static Renderer::RenderMode s_RenderMode = Renderer::RM_Normal; +bool g_bBlendSeparate = false; +int frameCount; + +void HandleCgError(CGcontext ctx, CGerror err, void *appdata); + +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 +}; + +static u32 s_blendMode; + +bool Renderer::Init() +{ + bool bSuccess = true; + int numvertexattribs = 0; + GLenum err = GL_NO_ERROR; + g_cgcontext = cgCreateContext(); + + cgGetError(); + cgSetErrorHandler(HandleCgError, NULL); + + // fill the opengl extension map + const char* ptoken = (const char*)glGetString(GL_EXTENSIONS); + if (ptoken == NULL) return false; + + INFO_LOG("Supported OpenGL Extensions:\n"); + INFO_LOG(ptoken); // write to the log file + INFO_LOG("\n"); + + if (GLEW_EXT_blend_func_separate && GLEW_EXT_blend_equation_separate) + g_bBlendSeparate = true; + + //Checks if it ONLY has the ATI_draw_buffers extension, some have both + if (GLEW_ATI_draw_buffers && !GLEW_ARB_draw_buffers) + s_bATIDrawBuffers = true; + + s_bFullscreen = g_Config.bFullscreen; + + if (glewInit() != GLEW_OK) { + ERROR_LOG("glewInit() failed!\nDoes your video card support OpenGL 2.x?"); + return false; + } + + if (!GLEW_EXT_framebuffer_object) { + ERROR_LOG("*********\nGPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nGPU: *********\nDoes your video card support OpenGL 2.x?"); + bSuccess = false; + } + + if (!GLEW_EXT_secondary_color) { + ERROR_LOG("*********\nGPU: OGL ERROR: Need GL_EXT_secondary_color\nGPU: *********\nDoes your video card support OpenGL 2.x?"); + bSuccess = false; + } + + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, (GLint *)&numvertexattribs); + + if (numvertexattribs < 11) { + ERROR_LOG("*********\nGPU: OGL ERROR: Number of attributes %d not enough\nGPU: *********\nDoes your video card support OpenGL 2.x?", numvertexattribs); + bSuccess = false; + } + + if (!bSuccess) + return false; + +#ifdef _WIN32 + if (WGLEW_EXT_swap_control) + wglSwapIntervalEXT(0); + else + ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\nDoes your video card support OpenGL 2.x?"); +#elif defined(HAVE_X11) && HAVE_X11 + if (glXSwapIntervalSGI) + glXSwapIntervalSGI(0); + else + ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); +#else + + //TODO + +#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) { + ERROR_LOG("GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024", max_texture_size); + } + + GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) bSuccess = false; + + if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers) + glDrawBuffers = glDrawBuffersARB; + + glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer); + if (s_uFramebuffer == 0) { + ERROR_LOG("failed to create the renderbuffer\nDoes your video card support OpenGL 2.x?"); + } + + _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); + + // 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. + int nBackbufferWidth = (int)OpenGL_GetWidth(); + int nBackbufferHeight = (int)OpenGL_GetHeight(); + + // Create the framebuffer target + glGenTextures(1, (GLuint *)&s_RenderTarget); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); + + // Setup the texture params + // initialize to default + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + 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); + + GL_REPORT_ERROR(); + + int nMaxMRT = 0; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, (GLint *)&nMaxMRT); + + if (nMaxMRT > 1) + { + // create zbuffer target + glGenTextures(1, (GLuint *)&s_ZBufferTarget); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, nBackbufferWidth, nBackbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + 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); + } + + // create the depth buffer + glGenRenderbuffersEXT(1, (GLuint *)&s_DepthTarget); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, nBackbufferWidth, nBackbufferHeight); + + if (glGetError() != GL_NO_ERROR) + { + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, nBackbufferWidth, nBackbufferHeight); + s_bHaveStencilBuffer = false; + } + else + { + s_bHaveStencilBuffer = true; + } + + GL_REPORT_ERROR(); + + // set as render targets + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget); + + GL_REPORT_ERROR(); + + if (s_ZBufferTarget != 0) { + // test to make sure it works + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0); + bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT; + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + + if (bFailed) { + glDeleteTextures(1, (GLuint *)&s_ZBufferTarget); + s_ZBufferTarget = 0; + } + } + + if (s_ZBufferTarget == 0) + ERROR_LOG("disabling ztarget mrt feature (max mrt=%d)\n", nMaxMRT); + + // Why is this left here? + //glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + nZBufferRender = 0; + + GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) + bSuccess = false; + + s_pfont = new RasterFont(); + + // load the effect, find the best profiles (if any) + if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE) { + ERROR_LOG("arbvp1 not supported\n"); + return false; + } + + if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE) { + ERROR_LOG("arbfp1 not supported\n"); + return false; + } + + g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX); + g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); + cgGLSetOptimalOptions(g_cgvProf); + cgGLSetOptimalOptions(g_cgfProf); + + //ERROR_LOG("max buffer sizes: %d %d\n", cgGetProgramBufferMaxSize(g_cgvProf), cgGetProgramBufferMaxSize(g_cgfProf)); + int nenvvertparams, nenvfragparams, naddrregisters[2]; + 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]); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, (GLint *)&naddrregisters[1]); + DEBUG_LOG("max program env parameters: vert=%d, frag=%d\n", nenvvertparams, nenvfragparams); + DEBUG_LOG("max program address register parameters: vert=%d, frag=%d\n", naddrregisters[0], naddrregisters[1]); + + if (nenvvertparams < 238) + ERROR_LOG("not enough vertex shader environment constants!!\n"); + +#ifndef _DEBUG + cgGLSetDebugMode(GL_FALSE); +#endif + + if (cgGetError() != CG_NO_ERROR) { + ERROR_LOG("cg error\n"); + return false; + } + + s_RenderMode = Renderer::RM_Normal; + + if (!InitializeGL()) + return false; + + XFB_Init(); + return glGetError() == GL_NO_ERROR && bSuccess; +} +void Renderer::Shutdown(void) +{ + delete s_pfont; + s_pfont = 0; + + XFB_Shutdown(); + + if (g_cgcontext) { + cgDestroyContext(g_cgcontext); + g_cgcontext = 0; + } + if (s_RenderTarget) { + glDeleteTextures(1, &s_RenderTarget); + s_RenderTarget = 0; + } + if (s_DepthTarget) { + glDeleteRenderbuffersEXT(1, &s_DepthTarget); + s_DepthTarget = 0; + } + if (s_uFramebuffer) { + glDeleteFramebuffersEXT(1, &s_uFramebuffer); + s_uFramebuffer = 0; + } +} + +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 + + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // perspective correct interpolation of colors and tex coords + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + // Do we really need to set this initial glScissor() value? Wont it be called all the time while the game is running? + //glScissor(0, 0, (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight()); + 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); + + GLenum err = GL_NO_ERROR; + GL_REPORT_ERROR(); + + return err == GL_NO_ERROR; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// Return the rendering window width and height +// ------------------------ +int Renderer::GetTargetWidth() +{ + return (g_Config.bStretchToFit ? 640 : (int)OpenGL_GetWidth()); +} + +int Renderer::GetTargetHeight() +{ + return (g_Config.bStretchToFit ? 480 : (int)OpenGL_GetHeight()); +} +///////////////////////////// + + +void Renderer::SetRenderTarget(GLuint targ) +{ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, + targ != 0 ? targ : s_RenderTarget, 0); +} + +void Renderer::SetDepthTarget(GLuint targ) +{ + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, + targ != 0 ? targ : s_DepthTarget); +} + +void Renderer::SetFramebuffer(GLuint fb) +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, + fb != 0 ? fb : s_uFramebuffer); +} + +GLuint Renderer::GetRenderTarget() +{ + return s_RenderTarget; +} +GLuint Renderer::GetZBufferTarget() +{ + return nZBufferRender > 0 ? s_ZBufferTarget : 0; +} + +void Renderer::ResetGLState() +{ + 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); +} + +void Renderer::RestoreGLState() +{ + glEnable(GL_SCISSOR_TEST); + + if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE); + if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); + if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); + + glEnable(GL_VERTEX_PROGRAM_ARB); + glEnable(GL_FRAGMENT_PROGRAM_ARB); + SetColorMask(); + SetBlendMode(true); +} + +void Renderer::SetColorMask() +{ + if (bpmem.blendmode.alphaupdate && bpmem.blendmode.colorupdate) + glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); + else if (bpmem.blendmode.alphaupdate) + glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_TRUE); + else if (bpmem.blendmode.colorupdate) + glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE); +} + +void Renderer::SetBlendMode(bool forceUpdate) +{ + // blend mode bit mask + // 0 - blend enable + // 1 - dst alpha enable + // 2 - reverse subtract enable (else add) + // 3-5 - srcRGB function + // 6-8 - dstRGB function + // 9-16 - dstAlpha + + u32 newval = bpmem.blendmode.subtract << 2; + + if (g_bBlendSeparate) { + newval |= bpmem.dstalpha.enable ? 3 : 0; + newval |= bpmem.dstalpha.alpha << 9; + } + + if (bpmem.blendmode.blendenable) { + newval |= 1; + + if (bpmem.blendmode.subtract) { + newval |= 0x0048; // src 1 dst 1 + } else { + newval |= bpmem.blendmode.srcfactor << 3; + newval |= bpmem.blendmode.dstfactor << 6; + } + } else { + newval |= 0x0008; // src 1 dst 0 + } + + u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; + + if (changes & 1) { + newval & 1 ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + } + + bool dstAlphaEnable = g_bBlendSeparate && newval & 2; + + if (changes & 6) { + // dst alpha enable or subtract enable change + if (dstAlphaEnable) + glBlendEquationSeparate(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD, GL_FUNC_ADD); + else + glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD); + } + + if (changes & 0x1FA) { + // dst alpha enable or blend RGB change + if (dstAlphaEnable) + glBlendFuncSeparate(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7], GL_CONSTANT_ALPHA, GL_ZERO); + else + glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); + } + + if (dstAlphaEnable && changes & 0x1FE00) { + // dst alpha color change + glBlendColor(0, 0, 0, (float)bpmem.dstalpha.alpha / 255.0f); + } + + s_blendMode = newval; +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() +// case 0x52 > SetScissorRect() +// --------------- +// This function handles the OpenGL glScissor() function +// --------------- +// bpmem.scissorTL.x, y = 342x342 +// bpmem.scissorBR.x, y = 981x821 +// 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() +{ + int xoff = bpmem.scissorOffset.x * 2 - 342; + int yoff = bpmem.scissorOffset.y * 2 - 342; + float MValueX = OpenGL_GetXmax(); + float MValueY = OpenGL_GetYmax(); + float rc_left = (float)bpmem.scissorTL.x - xoff - 342; // left = 0 + rc_left *= MValueX; + if (rc_left < 0) rc_left = 0; + + float rc_top = (float)bpmem.scissorTL.y - yoff - 342; // right = 0 + rc_top *= MValueY; + if (rc_top < 0) rc_top = 0; + + float rc_right = (float)bpmem.scissorBR.x - xoff - 341; // right = 640 + rc_right *= MValueX; + if (rc_right > 640 * MValueX) rc_right = 640 * MValueX; + + float rc_bottom = (float)bpmem.scissorBR.y - yoff - 341; // bottom = 480 + rc_bottom *= MValueY; + if (rc_bottom > 480 * MValueY) rc_bottom = 480 * MValueY; + + /*LOG("Scissor: lt=(%d,%d), rb=(%d,%d,%i), off=(%d,%d)\n", + 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 + (int)(rc_right-rc_left), // width = 640 for example + (int)(rc_bottom-rc_top) // height = 480 for example + ); + return true; + } + + return false; +} + +bool Renderer::IsUsingATIDrawBuffers() +{ + return s_bATIDrawBuffers; +} + +bool Renderer::HaveStencilBuffer() +{ + return s_bHaveStencilBuffer; +} + +void Renderer::SetZBufferRender() +{ + nZBufferRender = 10; // give it 10 frames + GLenum s_drawbuffers[2] = { + GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT + }; + glDrawBuffers(2, s_drawbuffers); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0); + _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT); +} + +void Renderer::FlushZBufferAlphaToTarget() +{ + ResetGLState(); + + SetRenderTarget(0); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + + glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); + + // texture map s_RenderTargets[s_curtarget] onto the main buffer + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget); + TextureMngr::EnableTexRECT(0); + // disable all other stages + for (int i = 1; i < 8; ++i) + TextureMngr::DisableStage(i); + GL_REPORT_ERRORD(); + + // setup the stencil to only accept pixels that have been written + glStencilFunc(GL_EQUAL, 1, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // TODO: This code should not have to bother with stretchtofit checking - + // all necessary scale initialization should be done elsewhere. + // TODO: Investigate BlitFramebufferEXT. + if (g_Config.bStretchToFit) + { + //TODO: Do Correctly in a bit + float FactorW = 640.f / (float)OpenGL_GetWidth(); + float FactorH = 480.f / (float)OpenGL_GetHeight(); + + float Max = (FactorW < FactorH) ? FactorH : FactorW; + float Temp = 1.0f / Max; + FactorW *= Temp; + FactorH *= Temp; + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(-FactorW,-FactorH); + glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-FactorW,FactorH); + glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(FactorW,FactorH); + glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(FactorW,-FactorH); + glEnd(); + } + else + { + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(-1,-1); + glTexCoord2f(0, (float)(GetTargetHeight())); glVertex2f(-1,1); + glTexCoord2f((float)(GetTargetWidth()), (float)(GetTargetHeight())); glVertex2f(1,1); + glTexCoord2f((float)(GetTargetWidth()), 0); glVertex2f(1,-1); + glEnd(); + } + + GL_REPORT_ERRORD(); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + RestoreGLState(); +} + +void Renderer::SetRenderMode(RenderMode mode) +{ + if (!s_bHaveStencilBuffer && mode == RM_ZBufferAlpha) + mode = RM_ZBufferOnly; + + if (s_RenderMode == mode) + return; + + if (mode == RM_Normal) { + // flush buffers + if (s_RenderMode == RM_ZBufferAlpha) { + FlushZBufferAlphaToTarget(); + glDisable(GL_STENCIL_TEST); + } + SetColorMask(); + SetRenderTarget(0); + SetZBufferRender(); + GL_REPORT_ERRORD(); + } + else if (s_RenderMode == RM_Normal) { + // setup buffers + _assert_(GetZBufferTarget() && bpmem.zmode.updateenable); + + if (mode == RM_ZBufferAlpha) { + glEnable(GL_STENCIL_TEST); + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilFunc(GL_ALWAYS, 1, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + + glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + GL_REPORT_ERRORD(); + } + else { + _assert_(GetZBufferTarget()); + _assert_(s_bHaveStencilBuffer); + + if (mode == RM_ZBufferOnly) { + // flush and remove stencil + _assert_(s_RenderMode==RM_ZBufferAlpha); + FlushZBufferAlphaToTarget(); + glDisable(GL_STENCIL_TEST); + + SetRenderTarget(s_ZBufferTarget); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + GL_REPORT_ERRORD(); + } + else { + _assert_(mode == RM_ZBufferAlpha && s_RenderMode == RM_ZBufferOnly); + + // setup stencil + glEnable(GL_STENCIL_TEST); + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilFunc(GL_ALWAYS, 1, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + } + + s_RenderMode = mode; +} + +Renderer::RenderMode Renderer::GetRenderMode() +{ + return s_RenderMode; +} + + +////////////////////////////////////////////////////////////////////////////////////// +// This function has the final picture if the XFB functions are not used. We adjust the aspect ratio here. +// ---------------------- +void Renderer::Swap(const TRectangle& rc) +{ + OpenGL_Update(); // just updates the render window position and the backbuffer size + + DVSTARTPROFILE(); + + Renderer::SetRenderMode(Renderer::RM_Normal); + +#if 0 + // Blit the FBO to do Anti-Aliasing + // Not working? + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + glBlitFramebufferEXT(0, 0, 640, 480, 0, 0, OpenGL_GetWidth(), OpenGL_GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); + +#else + // render to the real buffer now + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer + + // ----------------------------------------------------------------------- + // GLViewPort variables + // ------------------ + /* Work with float values for the XFB supplement and aspect ratio functions. These are default + values that are used if the XFB supplement and the keep aspect ratio function are unused */ + float FloatGLWidth = (float)OpenGL_GetWidth(); + float FloatGLHeight = (float)OpenGL_GetHeight(); + float FloatXOffset = 0, FloatYOffset = 0; + // ------------------------------------- + + + // ----------------------------------------------------------------------- + // XFB supplement, fix the black borders problem + // ------------------ + /* I'm limiting it to the stretch to fit option because I don't know how the other mode works. The reason + I don't allow this option together with UseXFB is that they are supplements and the XFB function + should be able to produce the same result */ + if(g_Config.bStretchToFit && !g_Config.bUseXFB) + { + // The rendering window size + float WinWidth = (float)OpenGL_GetWidth(); + float WinHeight = (float)OpenGL_GetHeight(); + + // The fraction of the screen that the image occupies + // Rc.right and rc.bottom is the original picture pixel size + /* There is a +1 in Rc (earlier called multirc, the input to this function), but these + adjustments seems to work better without it. */ + float WidthRatio = (float)(rc.right - 1) / 640.0f; + float HeightRatio = (float)(rc.bottom - 1) / 480.0f; + + // The pixel size of the image on the screen, adjusted for the actual window size + float OldWidth = WidthRatio * (float)WinWidth; + float OldHeight = HeightRatio * (float)WinHeight; + + // The adjusted width and height + FloatGLWidth = ceil((float)WinWidth / WidthRatio); + FloatGLHeight = ceil((float)WinHeight / HeightRatio); + + // The width and height deficit in actual pixels + float WidthDeficit = (float)WinWidth - OldWidth; + float HeightDeficit = (float)WinHeight - OldHeight; + + // The picture will be drawn from the bottom so we need this YOffset + // The X-axis needs no adjustment because the picture begins from the left + FloatYOffset = -HeightDeficit / HeightRatio; + + // ----------------------------------------------------------------------- + // Logging + // ------------------ + /* + Console::ClearScreen(); + Console::Print("Bpmem L:%i T:%i X:%i Y:%i\n", bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bpmem.copyTexSrcWH.x, bpmem.copyTexSrcWH.y); + Console::Print("Input Left:%i Top:%i Right:%i Bottom:%i\n", rc.left, rc.top, rc.right, rc.bottom); + Console::Print("Old picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f\n", WidthRatio, OldWidth, HeightRatio, OldHeight); + Console::Print("New picture: Width[%1.2f]:%4.0f Height[%1.2f]:%4.0f YOffset:%4.0f YDeficit:%4.0f\n", WidthRatio, WinWidth, HeightRatio, WinHeight, FloatYOffset, HeightDeficit); + Console::Print("----------------------------------------------------------------\n"); + */ + // ------------------------------ + } + // ------------------------------ + + + + // ----------------------------------------------------------------------- + /* Keep aspect ratio at 4:3. This may be interesting if you for example have a 5:4 screen but don't like + the stretching, and would rather have a letterbox. */ + // Output: GLWidth, GLHeight, XOffset, YOffset + // ------------------ + + // The rendering window size + float WinWidth = (float)OpenGL_GetWidth(); + float WinHeight = (float)OpenGL_GetHeight(); + // The rendering window aspect ratio as a fraction of the 4:3 ratio + float Ratio = WinWidth / WinHeight / (4.0f / 3.0f); + float wAdj, hAdj; + // Actual pixel size of the picture after adjustment + float PictureWidth = WinWidth, PictureHeight = WinHeight; + + // This function currently only works together with the Stretch To Fit option + if (g_Config.bKeepAR && g_Config.bStretchToFit) + { + // 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) + { + // ------------------------------------------------ + // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen + // ---------------- + wAdj = Ratio; + hAdj = 1.0; + FloatGLWidth = FloatGLWidth / wAdj; + FloatGLHeight = FloatGLHeight / hAdj; + // -------------------- + + // ------------------------------------------------ + // Calculate the new X offset + // ---------------- + // The picture width + PictureWidth = WinWidth / Ratio; + // Move the left of the picture to the middle of the screen + FloatXOffset = FloatXOffset + WinWidth / 2.0f; + // Then remove half the picture height to move it to the horizontal center + FloatXOffset = FloatXOffset - PictureWidth / 2.0f; + // -------------------- + } + // The window is to high, we have to limit the height + else + { + // ------------------------------------------------ + // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen + // ---------------- + // Invert the ratio to make it > 1 + Ratio = 1.0f / Ratio; + wAdj = 1.0f; + hAdj = Ratio; + FloatGLWidth = FloatGLWidth / wAdj; + FloatGLHeight = FloatGLHeight / hAdj; + // -------------------- + + // ------------------------------------------------ + // Calculate the new Y offset + // ---------------- + // The picture height + PictureHeight = WinHeight / Ratio; + // Keep the picture on the bottom of the screen, this is needed because YOffset may not be 0 here + FloatYOffset = FloatYOffset / hAdj; + // Move the bottom of the picture to the middle of the screen + FloatYOffset = FloatYOffset + WinHeight / 2.0f; + // Then remove half the picture height to move it to the vertical center + FloatYOffset = FloatYOffset - PictureHeight / 2.0f; + // -------------------- + } + + // ----------------------------------------------------------------------- + // Logging + // ------------------ + /* + Console::Print("Screen Width:%4.0f Height:%4.0f Ratio:%1.2f\n", WinWidth, WinHeight, Ratio); + Console::Print("GL Width:%4.1f Height:%4.1f\n", FloatGLWidth, FloatGLHeight); + Console::Print("Picture Width:%4.1f Height:%4.1f YOffset:%4.0f\n", PictureWidth, PictureHeight, FloatYOffset); + Console::Print("----------------------------------------------------------------\n"); + */ + // ------------------------------ + } + // ------------------------------------- + + // ----------------------------------------------------------------------- + /* Adjustments to + FloatGLWidth + FloatGLHeight + XOffset + YOffset + are done. Calculate the new new windows width and height. */ + // -------------------- + int GLx = OpenGL_GetXoff(); // These two are zero + int GLy = OpenGL_GetYoff(); + int GLWidth = ceil(FloatGLWidth); + int GLHeight = ceil(FloatGLHeight); + + // Because there is no round() function we use round(float) = floor(float + 0.5) instead + int YOffset = floor(FloatYOffset + 0.5); + int XOffset = floor(FloatXOffset+ 0.5); + // ------------------------------------- + + + // Update GLViewPort + glViewport( + GLx + XOffset, + GLy + YOffset, + GLWidth, + GLHeight + ); + + // ----------------------------------------------------------------------- + // Show the finished picture + // -------------------- + // Reset GL state + ResetGLState(); + + // Texture map s_RenderTargets[s_curtarget] onto the main buffer + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); + TextureMngr::EnableTexRECT(0); + + // Disable all other stages + for (int i = 1; i < 8; ++i) + TextureMngr::DisableStage(i); + + GL_REPORT_ERRORD(); + + // Place the texture + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(-1,-1); + glTexCoord2f(0, (float)GetTargetHeight()); glVertex2f(-1,1); + glTexCoord2f((float)GetTargetWidth(), (float)GetTargetHeight()); glVertex2f(1,1); + glTexCoord2f((float)GetTargetWidth(), 0); glVertex2f(1,-1); + glEnd(); + + // Wireframe + if (g_Config.bWireFrame) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureMngr::DisableStage(0); + // ------------------------------------- + + + // ----------------------------------------------------------------------- + /* Blacken out the borders in the 4:3 or the coming 16:9 aspect ratio modes. Somewhere in BPStructs + 0x52 or elsewhere the area outside the actual picture, that we now show with the aspect ratio option + has been filled with either for example white, or have copies of old renderings on it. So we replace + that with blacknes. */ + // -------------------- + if(g_Config.bKeepAR) + { + // Set current drawing color to red + glColor3f(0.0, 0.0, 0.0); // Black + + /* This doesn't work + glRecti, glRectf( + (float)Left, + (float)Right, + (float)Top, + (float)Bottom); */ + + /* The glVertex3f() coordinates are: + Top: 1 to -1 from top to bottom + Left: 1 to -1 from right to left + Height and width is therefore 2.0, zero is the center of the screen + */ + // The fraction of the screen that the image occupies + /* It's hard to make a border that always exactly begin where the screen ends. The ( -1) here will + sometimes hide one pixel to many, but if we use (- 0) we will on the other hand sometimes show + one line of pixels that we should not show. But a -0.5 adjustment seemed just right, it never hid + one pixel to much, and never one to little. So I settle with a -0.5 adjustment here. */ + float HeightRatio = (((float)(rc.bottom)) - 0.5) / 480.0f; + + // Bottom border float FLeft = 1.0, FWidth = -2.0, - FHeight = 2.0 * (1.0 - HeightRatio),
- FTop = -1.0 + FHeight;
-
+ FHeight = 2.0 * (1.0 - HeightRatio), + FTop = -1.0 + FHeight; + glBegin(GL_POLYGON); glVertex3f (FLeft, FTop - FHeight, 0.0); glVertex3f (FLeft + FWidth, FTop - FHeight, 0.0); glVertex3f (FLeft + FWidth, FTop, 0.0); glVertex3f (FLeft, FTop, 0.0); - glEnd();
- //Console::Print("Border Left:%1.3f Top:%1.3f Width:%1.3f Height:%1.3f\n", FLeft, FTop, FWidth, FHeight);
- }
- // -------------------------------------
-
-
- // Place messages on the picture, then copy it to the screen
- SwapBuffers();
-
- RestoreGLState();
-#endif
- GL_REPORT_ERRORD();
-
- g_Config.iSaveTargetId = 0;
-
-
- // for testing zbuffer targets
- //Renderer::SetZBufferRender();
- //SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, GetTargetWidth(), GetTargetHeight());
-}
-////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// We can now draw whatever we want on top of the picture. Then we copy the final picture to the output.
-// ----------------------
-void Renderer::SwapBuffers()
-{
- // -----------------------------------------------------------------------
- /* Draw messages on the screen */
- // --------------------
- static int fpscount;
- static int s_fps;
- static unsigned long lasttime;
- char debugtext_buffer[8192];
- char *p = debugtext_buffer;
- p[0] = 0;
-
- ++fpscount;
- if (timeGetTime() - lasttime > 1000)
- {
- lasttime = timeGetTime();
- s_fps = fpscount;
- fpscount = 0;
- }
-
- if (g_Config.bShowFPS)
- {
- p+=sprintf(p, "FPS: %d\n", s_fps);
- }
-
- if (g_Config.bOverlayStats) {
- 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);
- p+=sprintf(p,"%s",text1.c_str());
- }
-
- if (g_Config.bOverlayBlendStats)
- {
- p+=sprintf(p,"LogicOp Mode: %i\n", stats.logicOpMode);
- p+=sprintf(p,"Source Factor: %i\n", stats.srcFactor);
- p+=sprintf(p,"Destination Factor: %i\n", stats.dstFactor);
- p+=sprintf(p,"Dithering: %s\n", stats.dither==1 ? "Enabled" : "Disabled");
- p+=sprintf(p,"Color Update: %s\n", stats.colorUpdate==1 ? "Enabled" : "Disabled");
- p+=sprintf(p,"Alpha Update: %s\n", stats.alphaUpdate==1 ? "Enabled" : "Disabled");
- p+=sprintf(p,"Dst Alpha Enabled: %s\n", stats.dstAlphaEnable==1 ? "Enabled" : "Disabled");
- p+=sprintf(p,"Dst Alpha: %08x\n", stats.dstAlpha);
-
- }
-
- 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);
-
- OSD::DrawMessages();
- // -----------------------------
-
-
-#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();
-
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
-
- GL_REPORT_ERRORD();
-
- // Clean out old stuff from caches
- PixelShaderCache::Cleanup();
- TextureMngr::ProgressiveCleanup();
-
- frameCount++;
-
- // New frame
- stats.ResetFrame();
-
- // Render to the framebuffer.
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
-
- if (nZBufferRender > 0) {
- if (--nZBufferRender == 0) {
- // turn off
- nZBufferRender = 0;
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
- Renderer::SetRenderMode(RM_Normal); // turn off any zwrites
- }
- }
-}
-
-void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
-{
- int nBackbufferWidth = (int)OpenGL_GetWidth();
- int nBackbufferHeight = (int)OpenGL_GetHeight();
- 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);
-}
-
-bool Renderer::SaveRenderTarget(const char* filename, int jpeg)
-{
- bool bflip = true;
- int nBackbufferHeight = (int)OpenGL_GetHeight();
- int nBackbufferWidth = (int)OpenGL_GetWidth();
-
- std::vector<u32> data(nBackbufferWidth * nBackbufferHeight);
- glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
- if (glGetError() != GL_NO_ERROR)
- return false;
-
- if (bflip) {
- // swap scanlines
- std::vector<u32> scanline(nBackbufferWidth);
- for (int i = 0; i < nBackbufferHeight/2; ++i) {
- memcpy(&scanline[0], &data[i*nBackbufferWidth], nBackbufferWidth*4);
- memcpy(&data[i*nBackbufferWidth], &data[(nBackbufferHeight-i-1)*nBackbufferWidth], nBackbufferWidth*4);
- memcpy(&data[(nBackbufferHeight-i-1)*nBackbufferWidth], &scanline[0], nBackbufferWidth*4);
- }
- }
-
- return SaveTGA(filename, nBackbufferWidth, nBackbufferHeight, &data[0]);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture.
-// Call schedule: Called from VertexShaderManager
-// ----------------------
-void UpdateViewport()
-{
- // -----------------------------------------------------------------------
- // Logging
- // ------------------
- // 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
-
- /*INFO_LOG("view: topleft=(%f,%f), wh=(%f,%f), z=(%f,%f)\n",
- 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);*/
- // --------------------------
-
-
- // -----------------------------------------------------------------------
- // GLViewPort variables
- // ------------------
- int GLWidth, GLHeight, GLx, GLy;
- float FloatGLWidth = fabs(2 * xfregs.rawViewport[0]);
- float FloatGLHeight = fabs(2 * xfregs.rawViewport[1]);
-
- // rawViewport[0] = 320, rawViewport[1] = -240
- int scissorXOff = bpmem.scissorOffset.x * 2 - 342;
- int scissorYOff = bpmem.scissorOffset.y * 2 - 342;
- // -------------------------------------
-
-
- // -----------------------------------------------------------------------
- // Stretch picture while keeping the native resolution
- // ------------------
- if (g_Config.bStretchToFit)
- {
- GLx = (int)(xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff);
- GLy = Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff));
- // Round up to the nearest integer
- GLWidth = (int)ceil(FloatGLWidth);
- GLHeight = (int)ceil(FloatGLHeight);
- }
- // -----------------------------------------------------------------------
- // Stretch picture with increased internal resolution
- // ------------------
- else
- {
- float MValueX = OpenGL_GetXmax();
- float MValueY = OpenGL_GetYmax();
-
- GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff) * MValueX);
- GLy = (int)ceil(Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff)) * MValueY);
- GLWidth = (int)ceil(abs((int)(2 * xfregs.rawViewport[0])) * MValueX);
- GLHeight = (int)ceil(abs((int)(2 * xfregs.rawViewport[1])) * MValueY);
- }
- // -------------------------------------
-
-
- // Update the view port
- glViewport(
- GLx, GLy,
- GLWidth, GLHeight
- );
-
-
- // -----------------------------------------------------------------------
- // GLDepthRange
- // ------------------
- double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777215.0f;
- double GLFar = xfregs.rawViewport[5] / 16777215.0f;
- glDepthRange(GLNear, GLFar);
- // -------------------------------------
-
- // 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();
- Console::Print("----------------------------------------------------------------\n");
- Console::Print("Top window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcTop.left, RcTop.top, RcTop.right - RcTop.left, RcTop.bottom - RcTop.top);
- Console::Print("Parent window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcParent.left, RcParent.top, RcParent.right - RcParent.left, RcParent.bottom - RcParent.top);
- Console::Print("Child window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcChild.left, RcChild.top, RcChild.right - RcChild.left, RcChild.bottom - RcChild.top);
- Console::Print("----------------------------------------------------------------\n");
- Console::Print("Res. MValue: X:%f Y:%f XOffs:%f YOffs:%f\n", OpenGL_GetXmax(), OpenGL_GetYmax(), OpenGL_GetXoff(), OpenGL_GetYoff());
- Console::Print("GLViewPort: X:%03i Y:%03i Width:%03i Height:%03i\n", GLx, GLy, GLWidth, GLHeight);
- Console::Print("GLDepthRange: Near:%f Far:%f\n", GLNear, GLFar);
- Console::Print("GLScissor: X:%03i Y:%03i Width:%03i Height:%03i\n", GLScissorX, GLScissorY, GLScissorW, GLScissorH);
- Console::Print("----------------------------------------------------------------\n");
- */
-}
+ glEnd(); + //Console::Print("Border Left:%1.3f Top:%1.3f Width:%1.3f Height:%1.3f\n", FLeft, FTop, FWidth, FHeight); + } + // ------------------------------------- + + + // Place messages on the picture, then copy it to the screen + SwapBuffers(); + + RestoreGLState(); +#endif + GL_REPORT_ERRORD(); + + g_Config.iSaveTargetId = 0; + + + // for testing zbuffer targets + //Renderer::SetZBufferRender(); + //SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, GetTargetWidth(), GetTargetHeight()); +} +//////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// We can now draw whatever we want on top of the picture. Then we copy the final picture to the output. +// ---------------------- +void Renderer::SwapBuffers() +{ + // ----------------------------------------------------------------------- + /* Draw messages on the screen */ + // -------------------- + static int fpscount; + static int s_fps; + static unsigned long lasttime; + char debugtext_buffer[8192]; + char *p = debugtext_buffer; + p[0] = 0; + + ++fpscount; + if (timeGetTime() - lasttime > 1000) + { + lasttime = timeGetTime(); + s_fps = fpscount; + fpscount = 0; + } + + if (g_Config.bShowFPS) + { + p+=sprintf(p, "FPS: %d\n", s_fps); + } + + if (g_Config.bOverlayStats) { + 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); + p+=sprintf(p,"%s",text1.c_str()); + } + + if (g_Config.bOverlayBlendStats) + { + p+=sprintf(p,"LogicOp Mode: %i\n", stats.logicOpMode); + p+=sprintf(p,"Source Factor: %i\n", stats.srcFactor); + p+=sprintf(p,"Destination Factor: %i\n", stats.dstFactor); + p+=sprintf(p,"Dithering: %s\n", stats.dither==1 ? "Enabled" : "Disabled"); + p+=sprintf(p,"Color Update: %s\n", stats.colorUpdate==1 ? "Enabled" : "Disabled"); + p+=sprintf(p,"Alpha Update: %s\n", stats.alphaUpdate==1 ? "Enabled" : "Disabled"); + p+=sprintf(p,"Dst Alpha Enabled: %s\n", stats.dstAlphaEnable==1 ? "Enabled" : "Disabled"); + p+=sprintf(p,"Dst Alpha: %08x\n", stats.dstAlpha); + + } + + 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); + + OSD::DrawMessages(); + // ----------------------------- + + +#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(); + + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); + + GL_REPORT_ERRORD(); + + // Clean out old stuff from caches + PixelShaderCache::Cleanup(); + TextureMngr::ProgressiveCleanup(); + + frameCount++; + + // New frame + stats.ResetFrame(); + + // Render to the framebuffer. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); + + if (nZBufferRender > 0) { + if (--nZBufferRender == 0) { + // turn off + nZBufferRender = 0; + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + Renderer::SetRenderMode(RM_Normal); // turn off any zwrites + } + } +} + +void Renderer::RenderText(const char* pstr, int left, int top, u32 color) +{ + int nBackbufferWidth = (int)OpenGL_GetWidth(); + int nBackbufferHeight = (int)OpenGL_GetHeight(); + 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); +} + +bool Renderer::SaveRenderTarget(const char* filename, int jpeg) +{ + bool bflip = true; + int nBackbufferHeight = (int)OpenGL_GetHeight(); + int nBackbufferWidth = (int)OpenGL_GetWidth(); + + std::vector<u32> data(nBackbufferWidth * nBackbufferHeight); + glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]); + if (glGetError() != GL_NO_ERROR) + return false; + + if (bflip) { + // swap scanlines + std::vector<u32> scanline(nBackbufferWidth); + for (int i = 0; i < nBackbufferHeight/2; ++i) { + memcpy(&scanline[0], &data[i*nBackbufferWidth], nBackbufferWidth*4); + memcpy(&data[i*nBackbufferWidth], &data[(nBackbufferHeight-i-1)*nBackbufferWidth], nBackbufferWidth*4); + memcpy(&data[(nBackbufferHeight-i-1)*nBackbufferWidth], &scanline[0], nBackbufferWidth*4); + } + } + + return SaveTGA(filename, nBackbufferWidth, nBackbufferHeight, &data[0]); +} + +////////////////////////////////////////////////////////////////////////////////////// +// Function: This function does not have the final picture. Use Renderer::Swap() to adjust the final picture. +// Call schedule: Called from VertexShaderManager +// ---------------------- +void UpdateViewport() +{ + // ----------------------------------------------------------------------- + // Logging + // ------------------ + // 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 + + /*INFO_LOG("view: topleft=(%f,%f), wh=(%f,%f), z=(%f,%f)\n", + 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);*/ + // -------------------------- + + + // ----------------------------------------------------------------------- + // GLViewPort variables + // ------------------ + int GLWidth, GLHeight, GLx, GLy; + float FloatGLWidth = fabs(2 * xfregs.rawViewport[0]); + float FloatGLHeight = fabs(2 * xfregs.rawViewport[1]); + + // rawViewport[0] = 320, rawViewport[1] = -240 + int scissorXOff = bpmem.scissorOffset.x * 2 - 342; + int scissorYOff = bpmem.scissorOffset.y * 2 - 342; + // ------------------------------------- + + + // ----------------------------------------------------------------------- + // Stretch picture while keeping the native resolution + // ------------------ + if (g_Config.bStretchToFit) + { + GLx = (int)(xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff); + GLy = Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff)); + // Round up to the nearest integer + GLWidth = (int)ceil(FloatGLWidth); + GLHeight = (int)ceil(FloatGLHeight); + } + // ----------------------------------------------------------------------- + // Stretch picture with increased internal resolution + // ------------------ + else + { + float MValueX = OpenGL_GetXmax(); + float MValueY = OpenGL_GetYmax(); + + GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - 342 - scissorXOff) * MValueX); + GLy = (int)ceil(Renderer::GetTargetHeight() - ((int)(xfregs.rawViewport[4] - xfregs.rawViewport[1] - 342 - scissorYOff)) * MValueY); + GLWidth = (int)ceil(abs((int)(2 * xfregs.rawViewport[0])) * MValueX); + GLHeight = (int)ceil(abs((int)(2 * xfregs.rawViewport[1])) * MValueY); + } + // ------------------------------------- + + + // Update the view port + glViewport( + GLx, GLy, + GLWidth, GLHeight + ); + + + // ----------------------------------------------------------------------- + // GLDepthRange + // ------------------ + double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777215.0f; + double GLFar = xfregs.rawViewport[5] / 16777215.0f; + glDepthRange(GLNear, GLFar); + // ------------------------------------- + + // 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(); + Console::Print("----------------------------------------------------------------\n"); + Console::Print("Top window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcTop.left, RcTop.top, RcTop.right - RcTop.left, RcTop.bottom - RcTop.top); + Console::Print("Parent window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcParent.left, RcParent.top, RcParent.right - RcParent.left, RcParent.bottom - RcParent.top); + Console::Print("Child window: X:%03i Y:%03i Width:%03i Height:%03i\n", RcChild.left, RcChild.top, RcChild.right - RcChild.left, RcChild.bottom - RcChild.top); + Console::Print("----------------------------------------------------------------\n"); + Console::Print("Res. MValue: X:%f Y:%f XOffs:%f YOffs:%f\n", OpenGL_GetXmax(), OpenGL_GetYmax(), OpenGL_GetXoff(), OpenGL_GetYoff()); + Console::Print("GLViewPort: X:%03i Y:%03i Width:%03i Height:%03i\n", GLx, GLy, GLWidth, GLHeight); + Console::Print("GLDepthRange: Near:%f Far:%f\n", GLNear, GLFar); + Console::Print("GLScissor: X:%03i Y:%03i Width:%03i Height:%03i\n", GLScissorX, GLScissorY, GLScissorW, GLScissorH); + Console::Print("----------------------------------------------------------------\n"); + */ +} |
