// Copyright (C) 2003-2009 Dolphin Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ #include "Common.h" #include "Core.h" #include "GLUtil.h" #include "Renderer.h" #include "main.h" #include "Statistics.h" #include "RasterFont.h" #define VSYNC_ENABLED 0 static GLuint s_RenderTarget = 0; RasterFont* s_pfont = NULL; void Renderer::Init() { if (!OpenGL_Create(640, 480)) // 640x480 will be the default if all else fails { Core::Callback_VideoLog("Renderer::Create failed\n"); return; } } void Renderer::Shutdown() { glDeleteTextures(1, &s_RenderTarget); delete s_pfont; s_pfont = 0; } void Renderer::Prepare() { OpenGL_MakeCurrent(); // Init extension support. if (glewInit() != GLEW_OK) { ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?"); return; } // Handle VSync on/off #ifdef _WIN32 if (WGLEW_EXT_swap_control) wglSwapIntervalEXT(VSYNC_ENABLED); else ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)Does your video card support OpenGL 2.x?"); #elif defined(HAVE_X11) && HAVE_X11 if (glXSwapIntervalSGI) glXSwapIntervalSGI(VSYNC_ENABLED); else ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)"); #endif glStencilFunc(GL_ALWAYS, 0, 0); // used by hw rasterizer if it enables blending and depth test glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LEQUAL); glShadeModel(GL_SMOOTH); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); glEnable(GL_SCISSOR_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment glDisable(GL_LIGHTING); glDisable(GL_BLEND); glDisable(GL_STENCIL_TEST); //glDisable(GL_SCISSOR_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); s_pfont = new RasterFont(); // legacy multitexturing: select texture channel only. glActiveTexture(GL_TEXTURE0); glClientActiveTexture(GL_TEXTURE0); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glGenTextures(1, &s_RenderTarget); glEnable(GL_TEXTURE_RECTANGLE_ARB); } void Renderer::RenderText(const char* pstr, int left, int top, u32 color) { int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth(); int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight(); glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f, ((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f); s_pfont->printMultilineText(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight, 0, nBackbufferWidth, nBackbufferHeight); } void Renderer::DrawDebugText() { char debugtext_buffer[8192]; char *p = debugtext_buffer; p[0] = 0; if (g_SWVideoConfig.bShowStats) { p+=sprintf(p,"Objects: %i\n",stats.thisFrame.numDrawnObjects); p+=sprintf(p,"Primatives: %i\n",stats.thisFrame.numPrimatives); p+=sprintf(p,"Vertices Loaded: %i\n",stats.thisFrame.numVerticesLoaded); p+=sprintf(p,"Triangles Input: %i\n",stats.thisFrame.numTrianglesIn); p+=sprintf(p,"Triangles Rejected: %i\n",stats.thisFrame.numTrianglesRejected); p+=sprintf(p,"Triangles Culled: %i\n",stats.thisFrame.numTrianglesCulled); p+=sprintf(p,"Triangles Clipped: %i\n",stats.thisFrame.numTrianglesClipped); p+=sprintf(p,"Triangles Drawn: %i\n",stats.thisFrame.numTrianglesDrawn); p+=sprintf(p,"Rasterized Pix: %i\n",stats.thisFrame.rasterizedPixels); p+=sprintf(p,"TEV Pix In: %i\n",stats.thisFrame.tevPixelsIn); p+=sprintf(p,"TEV Pix Out: %i\n",stats.thisFrame.tevPixelsOut); } // Render a shadow, and then the text. Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000); Renderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00); } void Renderer::DrawTexture(u8 *texture, int width, int height) { GLsizei glWidth = (GLsizei)OpenGL_GetBackbufferWidth(); GLsizei glHeight = (GLsizei)OpenGL_GetBackbufferHeight(); // Update GLViewPort glViewport(0, 0, glWidth, glHeight); glScissor(0, 0, glWidth, glHeight); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GL_REPORT_ERRORD(); GLfloat u_max = (GLfloat)width; GLfloat v_max = (GLfloat)glHeight; glBegin(GL_QUADS); glTexCoord2f(0, v_max); glVertex2f(-1, -1); glTexCoord2f(0, 0); glVertex2f(-1, 1); glTexCoord2f(u_max, 0); glVertex2f( 1, 1); glTexCoord2f(u_max, v_max); glVertex2f( 1, -1); glEnd(); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } void Renderer::SwapBuffer() { DrawDebugText(); glFlush(); OpenGL_SwapBuffers(); GL_REPORT_ERRORD(); stats.ResetFrame(); // Clear framebuffer glClearColor(0, 0, 0, 0); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GL_REPORT_ERRORD(); }