Line endings...be normalized!
This commit is contained in:
@@ -1,432 +1,432 @@
|
||||
#include "global.h"
|
||||
#include "LowLevelWindow_Win32.h"
|
||||
#include "archutils/Win32/DirectXHelpers.h"
|
||||
#include "archutils/Win32/ErrorStrings.h"
|
||||
#include "archutils/Win32/GraphicsWindow.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "RageDisplay_OGL_Helpers.h"
|
||||
#include "RageDisplay_OGL.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
static PIXELFORMATDESCRIPTOR g_CurrentPixelFormat;
|
||||
static HGLRC g_HGLRC = NULL;
|
||||
static HGLRC g_HGLRC_Background = NULL;
|
||||
|
||||
static void DestroyGraphicsWindowAndOpenGLContext()
|
||||
{
|
||||
if( g_HGLRC != NULL )
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
wglDeleteContext( g_HGLRC );
|
||||
g_HGLRC = NULL;
|
||||
}
|
||||
|
||||
if( g_HGLRC_Background != NULL )
|
||||
{
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
ZERO( g_CurrentPixelFormat );
|
||||
|
||||
GraphicsWindow::DestroyGraphicsWindow();
|
||||
}
|
||||
|
||||
void *LowLevelWindow_Win32::GetProcAddress( RString s )
|
||||
{
|
||||
void *pRet = wglGetProcAddress( s );
|
||||
if( pRet != NULL )
|
||||
return pRet;
|
||||
|
||||
return ::GetProcAddress( GetModuleHandle(NULL), s );
|
||||
}
|
||||
|
||||
LowLevelWindow_Win32::LowLevelWindow_Win32()
|
||||
{
|
||||
ASSERT( g_HGLRC == NULL );
|
||||
ASSERT( g_HGLRC_Background == NULL );
|
||||
|
||||
GraphicsWindow::Initialize( false );
|
||||
}
|
||||
|
||||
LowLevelWindow_Win32::~LowLevelWindow_Win32()
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
GraphicsWindow::Shutdown();
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
{
|
||||
GraphicsWindow::GetDisplayResolutions( out );
|
||||
}
|
||||
|
||||
int ChooseWindowPixelFormat( const VideoModeParams &p, PIXELFORMATDESCRIPTOR *PixelFormat )
|
||||
{
|
||||
ASSERT( GraphicsWindow::GetHwnd() != NULL );
|
||||
ASSERT( GraphicsWindow::GetHDC() != NULL );
|
||||
|
||||
ZERO( *PixelFormat );
|
||||
PixelFormat->nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
PixelFormat->nVersion = 1;
|
||||
PixelFormat->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL;
|
||||
PixelFormat->iPixelType = PFD_TYPE_RGBA;
|
||||
PixelFormat->cColorBits = p.bpp == 16? 16:24;
|
||||
PixelFormat->cDepthBits = 16;
|
||||
|
||||
return ChoosePixelFormat( GraphicsWindow::GetHDC(), PixelFormat );
|
||||
}
|
||||
|
||||
void DumpPixelFormat( const PIXELFORMATDESCRIPTOR &pfd )
|
||||
{
|
||||
RString str = ssprintf( "Mode: " );
|
||||
bool bInvalidFormat = false;
|
||||
|
||||
if( pfd.dwFlags & PFD_GENERIC_FORMAT )
|
||||
{
|
||||
if( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) str += "MCD ";
|
||||
else { str += "software "; bInvalidFormat = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
str += "ICD ";
|
||||
}
|
||||
|
||||
if( pfd.iPixelType != PFD_TYPE_RGBA ) { str += "indexed "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ) { str += "!OPENGL "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ) { str += "!window "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_DOUBLEBUFFER) ) { str += "!dbuff "; bInvalidFormat = true; }
|
||||
|
||||
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( bInvalidFormat )
|
||||
LOG->Warn( "Invalid format: %s", str.c_str() );
|
||||
else
|
||||
LOG->Info( "%s", str.c_str() );
|
||||
}
|
||||
|
||||
/* This function does not reset the video mode if it fails, because we might be trying
|
||||
* yet another video mode, so we'd just thrash the display. On fatal error,
|
||||
* LowLevelWindow_Win32::~LowLevelWindow_Win32 will call GraphicsWindow::Shutdown(). */
|
||||
RString LowLevelWindow_Win32::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut )
|
||||
{
|
||||
//LOG->Warn( "LowLevelWindow_Win32::TryVideoMode" );
|
||||
|
||||
ASSERT_M( p.bpp == 16 || p.bpp == 32, ssprintf("%i", p.bpp) );
|
||||
|
||||
bNewDeviceOut = false;
|
||||
|
||||
/* We're only allowed to change the pixel format of a window exactly once. */
|
||||
bool bCanSetPixelFormat = true;
|
||||
|
||||
/* Do we have an old window? */
|
||||
if( GraphicsWindow::GetHwnd() == NULL )
|
||||
{
|
||||
/* No. Always create and show the window before changing the video mode.
|
||||
* Otherwise, some other window may have focus, and changing the video mode will
|
||||
* cause that window to be resized. */
|
||||
bNewDeviceOut = true;
|
||||
GraphicsWindow::CreateGraphicsWindow( p );
|
||||
} else {
|
||||
/* We already have a window. Assume that its pixel format has already
|
||||
* been set. */
|
||||
bCanSetPixelFormat = false;
|
||||
}
|
||||
|
||||
ASSERT( GraphicsWindow::GetHwnd() );
|
||||
|
||||
/* Set the display mode: switch to a fullscreen mode or revert to windowed mode. */
|
||||
LOG->Trace("SetScreenMode ...");
|
||||
RString sErr = GraphicsWindow::SetScreenMode( p );
|
||||
if( !sErr.empty() )
|
||||
return sErr;
|
||||
|
||||
PIXELFORMATDESCRIPTOR PixelFormat;
|
||||
int iPixelFormat = ChooseWindowPixelFormat( p, &PixelFormat );
|
||||
if( iPixelFormat == 0 )
|
||||
{
|
||||
/* Destroy the window. */
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return "Pixel format not found";
|
||||
}
|
||||
|
||||
bool bNeedToSetPixelFormat = false;
|
||||
{
|
||||
/* We'll need to recreate it if the pixel format is going to change. We
|
||||
* aren't allowed to change the pixel format twice. */
|
||||
PIXELFORMATDESCRIPTOR DestPixelFormat;
|
||||
ZERO( DestPixelFormat );
|
||||
DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &DestPixelFormat );
|
||||
if( memcmp( &DestPixelFormat, &g_CurrentPixelFormat, sizeof(PIXELFORMATDESCRIPTOR) ) )
|
||||
{
|
||||
LOG->Trace("Reset: pixel format changing" );
|
||||
bNeedToSetPixelFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( bNeedToSetPixelFormat && !bCanSetPixelFormat )
|
||||
{
|
||||
/*
|
||||
* The screen mode has changed, so we need to set the pixel format. If we're
|
||||
* not allowed to do so, destroy the window and make a new one.
|
||||
*
|
||||
* For some reason, if we destroy the old window before creating the new one,
|
||||
* the "maximized apps go under the taskbar" glitch will happen when we quit.
|
||||
* We have to create the new window first.
|
||||
*/
|
||||
LOG->Trace( "Mode requires new pixel format, and we've already set one; resetting OpenGL context" );
|
||||
if( g_HGLRC != NULL )
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
wglDeleteContext( g_HGLRC );
|
||||
g_HGLRC = NULL;
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
bNewDeviceOut = true;
|
||||
}
|
||||
|
||||
/* If we deleted the OpenGL context above, also recreate the window. Otherwise, just
|
||||
* reconfigure it. */
|
||||
GraphicsWindow::CreateGraphicsWindow( p, bNewDeviceOut );
|
||||
|
||||
if( bNeedToSetPixelFormat )
|
||||
{
|
||||
/* Set the pixel format. */
|
||||
if( !SetPixelFormat(GraphicsWindow::GetHDC(), iPixelFormat, &PixelFormat) )
|
||||
{
|
||||
/* Destroy the window. */
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
|
||||
return werr_ssprintf( GetLastError(), "Pixel format failed" );
|
||||
}
|
||||
|
||||
DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(g_CurrentPixelFormat), &g_CurrentPixelFormat );
|
||||
|
||||
DumpPixelFormat( g_CurrentPixelFormat );
|
||||
}
|
||||
|
||||
if( g_HGLRC == NULL )
|
||||
{
|
||||
g_HGLRC = wglCreateContext( GraphicsWindow::GetHDC() );
|
||||
if ( g_HGLRC == NULL )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
|
||||
g_HGLRC_Background = wglCreateContext( GraphicsWindow::GetHDC() );
|
||||
if( g_HGLRC_Background == NULL )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
|
||||
if( !wglShareLists(g_HGLRC, g_HGLRC_Background) )
|
||||
{
|
||||
LOG->Warn( werr_ssprintf(GetLastError(), "wglShareLists failed") );
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC ) )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
}
|
||||
return RString(); // we set the video mode successfully
|
||||
}
|
||||
|
||||
bool LowLevelWindow_Win32::SupportsThreadedRendering()
|
||||
{
|
||||
return g_HGLRC_Background != NULL;
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::BeginConcurrentRendering()
|
||||
{
|
||||
if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC_Background ) )
|
||||
{
|
||||
LOG->Warn( hr_ssprintf(GetLastError(), "wglMakeCurrent") );
|
||||
FAIL_M( hr_ssprintf(GetLastError(), "wglMakeCurrent") );
|
||||
}
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::EndConcurrentRendering()
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
}
|
||||
|
||||
static LocalizedString OPENGL_NOT_AVAILABLE( "LowLevelWindow_Win32", "OpenGL hardware acceleration is not available." );
|
||||
bool LowLevelWindow_Win32::IsSoftwareRenderer( RString &sError )
|
||||
{
|
||||
RString sVendor = (const char*)glGetString(GL_VENDOR);
|
||||
RString sRenderer = (const char*)glGetString(GL_RENDERER);
|
||||
|
||||
LOG->Trace( "LowLevelWindow_Win32::IsSoftwareRenderer '%s', '%s'", sVendor.c_str(), sRenderer.c_str() );
|
||||
|
||||
if( sVendor == "Microsoft Corporation" && sRenderer == "GDI Generic" )
|
||||
{
|
||||
sError = OPENGL_NOT_AVAILABLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::SwapBuffers()
|
||||
{
|
||||
::SwapBuffers( GraphicsWindow::GetHDC() );
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::Update()
|
||||
{
|
||||
GraphicsWindow::Update();
|
||||
}
|
||||
|
||||
const VideoModeParams &LowLevelWindow_Win32::GetActualVideoModeParams() const
|
||||
{
|
||||
return GraphicsWindow::GetParams();
|
||||
}
|
||||
|
||||
class RenderTarget_Win32 : public RenderTarget
|
||||
{
|
||||
public:
|
||||
RenderTarget_Win32( LowLevelWindow_Win32 *pWind );
|
||||
virtual ~RenderTarget_Win32();
|
||||
|
||||
void Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut );
|
||||
unsigned int GetTexture() const { return m_texHandle; }
|
||||
void StartRenderingTo();
|
||||
void FinishRenderingTo();
|
||||
|
||||
virtual bool InvertY() const { return true; }
|
||||
|
||||
private:
|
||||
LowLevelWindow_Win32 *m_pWind;
|
||||
int m_width;
|
||||
int m_height;
|
||||
GLuint m_texHandle;
|
||||
HDC m_hOldDeviceContext;
|
||||
HGLRC m_hOldRenderContext;
|
||||
};
|
||||
|
||||
RenderTarget_Win32::RenderTarget_Win32(LowLevelWindow_Win32 *pWind)
|
||||
{
|
||||
m_pWind = pWind;
|
||||
m_texHandle = 0;
|
||||
m_hOldDeviceContext = NULL;
|
||||
m_hOldRenderContext = NULL;
|
||||
}
|
||||
|
||||
RenderTarget_Win32::~RenderTarget_Win32()
|
||||
{
|
||||
glDeleteTextures( 1, &m_texHandle ); // deleting a 0 texture is safe and ignored
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::Create(const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut)
|
||||
{
|
||||
m_Param = param;
|
||||
m_width = param.iWidth;
|
||||
m_height = param.iHeight;
|
||||
|
||||
FlushGLErrors();
|
||||
|
||||
glGenTextures( 1, &m_texHandle );
|
||||
ASSERT(m_texHandle > 0);
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
|
||||
int iTextureWidth = power_of_two( param.iWidth );
|
||||
int iTextureHeight = power_of_two( param.iHeight );
|
||||
iTextureWidthOut = iTextureWidth;
|
||||
iTextureHeightOut = iTextureHeight;
|
||||
|
||||
GLenum internalformat;
|
||||
GLenum type = param.bWithAlpha? GL_RGBA:GL_RGB;
|
||||
if( param.bFloat && GLExt.m_bGL_ARB_texture_float )
|
||||
internalformat = param.bWithAlpha? GL_RGBA16F_ARB:GL_RGB16F_ARB;
|
||||
else
|
||||
internalformat = param.bWithAlpha? GL_RGBA8:GL_RGB8;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, iTextureWidth,
|
||||
iTextureHeight, 0, type, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
|
||||
|
||||
AssertNoGLError();
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::StartRenderingTo()
|
||||
{
|
||||
m_hOldDeviceContext = wglGetCurrentDC();
|
||||
m_hOldRenderContext = wglGetCurrentContext();
|
||||
|
||||
BOOL successful = wglMakeCurrent(GraphicsWindow::GetHDC(), g_HGLRC);
|
||||
ASSERT_M( successful == TRUE, "wglMakeCurrent failed in RenderTarget_Win32::StartRenderingTo()" );
|
||||
|
||||
FlushGLErrors();
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
AssertNoGLError();
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::FinishRenderingTo()
|
||||
{
|
||||
FlushGLErrors();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
AssertNoGLError();
|
||||
|
||||
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height );
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
|
||||
AssertNoGLError();
|
||||
|
||||
BOOL successful = wglMakeCurrent(m_hOldDeviceContext, m_hOldRenderContext);
|
||||
ASSERT_M( successful == TRUE, "wglMakeCurrent failed in RenderTarget_Win32::FinishRenderingTo()" );
|
||||
|
||||
m_hOldDeviceContext = 0;
|
||||
m_hOldRenderContext = 0;
|
||||
}
|
||||
|
||||
RenderTarget* LowLevelWindow_Win32::CreateRenderTarget()
|
||||
{
|
||||
return new RenderTarget_Win32( this );
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2004 Glenn Maynard
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||
* whom the Software is furnished to do so, provided that the above
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "global.h"
|
||||
#include "LowLevelWindow_Win32.h"
|
||||
#include "archutils/Win32/DirectXHelpers.h"
|
||||
#include "archutils/Win32/ErrorStrings.h"
|
||||
#include "archutils/Win32/GraphicsWindow.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "RageDisplay_OGL_Helpers.h"
|
||||
#include "RageDisplay_OGL.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
static PIXELFORMATDESCRIPTOR g_CurrentPixelFormat;
|
||||
static HGLRC g_HGLRC = NULL;
|
||||
static HGLRC g_HGLRC_Background = NULL;
|
||||
|
||||
static void DestroyGraphicsWindowAndOpenGLContext()
|
||||
{
|
||||
if( g_HGLRC != NULL )
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
wglDeleteContext( g_HGLRC );
|
||||
g_HGLRC = NULL;
|
||||
}
|
||||
|
||||
if( g_HGLRC_Background != NULL )
|
||||
{
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
ZERO( g_CurrentPixelFormat );
|
||||
|
||||
GraphicsWindow::DestroyGraphicsWindow();
|
||||
}
|
||||
|
||||
void *LowLevelWindow_Win32::GetProcAddress( RString s )
|
||||
{
|
||||
void *pRet = wglGetProcAddress( s );
|
||||
if( pRet != NULL )
|
||||
return pRet;
|
||||
|
||||
return ::GetProcAddress( GetModuleHandle(NULL), s );
|
||||
}
|
||||
|
||||
LowLevelWindow_Win32::LowLevelWindow_Win32()
|
||||
{
|
||||
ASSERT( g_HGLRC == NULL );
|
||||
ASSERT( g_HGLRC_Background == NULL );
|
||||
|
||||
GraphicsWindow::Initialize( false );
|
||||
}
|
||||
|
||||
LowLevelWindow_Win32::~LowLevelWindow_Win32()
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
GraphicsWindow::Shutdown();
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::GetDisplayResolutions( DisplayResolutions &out ) const
|
||||
{
|
||||
GraphicsWindow::GetDisplayResolutions( out );
|
||||
}
|
||||
|
||||
int ChooseWindowPixelFormat( const VideoModeParams &p, PIXELFORMATDESCRIPTOR *PixelFormat )
|
||||
{
|
||||
ASSERT( GraphicsWindow::GetHwnd() != NULL );
|
||||
ASSERT( GraphicsWindow::GetHDC() != NULL );
|
||||
|
||||
ZERO( *PixelFormat );
|
||||
PixelFormat->nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
PixelFormat->nVersion = 1;
|
||||
PixelFormat->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL;
|
||||
PixelFormat->iPixelType = PFD_TYPE_RGBA;
|
||||
PixelFormat->cColorBits = p.bpp == 16? 16:24;
|
||||
PixelFormat->cDepthBits = 16;
|
||||
|
||||
return ChoosePixelFormat( GraphicsWindow::GetHDC(), PixelFormat );
|
||||
}
|
||||
|
||||
void DumpPixelFormat( const PIXELFORMATDESCRIPTOR &pfd )
|
||||
{
|
||||
RString str = ssprintf( "Mode: " );
|
||||
bool bInvalidFormat = false;
|
||||
|
||||
if( pfd.dwFlags & PFD_GENERIC_FORMAT )
|
||||
{
|
||||
if( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) str += "MCD ";
|
||||
else { str += "software "; bInvalidFormat = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
str += "ICD ";
|
||||
}
|
||||
|
||||
if( pfd.iPixelType != PFD_TYPE_RGBA ) { str += "indexed "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ) { str += "!OPENGL "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ) { str += "!window "; bInvalidFormat = true; }
|
||||
if( !(pfd.dwFlags & PFD_DOUBLEBUFFER) ) { str += "!dbuff "; bInvalidFormat = true; }
|
||||
|
||||
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( bInvalidFormat )
|
||||
LOG->Warn( "Invalid format: %s", str.c_str() );
|
||||
else
|
||||
LOG->Info( "%s", str.c_str() );
|
||||
}
|
||||
|
||||
/* This function does not reset the video mode if it fails, because we might be trying
|
||||
* yet another video mode, so we'd just thrash the display. On fatal error,
|
||||
* LowLevelWindow_Win32::~LowLevelWindow_Win32 will call GraphicsWindow::Shutdown(). */
|
||||
RString LowLevelWindow_Win32::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut )
|
||||
{
|
||||
//LOG->Warn( "LowLevelWindow_Win32::TryVideoMode" );
|
||||
|
||||
ASSERT_M( p.bpp == 16 || p.bpp == 32, ssprintf("%i", p.bpp) );
|
||||
|
||||
bNewDeviceOut = false;
|
||||
|
||||
/* We're only allowed to change the pixel format of a window exactly once. */
|
||||
bool bCanSetPixelFormat = true;
|
||||
|
||||
/* Do we have an old window? */
|
||||
if( GraphicsWindow::GetHwnd() == NULL )
|
||||
{
|
||||
/* No. Always create and show the window before changing the video mode.
|
||||
* Otherwise, some other window may have focus, and changing the video mode will
|
||||
* cause that window to be resized. */
|
||||
bNewDeviceOut = true;
|
||||
GraphicsWindow::CreateGraphicsWindow( p );
|
||||
} else {
|
||||
/* We already have a window. Assume that its pixel format has already
|
||||
* been set. */
|
||||
bCanSetPixelFormat = false;
|
||||
}
|
||||
|
||||
ASSERT( GraphicsWindow::GetHwnd() );
|
||||
|
||||
/* Set the display mode: switch to a fullscreen mode or revert to windowed mode. */
|
||||
LOG->Trace("SetScreenMode ...");
|
||||
RString sErr = GraphicsWindow::SetScreenMode( p );
|
||||
if( !sErr.empty() )
|
||||
return sErr;
|
||||
|
||||
PIXELFORMATDESCRIPTOR PixelFormat;
|
||||
int iPixelFormat = ChooseWindowPixelFormat( p, &PixelFormat );
|
||||
if( iPixelFormat == 0 )
|
||||
{
|
||||
/* Destroy the window. */
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return "Pixel format not found";
|
||||
}
|
||||
|
||||
bool bNeedToSetPixelFormat = false;
|
||||
{
|
||||
/* We'll need to recreate it if the pixel format is going to change. We
|
||||
* aren't allowed to change the pixel format twice. */
|
||||
PIXELFORMATDESCRIPTOR DestPixelFormat;
|
||||
ZERO( DestPixelFormat );
|
||||
DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &DestPixelFormat );
|
||||
if( memcmp( &DestPixelFormat, &g_CurrentPixelFormat, sizeof(PIXELFORMATDESCRIPTOR) ) )
|
||||
{
|
||||
LOG->Trace("Reset: pixel format changing" );
|
||||
bNeedToSetPixelFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( bNeedToSetPixelFormat && !bCanSetPixelFormat )
|
||||
{
|
||||
/*
|
||||
* The screen mode has changed, so we need to set the pixel format. If we're
|
||||
* not allowed to do so, destroy the window and make a new one.
|
||||
*
|
||||
* For some reason, if we destroy the old window before creating the new one,
|
||||
* the "maximized apps go under the taskbar" glitch will happen when we quit.
|
||||
* We have to create the new window first.
|
||||
*/
|
||||
LOG->Trace( "Mode requires new pixel format, and we've already set one; resetting OpenGL context" );
|
||||
if( g_HGLRC != NULL )
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
wglDeleteContext( g_HGLRC );
|
||||
g_HGLRC = NULL;
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
bNewDeviceOut = true;
|
||||
}
|
||||
|
||||
/* If we deleted the OpenGL context above, also recreate the window. Otherwise, just
|
||||
* reconfigure it. */
|
||||
GraphicsWindow::CreateGraphicsWindow( p, bNewDeviceOut );
|
||||
|
||||
if( bNeedToSetPixelFormat )
|
||||
{
|
||||
/* Set the pixel format. */
|
||||
if( !SetPixelFormat(GraphicsWindow::GetHDC(), iPixelFormat, &PixelFormat) )
|
||||
{
|
||||
/* Destroy the window. */
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
|
||||
return werr_ssprintf( GetLastError(), "Pixel format failed" );
|
||||
}
|
||||
|
||||
DescribePixelFormat( GraphicsWindow::GetHDC(), iPixelFormat, sizeof(g_CurrentPixelFormat), &g_CurrentPixelFormat );
|
||||
|
||||
DumpPixelFormat( g_CurrentPixelFormat );
|
||||
}
|
||||
|
||||
if( g_HGLRC == NULL )
|
||||
{
|
||||
g_HGLRC = wglCreateContext( GraphicsWindow::GetHDC() );
|
||||
if ( g_HGLRC == NULL )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
|
||||
g_HGLRC_Background = wglCreateContext( GraphicsWindow::GetHDC() );
|
||||
if( g_HGLRC_Background == NULL )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
|
||||
if( !wglShareLists(g_HGLRC, g_HGLRC_Background) )
|
||||
{
|
||||
LOG->Warn( werr_ssprintf(GetLastError(), "wglShareLists failed") );
|
||||
wglDeleteContext( g_HGLRC_Background );
|
||||
g_HGLRC_Background = NULL;
|
||||
}
|
||||
|
||||
if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC ) )
|
||||
{
|
||||
DestroyGraphicsWindowAndOpenGLContext();
|
||||
return hr_ssprintf( GetLastError(), "wglCreateContext" );
|
||||
}
|
||||
}
|
||||
return RString(); // we set the video mode successfully
|
||||
}
|
||||
|
||||
bool LowLevelWindow_Win32::SupportsThreadedRendering()
|
||||
{
|
||||
return g_HGLRC_Background != NULL;
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::BeginConcurrentRendering()
|
||||
{
|
||||
if( !wglMakeCurrent( GraphicsWindow::GetHDC(), g_HGLRC_Background ) )
|
||||
{
|
||||
LOG->Warn( hr_ssprintf(GetLastError(), "wglMakeCurrent") );
|
||||
FAIL_M( hr_ssprintf(GetLastError(), "wglMakeCurrent") );
|
||||
}
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::EndConcurrentRendering()
|
||||
{
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
}
|
||||
|
||||
static LocalizedString OPENGL_NOT_AVAILABLE( "LowLevelWindow_Win32", "OpenGL hardware acceleration is not available." );
|
||||
bool LowLevelWindow_Win32::IsSoftwareRenderer( RString &sError )
|
||||
{
|
||||
RString sVendor = (const char*)glGetString(GL_VENDOR);
|
||||
RString sRenderer = (const char*)glGetString(GL_RENDERER);
|
||||
|
||||
LOG->Trace( "LowLevelWindow_Win32::IsSoftwareRenderer '%s', '%s'", sVendor.c_str(), sRenderer.c_str() );
|
||||
|
||||
if( sVendor == "Microsoft Corporation" && sRenderer == "GDI Generic" )
|
||||
{
|
||||
sError = OPENGL_NOT_AVAILABLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::SwapBuffers()
|
||||
{
|
||||
::SwapBuffers( GraphicsWindow::GetHDC() );
|
||||
}
|
||||
|
||||
void LowLevelWindow_Win32::Update()
|
||||
{
|
||||
GraphicsWindow::Update();
|
||||
}
|
||||
|
||||
const VideoModeParams &LowLevelWindow_Win32::GetActualVideoModeParams() const
|
||||
{
|
||||
return GraphicsWindow::GetParams();
|
||||
}
|
||||
|
||||
class RenderTarget_Win32 : public RenderTarget
|
||||
{
|
||||
public:
|
||||
RenderTarget_Win32( LowLevelWindow_Win32 *pWind );
|
||||
virtual ~RenderTarget_Win32();
|
||||
|
||||
void Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut );
|
||||
unsigned int GetTexture() const { return m_texHandle; }
|
||||
void StartRenderingTo();
|
||||
void FinishRenderingTo();
|
||||
|
||||
virtual bool InvertY() const { return true; }
|
||||
|
||||
private:
|
||||
LowLevelWindow_Win32 *m_pWind;
|
||||
int m_width;
|
||||
int m_height;
|
||||
GLuint m_texHandle;
|
||||
HDC m_hOldDeviceContext;
|
||||
HGLRC m_hOldRenderContext;
|
||||
};
|
||||
|
||||
RenderTarget_Win32::RenderTarget_Win32(LowLevelWindow_Win32 *pWind)
|
||||
{
|
||||
m_pWind = pWind;
|
||||
m_texHandle = 0;
|
||||
m_hOldDeviceContext = NULL;
|
||||
m_hOldRenderContext = NULL;
|
||||
}
|
||||
|
||||
RenderTarget_Win32::~RenderTarget_Win32()
|
||||
{
|
||||
glDeleteTextures( 1, &m_texHandle ); // deleting a 0 texture is safe and ignored
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::Create(const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut)
|
||||
{
|
||||
m_Param = param;
|
||||
m_width = param.iWidth;
|
||||
m_height = param.iHeight;
|
||||
|
||||
FlushGLErrors();
|
||||
|
||||
glGenTextures( 1, &m_texHandle );
|
||||
ASSERT(m_texHandle > 0);
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
|
||||
int iTextureWidth = power_of_two( param.iWidth );
|
||||
int iTextureHeight = power_of_two( param.iHeight );
|
||||
iTextureWidthOut = iTextureWidth;
|
||||
iTextureHeightOut = iTextureHeight;
|
||||
|
||||
GLenum internalformat;
|
||||
GLenum type = param.bWithAlpha? GL_RGBA:GL_RGB;
|
||||
if( param.bFloat && GLExt.m_bGL_ARB_texture_float )
|
||||
internalformat = param.bWithAlpha? GL_RGBA16F_ARB:GL_RGB16F_ARB;
|
||||
else
|
||||
internalformat = param.bWithAlpha? GL_RGBA8:GL_RGB8;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, iTextureWidth,
|
||||
iTextureHeight, 0, type, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
|
||||
|
||||
AssertNoGLError();
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::StartRenderingTo()
|
||||
{
|
||||
m_hOldDeviceContext = wglGetCurrentDC();
|
||||
m_hOldRenderContext = wglGetCurrentContext();
|
||||
|
||||
BOOL successful = wglMakeCurrent(GraphicsWindow::GetHDC(), g_HGLRC);
|
||||
ASSERT_M( successful == TRUE, "wglMakeCurrent failed in RenderTarget_Win32::StartRenderingTo()" );
|
||||
|
||||
FlushGLErrors();
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
AssertNoGLError();
|
||||
}
|
||||
|
||||
void RenderTarget_Win32::FinishRenderingTo()
|
||||
{
|
||||
FlushGLErrors();
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, m_texHandle );
|
||||
AssertNoGLError();
|
||||
|
||||
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height );
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
|
||||
AssertNoGLError();
|
||||
|
||||
BOOL successful = wglMakeCurrent(m_hOldDeviceContext, m_hOldRenderContext);
|
||||
ASSERT_M( successful == TRUE, "wglMakeCurrent failed in RenderTarget_Win32::FinishRenderingTo()" );
|
||||
|
||||
m_hOldDeviceContext = 0;
|
||||
m_hOldRenderContext = 0;
|
||||
}
|
||||
|
||||
RenderTarget* LowLevelWindow_Win32::CreateRenderTarget()
|
||||
{
|
||||
return new RenderTarget_Win32( this );
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2004 Glenn Maynard
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||
* whom the Software is furnished to do so, provided that the above
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user