2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: RageDisplay
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
|
|
|
|
Chris Danford
|
2003-04-25 21:05:40 +00:00
|
|
|
Glenn Maynard
|
2002-05-20 08:59:37 +00:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "RageDisplay.h"
|
2002-12-30 00:48:31 +00:00
|
|
|
#include "RageDisplayInternal.h"
|
2002-05-20 08:59:37 +00:00
|
|
|
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "RageLog.h"
|
2002-07-27 19:29:51 +00:00
|
|
|
#include "RageTimer.h"
|
|
|
|
|
#include "RageException.h"
|
2002-08-13 23:26:46 +00:00
|
|
|
#include "RageTexture.h"
|
2002-11-12 09:29:46 +00:00
|
|
|
#include "RageTextureManager.h"
|
2002-10-28 05:30:45 +00:00
|
|
|
#include "RageMath.h"
|
2002-11-11 04:53:31 +00:00
|
|
|
#include "RageTypes.h"
|
|
|
|
|
#include "GameConstantsAndTypes.h"
|
2003-01-24 23:57:02 +00:00
|
|
|
#include "StepMania.h"
|
2002-06-14 22:25:22 +00:00
|
|
|
|
2003-04-07 00:54:32 +00:00
|
|
|
#include "arch/arch.h"
|
|
|
|
|
#include "arch/LowLevelWindow/LowLevelWindow.h"
|
|
|
|
|
|
2003-01-25 03:57:14 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
|
2002-11-12 00:51:27 +00:00
|
|
|
RageDisplay* DISPLAY = NULL;
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
////////////
|
|
|
|
|
// Globals
|
|
|
|
|
////////////
|
2002-11-11 09:56:07 +00:00
|
|
|
RageTimer g_LastCheckTimer;
|
2002-11-11 04:53:31 +00:00
|
|
|
int g_iNumVerts;
|
2003-01-11 05:12:17 +00:00
|
|
|
int g_iFPS, g_iVPF, g_iCFPS;
|
2002-11-15 02:47:08 +00:00
|
|
|
|
2002-11-15 08:01:34 +00:00
|
|
|
int g_PerspectiveMode = 0;
|
|
|
|
|
|
2003-01-08 22:30:32 +00:00
|
|
|
int g_ModelMatrixCnt=0;
|
2002-11-11 20:43:30 +00:00
|
|
|
int RageDisplay::GetFPS() const { return g_iFPS; }
|
|
|
|
|
int RageDisplay::GetVPF() const { return g_iVPF; }
|
2003-01-11 05:12:17 +00:00
|
|
|
int RageDisplay::GetCumFPS() const { return g_iCFPS; }
|
2002-11-11 20:43:30 +00:00
|
|
|
|
|
|
|
|
static int g_iFramesRenderedSinceLastCheck,
|
2003-01-11 05:12:17 +00:00
|
|
|
g_iFramesRenderedSinceLastReset,
|
|
|
|
|
g_iVertsRenderedSinceLastCheck,
|
|
|
|
|
g_iNumChecksSinceLastReset;
|
2003-01-08 23:16:28 +00:00
|
|
|
|
2002-12-30 04:04:18 +00:00
|
|
|
PWSWAPINTERVALEXTPROC GLExt::wglSwapIntervalEXT;
|
2003-01-22 22:41:05 +00:00
|
|
|
PFNGLCOLORTABLEPROC GLExt::glColorTableEXT;
|
|
|
|
|
PFNGLCOLORTABLEPARAMETERIVPROC GLExt::glGetColorTableParameterivEXT;
|
2002-11-12 00:51:27 +00:00
|
|
|
|
2003-01-11 05:12:17 +00:00
|
|
|
/* We don't actually use normals (we don't tunr on lighting), there's just
|
|
|
|
|
* no GL_T2F_C4F_V3F. */
|
|
|
|
|
const GLenum RageVertexFormat = GL_T2F_C4F_N3F_V3F;
|
2003-01-09 04:35:20 +00:00
|
|
|
|
2003-04-07 00:54:32 +00:00
|
|
|
|
|
|
|
|
LowLevelWindow *wind;
|
|
|
|
|
|
2002-11-12 00:51:27 +00:00
|
|
|
void GetGLExtensions(set<string> &ext)
|
|
|
|
|
{
|
|
|
|
|
const char *buf = (const char *)glGetString(GL_EXTENSIONS);
|
|
|
|
|
|
|
|
|
|
vector<CString> lst;
|
|
|
|
|
split(buf, " ", lst);
|
|
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < lst.size(); ++i)
|
|
|
|
|
ext.insert(lst[i]);
|
|
|
|
|
}
|
2002-08-29 21:48:57 +00:00
|
|
|
|
2002-11-12 09:29:46 +00:00
|
|
|
RageDisplay::RageDisplay( bool windowed, int width, int height, int bpp, int rate, bool vsync )
|
2002-08-22 08:49:41 +00:00
|
|
|
{
|
2003-01-14 21:58:01 +00:00
|
|
|
LOG->Trace( "RageDisplay::RageDisplay()" );
|
2003-01-24 23:57:02 +00:00
|
|
|
|
2002-12-30 00:48:31 +00:00
|
|
|
m_oglspecs = new oglspecs_t;
|
2003-04-07 00:54:32 +00:00
|
|
|
|
|
|
|
|
wind = MakeLowLevelWindow();
|
|
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
SetVideoMode( windowed, width, height, bpp, rate, vsync );
|
2002-11-12 00:51:27 +00:00
|
|
|
|
2003-01-19 21:05:03 +00:00
|
|
|
// Log driver details
|
2003-01-19 21:11:35 +00:00
|
|
|
LOG->Info("OGL Vendor: %s", glGetString(GL_VENDOR));
|
|
|
|
|
LOG->Info("OGL Renderer: %s", glGetString(GL_RENDERER));
|
|
|
|
|
LOG->Info("OGL Version: %s", glGetString(GL_VERSION));
|
2003-01-19 21:51:46 +00:00
|
|
|
LOG->Info("OGL Extensions: %s", glGetString(GL_EXTENSIONS));
|
|
|
|
|
if( IsSoftwareRenderer() )
|
|
|
|
|
LOG->Warn("This is a software renderer!");
|
2003-01-19 21:05:03 +00:00
|
|
|
|
|
|
|
|
|
2002-11-15 02:47:08 +00:00
|
|
|
/* Log this, so if people complain that the radar looks bad on their
|
|
|
|
|
* system we can compare them: */
|
2002-12-30 00:48:31 +00:00
|
|
|
glGetFloatv(GL_LINE_WIDTH_RANGE, m_oglspecs->line_range);
|
|
|
|
|
glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &m_oglspecs->line_granularity);
|
2003-04-22 05:22:05 +00:00
|
|
|
LOG->Info("Line width range: %.3f-%.3f +%.3f", m_oglspecs->line_range[0], m_oglspecs->line_range[1], m_oglspecs->line_granularity);
|
2003-01-25 00:19:21 +00:00
|
|
|
|
2002-12-30 00:48:31 +00:00
|
|
|
glGetFloatv(GL_POINT_SIZE_RANGE, m_oglspecs->point_range);
|
|
|
|
|
glGetFloatv(GL_POINT_SIZE_GRANULARITY, &m_oglspecs->point_granularity);
|
2003-04-22 05:22:05 +00:00
|
|
|
LOG->Info("Point size range: %.3f-%.3f +%.3f", m_oglspecs->point_range[0], m_oglspecs->point_range[1], m_oglspecs->point_granularity);
|
2003-02-20 21:22:18 +00:00
|
|
|
|
2003-03-06 09:25:48 +00:00
|
|
|
/* sizeof("string constant") is the size of the pointer (~4), not the length of the string. */
|
|
|
|
|
m_oglspecs->bAALinesCauseProblems = strncmp((const char*)glGetString(GL_RENDERER),"3Dfx/Voodoo3 (tm)/2 TMUs/16 MB SDRAM/ICD (Nov 2 2000)",strlen("3Dfx/Voodoo3"))==0;
|
2003-02-20 21:22:18 +00:00
|
|
|
if( m_oglspecs->bAALinesCauseProblems )
|
|
|
|
|
LOG->Info("Anti-aliased lines are known to cause problems with this driver.");
|
2003-03-06 09:25:48 +00:00
|
|
|
m_oglspecs->bPackedPixelsCauseProblems =
|
|
|
|
|
strncmp((const char*)glGetString(GL_RENDERER),"GLDirect",strlen("GLDirect"))==0;
|
|
|
|
|
if( m_oglspecs->bPackedPixelsCauseProblems )
|
|
|
|
|
LOG->Info("Packed pixel formats are known to cause problems with this driver.");
|
2002-08-22 08:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-12 02:28:26 +00:00
|
|
|
void RageDisplay::Update(float fDeltaTime)
|
|
|
|
|
{
|
|
|
|
|
wind->Update(fDeltaTime);
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-19 21:51:46 +00:00
|
|
|
bool RageDisplay::IsSoftwareRenderer()
|
|
|
|
|
{
|
|
|
|
|
return
|
2003-02-20 21:22:18 +00:00
|
|
|
( strcmp((const char*)glGetString(GL_VENDOR),"Microsoft Corporation")==0 ) &&
|
|
|
|
|
( strcmp((const char*)glGetString(GL_RENDERER),"GDI Generic")==0 );
|
2003-01-19 21:51:46 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-12 09:29:46 +00:00
|
|
|
void RageDisplay::SetupOpenGL()
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Set up OpenGL for 2D rendering.
|
|
|
|
|
*/
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set state variables
|
|
|
|
|
*/
|
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
2002-11-15 08:13:51 +00:00
|
|
|
|
2002-12-17 05:05:41 +00:00
|
|
|
/* Use <= for depth testing. This lets us set all components of an actor to the
|
|
|
|
|
* same depth. */
|
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
|
|
2002-11-18 20:55:23 +00:00
|
|
|
/* Line antialiasing is fast on most hardware, and saying "don't care"
|
|
|
|
|
* should turn it off if it isn't. */
|
|
|
|
|
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
|
|
|
|
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
|
|
|
|
|
2002-11-15 08:13:51 +00:00
|
|
|
/* Initialize the default ortho projection. */
|
2003-03-06 09:58:25 +00:00
|
|
|
|
2003-04-23 02:23:51 +00:00
|
|
|
LoadMenuPerspective(0); // 0 FOV = ortho
|
2002-11-12 09:29:46 +00:00
|
|
|
}
|
2002-11-12 20:39:08 +00:00
|
|
|
|
2002-05-20 08:59:37 +00:00
|
|
|
RageDisplay::~RageDisplay()
|
|
|
|
|
{
|
2003-04-07 00:54:32 +00:00
|
|
|
delete wind;
|
2002-12-30 00:48:31 +00:00
|
|
|
delete m_oglspecs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RageDisplay::HasExtension(CString ext) const
|
|
|
|
|
{
|
|
|
|
|
return m_oglspecs->glExts.find(ext) != m_oglspecs->glExts.end();
|
2002-08-29 22:30:06 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-12 20:39:08 +00:00
|
|
|
void RageDisplay::SetupExtensions()
|
|
|
|
|
{
|
|
|
|
|
double fGLVersion = atof( (const char *) glGetString(GL_VERSION) );
|
2002-12-30 00:48:31 +00:00
|
|
|
m_oglspecs->glVersion = int(roundf(fGLVersion * 10));
|
|
|
|
|
GetGLExtensions(m_oglspecs->glExts);
|
|
|
|
|
|
|
|
|
|
/* Check for extensions: */
|
|
|
|
|
m_oglspecs->EXT_texture_env_combine = HasExtension("GL_EXT_texture_env_combine");
|
|
|
|
|
m_oglspecs->WGL_EXT_swap_control = HasExtension("WGL_EXT_swap_control");
|
2003-01-22 22:41:05 +00:00
|
|
|
m_oglspecs->EXT_paletted_texture = HasExtension("GL_EXT_paletted_texture");
|
2002-12-30 00:48:31 +00:00
|
|
|
|
|
|
|
|
/* Find extension functions. */
|
2003-04-07 00:54:32 +00:00
|
|
|
GLExt::wglSwapIntervalEXT = (PWSWAPINTERVALEXTPROC) wind->GetProcAddress("wglSwapIntervalEXT");
|
|
|
|
|
GLExt::glColorTableEXT = (PFNGLCOLORTABLEPROC) wind->GetProcAddress("glColorTableEXT");
|
|
|
|
|
GLExt::glGetColorTableParameterivEXT = (PFNGLCOLORTABLEPARAMETERIVPROC) wind->GetProcAddress("glGetColorTableParameterivEXT");
|
2003-01-22 22:41:05 +00:00
|
|
|
|
2002-12-30 00:48:31 +00:00
|
|
|
/* Make sure we have all components for detected extensions. */
|
|
|
|
|
if(m_oglspecs->WGL_EXT_swap_control)
|
2003-01-31 18:19:58 +00:00
|
|
|
{
|
2003-02-14 23:29:30 +00:00
|
|
|
if(!GLExt::wglSwapIntervalEXT)
|
2003-01-31 18:19:58 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn("wglSwapIntervalEXT but wglSwapIntervalEXT() not found");
|
|
|
|
|
m_oglspecs->WGL_EXT_swap_control=false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-01-22 22:41:05 +00:00
|
|
|
if(m_oglspecs->EXT_paletted_texture)
|
|
|
|
|
{
|
2003-02-14 23:29:30 +00:00
|
|
|
if(!GLExt::glColorTableEXT || !GLExt::glGetColorTableParameterivEXT)
|
2003-01-31 18:19:58 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn("GL_EXT_paletted_texture but glColorTableEXT or glGetColorTableParameterivEXT not found");
|
|
|
|
|
m_oglspecs->EXT_paletted_texture = false;
|
|
|
|
|
}
|
2003-01-22 22:41:05 +00:00
|
|
|
}
|
2002-11-12 20:39:08 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-12 09:29:46 +00:00
|
|
|
/* Set the video mode. In some cases, changing the video mode will reset
|
|
|
|
|
* the rendering context; returns true if we need to reload textures. */
|
|
|
|
|
bool RageDisplay::SetVideoMode( bool windowed, int width, int height, int bpp, int rate, bool vsync )
|
2002-08-29 22:30:06 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
// LOG->Trace( "RageDisplay::SetVideoMode( %d, %d, %d, %d, %d, %d )", windowed, width, height, bpp, rate, vsync );
|
2003-04-07 00:54:32 +00:00
|
|
|
bool NewOpenGLContext = wind->SetVideoMode( windowed, width, height, bpp, rate, vsync );
|
2002-08-29 22:30:06 +00:00
|
|
|
|
2003-04-07 00:54:32 +00:00
|
|
|
if(NewOpenGLContext)
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-01-20 21:54:58 +00:00
|
|
|
/* We have a new OpenGL context, so we have to tell our textures that
|
|
|
|
|
* their OpenGL texture number is invalid. */
|
2002-11-16 21:21:43 +00:00
|
|
|
if(TEXTUREMAN)
|
|
|
|
|
TEXTUREMAN->InvalidateTextures();
|
2003-01-20 21:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-06 23:30:58 +00:00
|
|
|
SetupOpenGL();
|
|
|
|
|
DumpOpenGLDebugInfo();
|
|
|
|
|
|
|
|
|
|
/* Now that we've initialized, we can search for extensions (some of which
|
|
|
|
|
* we may need to set up the video mode). */
|
|
|
|
|
SetupExtensions();
|
|
|
|
|
|
|
|
|
|
/* Set vsync the Windows way, if we can. (What other extensions are there
|
|
|
|
|
* to do this, for other archs?) */
|
2003-04-12 02:28:26 +00:00
|
|
|
if(m_oglspecs->WGL_EXT_swap_control)
|
2003-04-06 23:30:58 +00:00
|
|
|
GLExt::wglSwapIntervalEXT(vsync);
|
|
|
|
|
|
2003-04-12 02:28:26 +00:00
|
|
|
ResolutionChanged();
|
2002-05-20 08:59:37 +00:00
|
|
|
|
2003-01-20 21:54:58 +00:00
|
|
|
return NewOpenGLContext;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-24 00:19:56 +00:00
|
|
|
void RageDisplay::DumpOpenGLDebugInfo()
|
|
|
|
|
{
|
|
|
|
|
#if defined(WIN32)
|
|
|
|
|
/* Dump Windows pixel format data. */
|
|
|
|
|
int Actual = GetPixelFormat(wglGetCurrentDC());
|
|
|
|
|
|
|
|
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
|
memset(&pfd, 0, sizeof(pfd));
|
|
|
|
|
pfd.nSize=sizeof(pfd);
|
|
|
|
|
pfd.nVersion=1;
|
|
|
|
|
|
|
|
|
|
int pfcnt = DescribePixelFormat(GetDC(g_hWndMain),1,sizeof(pfd),&pfd);
|
|
|
|
|
for (int i=1; i <= pfcnt; i++)
|
|
|
|
|
{
|
|
|
|
|
memset(&pfd, 0, sizeof(pfd));
|
|
|
|
|
pfd.nSize=sizeof(pfd);
|
|
|
|
|
pfd.nVersion=1;
|
|
|
|
|
DescribePixelFormat(GetDC(g_hWndMain),i,sizeof(pfd),&pfd);
|
|
|
|
|
|
|
|
|
|
bool skip = false;
|
|
|
|
|
|
|
|
|
|
bool rgba = (pfd.iPixelType==PFD_TYPE_RGBA);
|
|
|
|
|
|
|
|
|
|
bool mcd = ((pfd.dwFlags & PFD_GENERIC_FORMAT) && (pfd.dwFlags & PFD_GENERIC_ACCELERATED));
|
|
|
|
|
bool soft = ((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED));
|
|
|
|
|
bool icd = !(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED);
|
|
|
|
|
bool opengl = !!(pfd.dwFlags & PFD_SUPPORT_OPENGL);
|
|
|
|
|
bool window = !!(pfd.dwFlags & PFD_DRAW_TO_WINDOW);
|
|
|
|
|
bool dbuff = !!(pfd.dwFlags & PFD_DOUBLEBUFFER);
|
|
|
|
|
|
|
|
|
|
if(!rgba || soft || !opengl || !window || !dbuff)
|
|
|
|
|
skip = true;
|
|
|
|
|
|
|
|
|
|
/* Skip the above, unless it happens to be the one we chose. */
|
|
|
|
|
if(skip && i != Actual)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CString str = ssprintf("Mode %i: ", i);
|
|
|
|
|
if(i == Actual) str += "*** ";
|
|
|
|
|
if(skip) str += "(BOGUS) ";
|
|
|
|
|
if(soft) str += "software ";
|
|
|
|
|
if(icd) str += "ICD ";
|
|
|
|
|
if(mcd) str += "MCD ";
|
|
|
|
|
if(!rgba) str += "indexed ";
|
|
|
|
|
if(!opengl) str += "!OPENGL ";
|
|
|
|
|
if(!window) str += "!window ";
|
|
|
|
|
if(!dbuff) str += "!dbuff ";
|
|
|
|
|
|
|
|
|
|
str += ssprintf("%i (%i%i%i) ", pfd.cColorBits, pfd.cRedBits, pfd.cGreenBits, pfd.cBlueBits);
|
|
|
|
|
if(pfd.cAlphaBits) str += ssprintf("%i alpha ", pfd.cAlphaBits);
|
|
|
|
|
if(pfd.cDepthBits) str += ssprintf("%i depth ", pfd.cDepthBits);
|
|
|
|
|
if(pfd.cStencilBits) str += ssprintf("%i stencil ", pfd.cStencilBits);
|
|
|
|
|
if(pfd.cAccumBits) str += ssprintf("%i accum ", pfd.cAccumBits);
|
|
|
|
|
|
|
|
|
|
if(i == Actual && skip)
|
|
|
|
|
{
|
|
|
|
|
/* We chose a bogus format. */
|
2003-04-25 00:01:35 +00:00
|
|
|
LOG->Warn("%s", str.c_str());
|
2003-01-24 00:19:56 +00:00
|
|
|
} else
|
2003-04-25 00:01:35 +00:00
|
|
|
LOG->Info("%s", str.c_str());
|
2003-01-24 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-12 02:28:26 +00:00
|
|
|
void RageDisplay::ResolutionChanged()
|
2002-12-28 21:37:18 +00:00
|
|
|
{
|
|
|
|
|
SetViewport(0,0);
|
|
|
|
|
|
|
|
|
|
/* Clear any junk that's in the framebuffer. */
|
|
|
|
|
Clear();
|
|
|
|
|
Flip();
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-15 02:47:08 +00:00
|
|
|
void RageDisplay::SetViewport(int shift_left, int shift_down)
|
|
|
|
|
{
|
|
|
|
|
/* left and down are on a 0..SCREEN_WIDTH, 0..SCREEN_HEIGHT scale.
|
|
|
|
|
* Scale them to the actual viewport range. */
|
2003-04-07 00:54:32 +00:00
|
|
|
shift_left = int( shift_left * float(wind->GetWidth()) / SCREEN_WIDTH );
|
|
|
|
|
shift_down = int( shift_down * float(wind->GetWidth()) / SCREEN_WIDTH );
|
2002-11-15 02:47:08 +00:00
|
|
|
|
2003-04-07 00:54:32 +00:00
|
|
|
glViewport(shift_left, -shift_down, wind->GetWidth(), wind->GetHeight());
|
2002-11-15 02:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
int RageDisplay::GetMaxTextureSize() const
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
GLint size;
|
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
|
|
|
|
|
return size;
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::Clear()
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
glClearColor( 0,0,0,1 );
|
|
|
|
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::Flip()
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-04-07 00:54:32 +00:00
|
|
|
wind->SwapBuffers();
|
2002-11-11 09:56:07 +00:00
|
|
|
g_iFramesRenderedSinceLastCheck++;
|
2003-01-11 05:12:17 +00:00
|
|
|
g_iFramesRenderedSinceLastReset++;
|
2002-11-11 09:56:07 +00:00
|
|
|
|
|
|
|
|
if( g_LastCheckTimer.PeekDeltaTime() >= 1.0f ) // update stats every 1 sec.
|
|
|
|
|
{
|
|
|
|
|
g_LastCheckTimer.GetDeltaTime();
|
2003-01-11 05:12:17 +00:00
|
|
|
g_iNumChecksSinceLastReset++;
|
2002-11-11 09:56:07 +00:00
|
|
|
g_iFPS = g_iFramesRenderedSinceLastCheck;
|
2003-01-11 05:12:17 +00:00
|
|
|
g_iCFPS = g_iFramesRenderedSinceLastReset / g_iNumChecksSinceLastReset;
|
2002-11-11 20:43:30 +00:00
|
|
|
g_iVPF = g_iVertsRenderedSinceLastCheck / g_iFPS;
|
2003-01-08 23:16:28 +00:00
|
|
|
g_iFramesRenderedSinceLastCheck = g_iVertsRenderedSinceLastCheck = 0;
|
2003-01-11 05:12:17 +00:00
|
|
|
LOG->Trace( "FPS: %d, CFPS %d, VPF: %d", g_iFPS, g_iCFPS, g_iVPF );
|
2002-11-11 09:56:07 +00:00
|
|
|
}
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2003-02-10 22:08:10 +00:00
|
|
|
float RageDisplay::PredictedSecondsUntilNextFlip() const
|
|
|
|
|
{
|
|
|
|
|
float fps = max( 30.f, GetFPS() );
|
|
|
|
|
return 1.f/fps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-12-21 07:54:24 +00:00
|
|
|
void RageDisplay::ResetStats()
|
|
|
|
|
{
|
2003-01-08 23:16:28 +00:00
|
|
|
g_iFPS = g_iVPF = 0;
|
2003-01-11 05:12:17 +00:00
|
|
|
g_iFramesRenderedSinceLastCheck = g_iFramesRenderedSinceLastReset = 0;
|
|
|
|
|
g_iNumChecksSinceLastReset = 0;
|
|
|
|
|
g_iVertsRenderedSinceLastCheck = 0;
|
2002-12-21 07:54:24 +00:00
|
|
|
g_LastCheckTimer.GetDeltaTime();
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-22 22:41:05 +00:00
|
|
|
void RageDisplay::DisablePalettedTexture()
|
|
|
|
|
{
|
|
|
|
|
m_oglspecs->EXT_paletted_texture = false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-31 22:34:04 +00:00
|
|
|
void RageDisplay::SaveScreenshot( CString sPath )
|
|
|
|
|
{
|
|
|
|
|
ASSERT( sPath.Right(3).CompareNoCase("bmp") == 0 ); // we can only save bitmaps
|
|
|
|
|
|
|
|
|
|
SDL_Surface *image = SDL_CreateRGBSurface(
|
2003-04-07 00:54:32 +00:00
|
|
|
SDL_SWSURFACE, wind->GetWidth(), wind->GetHeight(),
|
2003-01-31 22:34:04 +00:00
|
|
|
24, 0x0000FF, 0x00FF00, 0xFF0000, 0x000000);
|
|
|
|
|
SDL_Surface *temp = SDL_CreateRGBSurface(
|
2003-04-07 00:54:32 +00:00
|
|
|
SDL_SWSURFACE, wind->GetWidth(), wind->GetHeight(),
|
2003-01-31 22:34:04 +00:00
|
|
|
24, 0x0000FF, 0x00FF00, 0xFF0000, 0x000000);
|
|
|
|
|
|
2003-04-07 00:54:32 +00:00
|
|
|
glReadPixels(0, 0, wind->GetWidth(), wind->GetHeight(), GL_RGB,
|
2003-01-31 22:34:04 +00:00
|
|
|
GL_UNSIGNED_BYTE, image->pixels);
|
|
|
|
|
|
|
|
|
|
// flip vertically
|
2003-04-07 00:54:32 +00:00
|
|
|
for( int y=0; y<wind->GetHeight(); y++ )
|
2003-01-31 22:34:04 +00:00
|
|
|
memcpy(
|
2003-04-07 00:54:32 +00:00
|
|
|
(char *)temp->pixels + 3 * wind->GetWidth() * y,
|
|
|
|
|
(char *)image->pixels + 3 * wind->GetWidth() * (wind->GetHeight()-1-y),
|
|
|
|
|
3*wind->GetWidth() );
|
2003-01-31 22:34:04 +00:00
|
|
|
|
|
|
|
|
SDL_SaveBMP( temp, sPath );
|
2003-02-01 01:11:00 +00:00
|
|
|
|
|
|
|
|
SDL_FreeSurface( image );
|
2003-01-31 22:34:04 +00:00
|
|
|
SDL_FreeSurface( temp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
bool RageDisplay::IsWindowed() const
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2003-04-07 00:54:32 +00:00
|
|
|
return wind->IsWindowed();
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
2003-03-15 00:19:48 +00:00
|
|
|
|
2003-02-20 21:22:18 +00:00
|
|
|
void RageDisplay::DrawQuad( const RageVertex v[4] ) // upper-left, upper-right, lower-right, lower-left
|
2002-05-20 08:59:37 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
DrawQuads( v, 4 );
|
2002-05-20 08:59:37 +00:00
|
|
|
}
|
2003-01-08 23:16:28 +00:00
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::DrawQuads( const RageVertex v[], int iNumVerts )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
ASSERT( (iNumVerts%4) == 0 );
|
2002-11-13 05:17:15 +00:00
|
|
|
|
2003-04-18 09:13:29 +00:00
|
|
|
if(iNumVerts == 0)
|
|
|
|
|
return;
|
|
|
|
|
#if 1
|
|
|
|
|
static float *Vertex, *Color, *Texture;
|
|
|
|
|
static int Size = 0;
|
|
|
|
|
if(iNumVerts > Size)
|
|
|
|
|
{
|
|
|
|
|
Size = iNumVerts;
|
|
|
|
|
delete [] Vertex;
|
|
|
|
|
delete [] Color;
|
|
|
|
|
delete [] Texture;
|
|
|
|
|
Vertex = new float[Size*3];
|
|
|
|
|
Color = new float[Size*4];
|
|
|
|
|
Texture = new float[Size*2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < unsigned(iNumVerts); ++i)
|
|
|
|
|
{
|
|
|
|
|
Vertex[i*3+0] = v[i].p[0];
|
|
|
|
|
Vertex[i*3+1] = v[i].p[1];
|
|
|
|
|
Vertex[i*3+2] = v[i].p[2];
|
|
|
|
|
Color[i*4+0] = v[i].c[0];
|
|
|
|
|
Color[i*4+1] = v[i].c[1];
|
|
|
|
|
Color[i*4+2] = v[i].c[2];
|
|
|
|
|
Color[i*4+3] = v[i].c[3];
|
|
|
|
|
Texture[i*2+0] = v[i].t[0];
|
|
|
|
|
Texture[i*2+1] = v[i].t[1];
|
|
|
|
|
}
|
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, Vertex);
|
|
|
|
|
|
|
|
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
|
|
|
glColorPointer(4, GL_FLOAT, 0, Color);
|
|
|
|
|
|
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, Texture);
|
|
|
|
|
|
|
|
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
|
|
|
#else
|
2003-01-08 23:16:28 +00:00
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
2003-04-18 09:13:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
2003-01-08 23:16:28 +00:00
|
|
|
glDrawArrays( GL_QUADS, 0, iNumVerts );
|
2002-11-13 05:17:15 +00:00
|
|
|
|
2003-01-08 23:16:28 +00:00
|
|
|
g_iVertsRenderedSinceLastCheck += iNumVerts;
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::DrawFan( const RageVertex v[], int iNumVerts )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
ASSERT( iNumVerts >= 3 );
|
2003-01-08 23:16:28 +00:00
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
|
|
|
|
glDrawArrays( GL_TRIANGLE_FAN, 0, iNumVerts );
|
|
|
|
|
g_iVertsRenderedSinceLastCheck += iNumVerts;
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
2003-01-08 23:16:28 +00:00
|
|
|
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::DrawStrip( const RageVertex v[], int iNumVerts )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
ASSERT( iNumVerts >= 3 );
|
2003-01-08 23:16:28 +00:00
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
|
|
|
|
glDrawArrays( GL_TRIANGLE_STRIP, 0, iNumVerts );
|
|
|
|
|
g_iVertsRenderedSinceLastCheck += iNumVerts;
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2002-11-14 08:38:41 +00:00
|
|
|
|
2003-04-25 21:05:40 +00:00
|
|
|
void RageDisplay::DrawTriangles( const RageVertex v[], int iNumVerts )
|
|
|
|
|
{
|
|
|
|
|
ASSERT( iNumVerts >= 3 );
|
|
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
|
|
|
|
glDrawArrays( GL_TRIANGLES, 0, iNumVerts );
|
|
|
|
|
g_iVertsRenderedSinceLastCheck += iNumVerts;
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-19 09:46:22 +00:00
|
|
|
/* Draw a line as a quad. GL_LINES with antialiasing off can draw line
|
2003-01-25 03:57:14 +00:00
|
|
|
* ends at odd angles--they're forced to axis-alignment regardless of the
|
|
|
|
|
* angle of the line. */
|
|
|
|
|
void RageDisplay::DrawPolyLine(const RageVertex &p1, const RageVertex &p2, float LineWidth )
|
|
|
|
|
{
|
|
|
|
|
/* soh cah toa strikes strikes again! */
|
|
|
|
|
float opp = p2.p.x - p1.p.x;
|
|
|
|
|
float adj = p2.p.y - p1.p.y;
|
|
|
|
|
float hyp = powf(opp*opp + adj*adj, 0.5f);
|
|
|
|
|
|
|
|
|
|
float lsin = opp/hyp;
|
|
|
|
|
float lcos = adj/hyp;
|
|
|
|
|
|
|
|
|
|
RageVertex p[4];
|
|
|
|
|
p[0] = p[1] = p1;
|
|
|
|
|
p[2] = p[3] = p2;
|
|
|
|
|
|
|
|
|
|
float ydist = lsin * LineWidth/2;
|
|
|
|
|
float xdist = lcos * LineWidth/2;
|
|
|
|
|
|
|
|
|
|
p[0].p.x += xdist;
|
|
|
|
|
p[0].p.y -= ydist;
|
|
|
|
|
p[1].p.x -= xdist;
|
|
|
|
|
p[1].p.y += ydist;
|
|
|
|
|
p[2].p.x -= xdist;
|
|
|
|
|
p[2].p.y += ydist;
|
|
|
|
|
p[3].p.x += xdist;
|
|
|
|
|
p[3].p.y -= ydist;
|
|
|
|
|
|
|
|
|
|
DrawQuad(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw a line loop with rounded corners using polys. This is used on
|
|
|
|
|
* cards that have strange allergic reactions to antialiased points and
|
|
|
|
|
* lines. */
|
|
|
|
|
void RageDisplay::DrawLoop_Polys( const RageVertex v[], int iNumVerts, float LineWidth )
|
|
|
|
|
{
|
|
|
|
|
ASSERT( iNumVerts >= 3 );
|
2003-02-14 07:04:19 +00:00
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
for(i = 0; i < iNumVerts; ++i)
|
2003-01-25 03:57:14 +00:00
|
|
|
DrawPolyLine(v[i], v[(i+1)%iNumVerts], LineWidth);
|
|
|
|
|
|
|
|
|
|
/* Join the lines with circles so we get rounded corners. */
|
|
|
|
|
GLUquadricObj *q = gluNewQuadric();
|
2003-01-25 23:48:33 +00:00
|
|
|
for(i = 0; i < iNumVerts; ++i)
|
2003-01-25 03:57:14 +00:00
|
|
|
{
|
|
|
|
|
glPushMatrix();
|
|
|
|
|
glColor4fv(v[i].c);
|
|
|
|
|
glTexCoord3fv(v[i].t);
|
|
|
|
|
glTranslatef(v[i].p.x, v[i].p.y, v[i].p.z);
|
|
|
|
|
|
|
|
|
|
gluDisk(q, 0, LineWidth/2, 32, 32);
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
}
|
|
|
|
|
gluDeleteQuadric(q);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw a nice AA'd line loop. One problem with this is that point and line
|
|
|
|
|
* sizes don't always precisely match, which doesn't look quite right.
|
|
|
|
|
* It's worth it for the AA, though. */
|
|
|
|
|
void RageDisplay::DrawLoop_LinesAndPoints( const RageVertex v[], int iNumVerts, float LineWidth )
|
2002-11-14 08:38:41 +00:00
|
|
|
{
|
|
|
|
|
ASSERT( iNumVerts >= 3 );
|
|
|
|
|
|
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
2002-11-18 20:55:23 +00:00
|
|
|
|
2002-11-14 09:03:19 +00:00
|
|
|
/* Our line width is wrt the regular internal SCREEN_WIDTHxSCREEN_HEIGHT screen,
|
|
|
|
|
* but these width functions actually want raster sizes (that is, actual pixels).
|
|
|
|
|
* Scale the line width and point size by the average ratio of the scale. */
|
2003-04-07 00:54:32 +00:00
|
|
|
float WidthVal = float(wind->GetWidth()) / SCREEN_WIDTH;
|
|
|
|
|
float HeightVal = float(wind->GetHeight()) / SCREEN_HEIGHT;
|
2002-12-07 06:20:47 +00:00
|
|
|
LineWidth *= (WidthVal + HeightVal) / 2;
|
|
|
|
|
|
|
|
|
|
/* Clamp the width to the hardware max for both lines and points (whichever
|
|
|
|
|
* is more restrictive). */
|
2002-12-30 00:48:31 +00:00
|
|
|
LineWidth = clamp(LineWidth, m_oglspecs->line_range[0], m_oglspecs->line_range[1]);
|
|
|
|
|
LineWidth = clamp(LineWidth, m_oglspecs->point_range[0], m_oglspecs->point_range[1]);
|
2002-12-07 06:20:47 +00:00
|
|
|
|
|
|
|
|
/* Hmm. The granularity of lines and points might be different; for example,
|
|
|
|
|
* if lines are .5 and points are .25, we might want to snap the width to the
|
|
|
|
|
* nearest .5, so the hardware doesn't snap them to different sizes. Does it
|
|
|
|
|
* matter? */
|
|
|
|
|
glLineWidth(LineWidth);
|
2002-11-14 08:38:41 +00:00
|
|
|
|
|
|
|
|
/* Draw the line loop: */
|
2003-01-08 23:16:28 +00:00
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
|
|
|
|
glDrawArrays( GL_LINE_LOOP, 0, iNumVerts );
|
2002-11-14 08:38:41 +00:00
|
|
|
|
2002-11-18 20:55:23 +00:00
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
|
|
2002-11-14 09:03:19 +00:00
|
|
|
/* Round off the corners. This isn't perfect; the point is sometimes a little
|
|
|
|
|
* larger than the line, causing a small bump on the edge. Not sure how to fix
|
2002-12-07 06:20:47 +00:00
|
|
|
* that. */
|
|
|
|
|
glPointSize(LineWidth);
|
2002-11-18 20:55:23 +00:00
|
|
|
|
|
|
|
|
/* Hack: if the points will all be the same, we don't want to draw
|
|
|
|
|
* any points at all, since there's nothing to connect. That'll happen
|
|
|
|
|
* if both scale factors in the matrix are ~0. (Actually, I think
|
|
|
|
|
* it's true if two of the three scale factors are ~0, but we don't
|
2003-01-25 03:57:14 +00:00
|
|
|
* use this for anything 3d at the moment anyway ...) This is needed
|
|
|
|
|
* because points aren't scaled like regular polys--a zero-size point
|
|
|
|
|
* will still be drawn. */
|
2003-01-08 22:30:32 +00:00
|
|
|
RageMatrix mat;
|
|
|
|
|
glGetFloatv( GL_MODELVIEW_MATRIX, (float*)mat );
|
|
|
|
|
|
2002-11-18 20:55:23 +00:00
|
|
|
if(mat.m[0][0] < 1e-5 && mat.m[1][1] < 1e-5)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
glEnable(GL_POINT_SMOOTH);
|
|
|
|
|
|
2003-01-08 23:16:28 +00:00
|
|
|
glInterleavedArrays( RageVertexFormat, sizeof(RageVertex), v );
|
|
|
|
|
glDrawArrays( GL_POINTS, 0, iNumVerts );
|
2002-11-14 08:38:41 +00:00
|
|
|
|
|
|
|
|
glDisable(GL_POINT_SMOOTH);
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-25 03:57:14 +00:00
|
|
|
void RageDisplay::DrawLoop( const RageVertex v[], int iNumVerts, float LineWidth )
|
|
|
|
|
{
|
2003-02-20 21:22:18 +00:00
|
|
|
if( m_oglspecs->bAALinesCauseProblems )
|
2003-01-26 03:51:59 +00:00
|
|
|
DrawLoop_Polys(v, iNumVerts, LineWidth);
|
|
|
|
|
else
|
|
|
|
|
DrawLoop_LinesAndPoints(v, iNumVerts, LineWidth);
|
2003-01-25 03:57:14 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-18 16:19:26 +00:00
|
|
|
void RageDisplay::PushMatrix()
|
|
|
|
|
{
|
2003-01-08 22:30:32 +00:00
|
|
|
glPushMatrix();
|
|
|
|
|
ASSERT(++g_ModelMatrixCnt<20);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageDisplay::PopMatrix()
|
|
|
|
|
{
|
2003-01-08 22:30:32 +00:00
|
|
|
glPopMatrix();
|
|
|
|
|
ASSERT(g_ModelMatrixCnt-->0);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-25 08:17:27 +00:00
|
|
|
static RageMatrix rgluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
|
|
|
|
|
GLfloat centerx, GLfloat centery, GLfloat centerz,
|
|
|
|
|
GLfloat upx, GLfloat upy, GLfloat upz)
|
|
|
|
|
{
|
|
|
|
|
RageVector3 Z(eyex - centerx, eyey - centery, eyez - centerz);
|
|
|
|
|
RageVec3Normalize(&Z, &Z);
|
|
|
|
|
|
|
|
|
|
RageVector3 Y(upx, upy, upz);
|
|
|
|
|
|
|
|
|
|
RageVector3 X(
|
|
|
|
|
Y[1] * Z[2] - Y[2] * Z[1],
|
|
|
|
|
-Y[0] * Z[2] + Y[2] * Z[0],
|
|
|
|
|
Y[0] * Z[1] - Y[1] * Z[0]);
|
|
|
|
|
|
|
|
|
|
Y = RageVector3(
|
|
|
|
|
Z[1] * X[2] - Z[2] * X[1],
|
|
|
|
|
-Z[0] * X[2] + Z[2] * X[0],
|
|
|
|
|
Z[0] * X[1] - Z[1] * X[0] );
|
|
|
|
|
|
|
|
|
|
RageVec3Normalize(&X, &X);
|
|
|
|
|
RageVec3Normalize(&Y, &Y);
|
|
|
|
|
|
|
|
|
|
RageMatrix mat(
|
|
|
|
|
X[0], Y[0], Z[0], 0,
|
|
|
|
|
X[1], Y[1], Z[1], 0,
|
|
|
|
|
X[2], Y[2], Z[2], 0,
|
|
|
|
|
0, 0, 0, 1 );
|
|
|
|
|
|
|
|
|
|
RageMatrix mat2;
|
|
|
|
|
RageMatrixTranslation(&mat2, -eyex, -eyey, -eyez);
|
|
|
|
|
|
|
|
|
|
RageMatrix ret;
|
|
|
|
|
RageMatrixMultiply(&ret, &mat, &mat2);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-04-23 02:23:51 +00:00
|
|
|
void RageDisplay::LoadMenuPerspective(float fovDegrees)
|
|
|
|
|
{
|
|
|
|
|
/* fovDegrees == 0 looks the same as an ortho projection. However,
|
|
|
|
|
* we don't want to mess with the ModelView stack because
|
|
|
|
|
* EnterPerspectiveMode's preserve location feature expectes there
|
|
|
|
|
* not to be any camera transforms. So, do a true ortho projection
|
|
|
|
|
* if fovDegrees == 0. Perhaps it would be more convenient to keep
|
|
|
|
|
* separate model and view stacks like D3D?
|
|
|
|
|
*/
|
|
|
|
|
if( fovDegrees == 0 )
|
|
|
|
|
{
|
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
|
|
float left = 0, right = SCREEN_WIDTH, bottom = SCREEN_HEIGHT, top = 0;
|
|
|
|
|
if(strncmp((const char*)glGetString(GL_RENDERER),"GLDirect",strlen("GLDirect"))==0)
|
|
|
|
|
{
|
|
|
|
|
/* GLDirect incorrectly uses Direct3D's device coordinate system
|
|
|
|
|
* instead of OpenGL's, so we need to compensate. */
|
|
|
|
|
left += 0.5f;
|
|
|
|
|
right += 0.5f;
|
|
|
|
|
bottom += 0.5f;
|
|
|
|
|
top += 0.5f;
|
|
|
|
|
}
|
|
|
|
|
glOrtho(left, right, bottom, top, SCREEN_NEAR, SCREEN_FAR );
|
|
|
|
|
|
|
|
|
|
glMatrixMode( GL_MODELVIEW );
|
|
|
|
|
glLoadIdentity();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CLAMP( fovDegrees, 0.1f, 179.9f );
|
|
|
|
|
float fovRadians = fovDegrees / 180.f * PI;
|
|
|
|
|
// tan(theta) = 320/d
|
|
|
|
|
float theta = fovRadians/2;
|
|
|
|
|
float fDistCameraFromImage = SCREEN_WIDTH/2 / tanf( theta );
|
|
|
|
|
|
|
|
|
|
/* It's the caller's responsibility to push first. */
|
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
|
|
glFrustum(
|
|
|
|
|
-(SCREEN_WIDTH/2)/fDistCameraFromImage,
|
|
|
|
|
+(SCREEN_WIDTH/2)/fDistCameraFromImage,
|
|
|
|
|
+(SCREEN_HEIGHT/2)/fDistCameraFromImage,
|
|
|
|
|
-(SCREEN_HEIGHT/2)/fDistCameraFromImage,
|
|
|
|
|
1,
|
|
|
|
|
fDistCameraFromImage+1000
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
glMatrixMode( GL_MODELVIEW );
|
|
|
|
|
RageVector3 Up( 0.0f, 1.0f, 0.0f );
|
|
|
|
|
RageVector3 Eye( CENTER_X, CENTER_Y, fDistCameraFromImage );
|
|
|
|
|
RageVector3 At( CENTER_X, CENTER_Y, 0 );
|
|
|
|
|
glLoadIdentity();
|
2003-04-25 08:17:27 +00:00
|
|
|
PostMultMatrix(rgluLookAt(Eye.x, Eye.y, Eye.z, At.x, At.y, At.z, Up.x, Up.y, Up.z));
|
2003-04-23 02:23:51 +00:00
|
|
|
|
|
|
|
|
/* GLDirect incorrectly uses Direct3D's device coordinate system
|
|
|
|
|
* instead of OpenGL's, so we need to compensate. */
|
|
|
|
|
if(strncmp((const char*)glGetString(GL_RENDERER),"GLDirect",strlen("GLDirect"))==0)
|
|
|
|
|
glTranslatef( 0.5f, 0.5f, 0 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-25 06:58:19 +00:00
|
|
|
/* Getting rid of GLU calls. We don't use them much, and it's just another
|
|
|
|
|
* library. */
|
|
|
|
|
static void rgluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
|
|
|
|
|
{
|
|
|
|
|
GLfloat ymax = zNear * tanf(fovy * PI / 360.0f);
|
|
|
|
|
GLfloat ymin = -ymax;
|
|
|
|
|
GLfloat xmin = ymin * aspect;
|
|
|
|
|
GLfloat xmax = ymax * aspect;
|
|
|
|
|
|
|
|
|
|
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-15 08:01:34 +00:00
|
|
|
/* Switch from orthogonal to perspective view.
|
|
|
|
|
*
|
|
|
|
|
* Tricky: we want to maintain all of the zooms, rotations and translations
|
|
|
|
|
* that have been applied already. They're in our internal screen space (that
|
|
|
|
|
* is, 640x480 ortho). We can't simply leave them where they are, since they'll
|
|
|
|
|
* be applied before the perspective transform, which means they'll be in the
|
|
|
|
|
* wrong coordinate space.
|
|
|
|
|
*
|
|
|
|
|
* Handle translations (the right column of the transform matrix) to the viewport.
|
|
|
|
|
* Move rotations and scaling (0,0 through 1,1) to after the perspective transform.
|
|
|
|
|
* Actually, those might be able to stay where they are, I'm not sure; it's translations
|
|
|
|
|
* that are annoying. So, XXX: see if rots and scales can be left on the modelview
|
|
|
|
|
* matrix instead of messing with the projection matrix.
|
|
|
|
|
*
|
|
|
|
|
* When finished, the current position will be the "viewpoint" (at 0,0). negative
|
|
|
|
|
* Z goes into the screen, positive X and Y is right and down.
|
|
|
|
|
*/
|
2003-04-16 18:57:20 +00:00
|
|
|
void RageDisplay::EnterPerspective(float fov, bool preserve_loc, float near_clip, float far_clip)
|
2002-11-15 08:01:34 +00:00
|
|
|
{
|
|
|
|
|
g_PerspectiveMode++;
|
|
|
|
|
if(g_PerspectiveMode > 1) {
|
|
|
|
|
/* havn't yet worked out the details of this */
|
|
|
|
|
LOG->Trace("EnterPerspective called when already in perspective mode");
|
|
|
|
|
g_PerspectiveMode++;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save the old matrices. */
|
|
|
|
|
DISPLAY->PushMatrix();
|
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
2002-11-15 08:22:53 +00:00
|
|
|
glPushMatrix();
|
2002-11-15 08:01:34 +00:00
|
|
|
glLoadIdentity();
|
|
|
|
|
float aspect = SCREEN_WIDTH/(float)SCREEN_HEIGHT;
|
2003-04-25 06:58:19 +00:00
|
|
|
rgluPerspective(fov, aspect, near_clip, far_clip);
|
2002-11-15 08:01:34 +00:00
|
|
|
|
2003-04-23 02:23:51 +00:00
|
|
|
|
2002-11-15 08:01:34 +00:00
|
|
|
/* Flip the Y coordinate, so positive numbers go down. */
|
|
|
|
|
glScalef(1, -1, 1);
|
|
|
|
|
|
2003-01-09 04:35:20 +00:00
|
|
|
if(!preserve_loc)
|
|
|
|
|
{
|
|
|
|
|
glMatrixMode( GL_MODELVIEW );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RageMatrix matTop;
|
|
|
|
|
glGetFloatv( GL_MODELVIEW_MATRIX, (float*)matTop );
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
/* Pull out the 2d translation. */
|
|
|
|
|
float x = matTop.m[3][0], y = matTop.m[3][1];
|
|
|
|
|
|
|
|
|
|
/* These values are where the viewpoint should be. By default, it's in the
|
|
|
|
|
* center of the screen, and these values are from the top-left, so subtract
|
|
|
|
|
* the difference. */
|
|
|
|
|
x -= SCREEN_WIDTH/2;
|
|
|
|
|
y -= SCREEN_HEIGHT/2;
|
|
|
|
|
DISPLAY->SetViewport(int(x), int(y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pull out the 2d rotations and scales. */
|
|
|
|
|
{
|
|
|
|
|
RageMatrix mat;
|
|
|
|
|
RageMatrixIdentity(&mat);
|
|
|
|
|
mat.m[0][0] = matTop.m[0][0];
|
|
|
|
|
mat.m[0][1] = matTop.m[0][1];
|
|
|
|
|
mat.m[1][0] = matTop.m[1][0];
|
|
|
|
|
mat.m[1][1] = matTop.m[1][1];
|
2003-04-10 17:58:27 +00:00
|
|
|
this->MultMatrix(mat);
|
2002-11-15 08:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-09 04:35:20 +00:00
|
|
|
/* We can't cope with perspective matrices or things that touch Z. (We shouldn't
|
|
|
|
|
* have touched those while in 2d, anyway.) */
|
|
|
|
|
ASSERT(matTop.m[0][2] == 0.f && matTop.m[0][3] == 0.f && matTop.m[1][2] == 0.f &&
|
|
|
|
|
matTop.m[1][3] == 0.f && matTop.m[2][0] == 0.f && matTop.m[2][1] == 0.f &&
|
|
|
|
|
matTop.m[2][2] == 1.f && matTop.m[3][2] == 0.f && matTop.m[3][3] == 1.f);
|
|
|
|
|
|
|
|
|
|
/* Reset the matrix back to identity. */
|
2002-11-15 08:01:34 +00:00
|
|
|
glMatrixMode( GL_MODELVIEW );
|
2003-01-09 04:35:20 +00:00
|
|
|
glLoadIdentity();
|
2002-11-15 08:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageDisplay::ExitPerspective()
|
|
|
|
|
{
|
|
|
|
|
g_PerspectiveMode--;
|
|
|
|
|
if(g_PerspectiveMode) return;
|
|
|
|
|
|
|
|
|
|
/* Restore the old matrices. */
|
2002-11-15 08:22:53 +00:00
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
glMatrixMode( GL_MODELVIEW );
|
2002-11-15 08:01:34 +00:00
|
|
|
DISPLAY->PopMatrix();
|
|
|
|
|
|
|
|
|
|
/* Restore the viewport. */
|
|
|
|
|
DISPLAY->SetViewport(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-10 17:58:27 +00:00
|
|
|
/* gluLookAt. The result is pre-multiplied to the matrix (M = L * M) instead of
|
|
|
|
|
* post-multiplied. */
|
2002-11-15 08:01:34 +00:00
|
|
|
void RageDisplay::LookAt(const RageVector3 &Eye, const RageVector3 &At, const RageVector3 &Up)
|
|
|
|
|
{
|
2003-04-25 08:17:27 +00:00
|
|
|
PreMultMatrix(rgluLookAt(Eye.x, Eye.y, Eye.z, At.x, At.y, At.z, Up.x, Up.y, Up.z));
|
2002-11-15 08:01:34 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::Translate( float x, float y, float z )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2003-01-08 22:30:32 +00:00
|
|
|
glTranslatef(x, y, z);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-08 22:30:32 +00:00
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::TranslateLocal( float x, float y, float z )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2002-10-28 05:30:45 +00:00
|
|
|
RageMatrix matTemp;
|
|
|
|
|
RageMatrixTranslation( &matTemp, x, y, z );
|
2003-01-08 04:16:39 +00:00
|
|
|
|
2003-04-10 17:58:27 +00:00
|
|
|
PreMultMatrix(matTemp);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::Scale( float x, float y, float z )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2003-01-08 22:30:32 +00:00
|
|
|
glScalef(x, y, z);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::RotateX( float r )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2003-04-02 06:02:55 +00:00
|
|
|
glRotatef(r, 1, 0, 0);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::RotateY( float r )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2003-04-02 06:02:55 +00:00
|
|
|
glRotatef(r, 0, 1, 0);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-29 21:30:16 +00:00
|
|
|
void RageDisplay::RotateZ( float r )
|
2002-08-18 16:19:26 +00:00
|
|
|
{
|
2003-02-20 10:41:43 +00:00
|
|
|
// HACK: Rotation about (0,0,1) seems to be broken in many Voodoo3 drivers,
|
|
|
|
|
// but only while using orthographic projections. Strange...
|
|
|
|
|
// Adding a tiny X component fixes the problem. -Chris
|
2003-04-02 06:02:55 +00:00
|
|
|
glRotatef(r, 0.00001f, 0, 1);
|
2003-01-08 22:30:32 +00:00
|
|
|
}
|
2003-01-08 04:16:39 +00:00
|
|
|
|
2003-04-10 17:58:27 +00:00
|
|
|
void RageDisplay::PostMultMatrix( const RageMatrix &f )
|
|
|
|
|
{
|
|
|
|
|
glMultMatrixf((const float *) f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageDisplay::PreMultMatrix( const RageMatrix &f )
|
2003-01-08 22:30:32 +00:00
|
|
|
{
|
|
|
|
|
RageMatrix m;
|
|
|
|
|
glGetFloatv( GL_MODELVIEW_MATRIX, (float*)m );
|
|
|
|
|
RageMatrixMultiply( &m, &f, &m );
|
|
|
|
|
glLoadMatrixf((const float*) m);
|
2002-08-18 16:19:26 +00:00
|
|
|
}
|
|
|
|
|
|
2002-08-13 23:26:46 +00:00
|
|
|
void RageDisplay::SetTexture( RageTexture* pTexture )
|
|
|
|
|
{
|
2003-01-08 23:16:28 +00:00
|
|
|
glBindTexture( GL_TEXTURE_2D, pTexture? pTexture->GetGLTextureID() : 0 );
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2002-11-11 04:53:31 +00:00
|
|
|
void RageDisplay::SetTextureModeModulate()
|
2002-08-13 23:26:46 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2002-08-18 16:19:26 +00:00
|
|
|
|
2002-11-12 00:51:27 +00:00
|
|
|
/* Set the blend mode for both texture and alpha. This is all that's
|
|
|
|
|
* available pre-OpenGL 1.4. */
|
|
|
|
|
void RageDisplay::SetBlendMode(int src, int dst)
|
2002-08-13 23:26:46 +00:00
|
|
|
{
|
2003-02-14 23:13:22 +00:00
|
|
|
glBlendFunc( GLenum(src), GLenum(dst) );
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2002-11-12 00:51:27 +00:00
|
|
|
|
|
|
|
|
void RageDisplay::SetTextureModeGlow()
|
2002-08-13 23:26:46 +00:00
|
|
|
{
|
2002-12-30 00:48:31 +00:00
|
|
|
if(!m_oglspecs->EXT_texture_env_combine) {
|
2002-11-12 00:51:27 +00:00
|
|
|
SetBlendMode( GL_SRC_ALPHA, GL_ONE );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-08-18 16:19:26 +00:00
|
|
|
|
2002-11-12 00:51:27 +00:00
|
|
|
/* Source color is the diffuse color only: */
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
2003-02-14 23:13:22 +00:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_COMBINE_RGB_EXT), GL_REPLACE);
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_SOURCE0_RGB_EXT), GL_PRIMARY_COLOR_EXT);
|
2002-11-12 00:51:27 +00:00
|
|
|
|
|
|
|
|
/* Source alpha is texture alpha * diffuse alpha: */
|
2003-02-14 23:13:22 +00:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_COMBINE_ALPHA_EXT), GL_MODULATE);
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_OPERAND0_ALPHA_EXT), GL_SRC_ALPHA);
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_SOURCE0_ALPHA_EXT), GL_PRIMARY_COLOR_EXT);
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_OPERAND1_ALPHA_EXT), GL_SRC_ALPHA);
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GLenum(GL_SOURCE1_ALPHA_EXT), GL_TEXTURE);
|
2002-11-12 00:51:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageDisplay::SetBlendModeNormal()
|
|
|
|
|
{
|
|
|
|
|
SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
|
|
|
|
void RageDisplay::SetBlendModeAdd()
|
|
|
|
|
{
|
2002-11-12 00:51:27 +00:00
|
|
|
SetBlendMode( GL_ONE, GL_ONE );
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
2002-11-12 01:25:03 +00:00
|
|
|
|
|
|
|
|
bool RageDisplay::ZBufferEnabled() const
|
2002-08-13 23:26:46 +00:00
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
bool a;
|
|
|
|
|
glGetBooleanv( GL_DEPTH_TEST, (unsigned char*)&a );
|
2002-11-12 01:25:03 +00:00
|
|
|
return a;
|
|
|
|
|
}
|
2002-08-18 16:19:26 +00:00
|
|
|
|
2002-11-12 01:25:03 +00:00
|
|
|
void RageDisplay::EnableZBuffer()
|
|
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
glEnable( GL_DEPTH_TEST );
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
|
|
|
|
void RageDisplay::DisableZBuffer()
|
|
|
|
|
{
|
2002-11-11 04:53:31 +00:00
|
|
|
glDisable( GL_DEPTH_TEST );
|
2002-10-18 19:01:32 +00:00
|
|
|
}
|
2003-04-10 18:25:17 +00:00
|
|
|
void RageDisplay::EnableTextureWrapping(bool yes)
|
2002-10-18 19:01:32 +00:00
|
|
|
{
|
2003-04-10 18:25:17 +00:00
|
|
|
GLenum mode = yes? GL_REPEAT:GL_CLAMP;
|
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode );
|
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode );
|
2002-10-18 19:01:32 +00:00
|
|
|
}
|