2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* OpenGL implementation of NewGfx */
2009-10-20 03:39:24 +00:00
# include "C4Include.h"
2012-04-27 17:04:43 +00:00
# include <C4DrawGL.h>
2011-11-01 22:17:41 +00:00
2011-10-03 14:06:41 +00:00
# include <C4Surface.h>
2011-10-03 15:19:24 +00:00
# include <C4Window.h>
2014-11-06 16:19:41 +00:00
# include <C4FoWRegion.h>
2009-08-12 20:03:50 +00:00
# include "C4Rect.h"
2010-09-05 13:07:45 +00:00
# include "C4Config.h"
# include "C4Application.h"
2009-05-08 13:28:41 +00:00
2013-10-29 13:27:18 +00:00
# ifndef USE_CONSOLE
2009-05-08 13:28:41 +00:00
2010-01-26 18:35:15 +00:00
// MSVC doesn't define M_PI in math.h unless requested
# ifdef _MSC_VER
# define _USE_MATH_DEFINES
# endif /* _MSC_VER */
2009-05-08 13:28:41 +00:00
# include <stdio.h>
# include <math.h>
# include <limits.h>
2010-03-06 14:07:30 +00:00
CStdGL : : CStdGL ( ) :
2010-03-28 18:58:01 +00:00
pMainCtx ( 0 )
{
2009-05-08 13:28:41 +00:00
Default ( ) ;
2010-03-06 14:07:30 +00:00
byByteCnt = 4 ;
2009-05-08 13:28:41 +00:00
// global ptr
pGL = this ;
2010-03-18 12:52:09 +00:00
lines_tex = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
CStdGL : : ~ CStdGL ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Clear ( ) ;
pGL = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void CStdGL : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
NoPrimaryClipper ( ) ;
2010-12-29 14:19:46 +00:00
//if (pTexMgr) pTexMgr->IntUnlock(); // cannot do this here or we can't preserve textures across GL reinitialization as required when changing multisampling
2009-05-31 00:09:15 +00:00
InvalidateDeviceObjects ( ) ;
NoPrimaryClipper ( ) ;
RenderTarget = NULL ;
2014-11-24 19:50:05 +00:00
// Clear all shaders
SpriteShader . Clear ( ) ;
SpriteShaderMod2 . Clear ( ) ;
SpriteShaderBase . Clear ( ) ;
SpriteShaderBaseMod2 . Clear ( ) ;
SpriteShaderBaseOverlay . Clear ( ) ;
SpriteShaderBaseOverlayMod2 . Clear ( ) ;
SpriteShaderLight . Clear ( ) ;
SpriteShaderLightMod2 . Clear ( ) ;
SpriteShaderLightBase . Clear ( ) ;
SpriteShaderLightBaseMod2 . Clear ( ) ;
SpriteShaderLightBaseOverlay . Clear ( ) ;
SpriteShaderLightBaseOverlayMod2 . Clear ( ) ;
SpriteShaderLightBaseNormal . Clear ( ) ;
SpriteShaderLightBaseNormalMod2 . Clear ( ) ;
SpriteShaderLightBaseNormalOverlay . Clear ( ) ;
SpriteShaderLightBaseNormalOverlayMod2 . Clear ( ) ;
2009-05-31 00:09:15 +00:00
// clear context
if ( pCurrCtx ) pCurrCtx - > Deselect ( ) ;
2010-03-06 14:07:30 +00:00
pMainCtx = 0 ;
2011-10-03 14:34:08 +00:00
C4Draw : : Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void CStdGL : : FillBG ( DWORD dwClr )
2010-03-28 18:58:01 +00:00
{
2010-03-06 14:07:30 +00:00
if ( ! pCurrCtx ) return ;
2011-03-11 02:37:27 +00:00
glClearColor ( ( float ) GetRedValue ( dwClr ) / 255.0f , ( float ) GetGreenValue ( dwClr ) / 255.0f , ( float ) GetBlueValue ( dwClr ) / 255.0f , 0.0f ) ;
2009-05-08 13:28:41 +00:00
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool CStdGL : : UpdateClipper ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no render target? do nothing
if ( ! RenderTarget | | ! Active ) return true ;
// negative/zero?
2014-11-23 21:26:09 +00:00
C4Rect clipRect = GetClipRect ( ) ;
if ( clipRect . Wdt < = 0 | | clipRect . Hgt < = 0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ClipAll = true ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
ClipAll = false ;
// set it
2014-11-23 21:26:09 +00:00
glViewport ( clipRect . x , RenderTarget - > Hgt - clipRect . y - clipRect . Hgt , clipRect . Wdt , clipRect . Hgt ) ;
2009-05-08 13:28:41 +00:00
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
2009-09-10 02:54:12 +00:00
// Set clipping plane to -1000 and 1000 so that large meshes are not
// clipped away.
2010-02-06 17:33:30 +00:00
//glOrtho((GLdouble) iX, (GLdouble) (iX+iWdt), (GLdouble) (iY+iHgt), (GLdouble) iY, -1000.0f, 1000.0f);
2014-11-23 21:26:09 +00:00
gluOrtho2D ( ( GLdouble ) clipRect . x , ( GLdouble ) ( clipRect . x + clipRect . Wdt ) , ( GLdouble ) ( clipRect . y + clipRect . Hgt ) , ( GLdouble ) clipRect . y ) ;
2009-05-08 13:28:41 +00:00
//gluOrtho2D((GLdouble) 0, (GLdouble) xRes, (GLdouble) yRes, (GLdouble) yRes-iHgt);
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-03 14:07:07 +00:00
bool CStdGL : : PrepareRendering ( C4Surface * sfcToSurface )
2009-05-08 13:28:41 +00:00
{
// call from gfx thread only!
if ( ! pApp | | ! pApp - > AssertMainThread ( ) ) return false ;
// not ready?
if ( ! Active )
//if (!RestoreDeviceObjects())
2010-03-28 18:58:01 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// target?
if ( ! sfcToSurface ) return false ;
// target locked?
if ( sfcToSurface - > Locked ) return false ;
// target is already set as render target?
if ( sfcToSurface ! = RenderTarget )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// target is a render-target?
if ( ! sfcToSurface - > IsRenderTarget ( ) ) return false ;
2010-03-06 14:07:30 +00:00
// context
if ( sfcToSurface - > pCtx & & sfcToSurface - > pCtx ! = pCurrCtx )
if ( ! sfcToSurface - > pCtx - > Select ( ) ) return false ;
2009-05-08 13:28:41 +00:00
// set target
RenderTarget = sfcToSurface ;
// new target has different size; needs other clipping rect
UpdateClipper ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-08-27 21:12:01 +00:00
CStdGLCtx * CStdGL : : CreateContext ( C4Window * pWindow , C4AbstractApp * pApp )
2010-03-28 18:58:01 +00:00
{
2009-06-02 23:59:04 +00:00
DebugLog ( " gl: Create Context... " ) ;
2009-05-08 13:28:41 +00:00
// safety
if ( ! pWindow ) return NULL ;
// create it
CStdGLCtx * pCtx = new CStdGLCtx ( ) ;
2014-12-14 11:35:22 +00:00
bool first_ctx = ! pMainCtx ;
if ( first_ctx ) pMainCtx = pCtx ;
bool success = pCtx - > Init ( pWindow , pApp ) ;
// First context: Log some information about hardware/drivers
// Must log after context creation to get valid results
if ( first_ctx )
{
const char * gl_vendor = reinterpret_cast < const char * > ( glGetString ( GL_VENDOR ) ) ;
const char * gl_renderer = reinterpret_cast < const char * > ( glGetString ( GL_RENDERER ) ) ;
const char * gl_version = reinterpret_cast < const char * > ( glGetString ( GL_VERSION ) ) ;
const char * gl_extensions = reinterpret_cast < const char * > ( glGetString ( GL_EXTENSIONS ) ) ;
LogF ( " GL %s on %s (%s) " , gl_version ? gl_version : " " , gl_renderer ? gl_renderer : " " , gl_vendor ? gl_vendor : " " ) ;
// LogSilentF("GLExt: %s", gl_extensions ? gl_extensions : ""); // uncomment to flood the log with extension list
}
if ( ! success )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pCtx ; Error ( " gl: Error creating secondary context! " ) ; return NULL ;
2010-03-28 18:58:01 +00:00
}
2010-12-03 19:18:36 +00:00
// creation selected the new context - switch back to previous context
RenderTarget = NULL ;
pCurrCtx = NULL ;
2009-05-08 13:28:41 +00:00
// done
return pCtx ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-03-23 21:53:56 +00:00
# ifdef USE_WIN32_WINDOWS
2011-08-27 14:20:39 +00:00
CStdGLCtx * CStdGL : : CreateContext ( HWND hWindow , C4AbstractApp * pApp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! hWindow ) return NULL ;
// create it
CStdGLCtx * pCtx = new CStdGLCtx ( ) ;
if ( ! pCtx - > Init ( NULL , pApp , hWindow ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
delete pCtx ; Error ( " gl: Error creating secondary context! " ) ; return NULL ;
2010-03-28 18:58:01 +00:00
}
2010-12-03 19:18:36 +00:00
if ( ! pMainCtx )
{
pMainCtx = pCtx ;
}
else
{
// creation selected the new context - switch back to previous context
RenderTarget = NULL ;
pCurrCtx = NULL ;
}
2009-05-08 13:28:41 +00:00
// done
return pCtx ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# endif
2014-11-04 16:24:55 +00:00
bool CStdGL : : CreatePrimarySurfaces ( unsigned int , unsigned int , int iColorDepth , unsigned int )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// store options
2009-05-31 00:09:15 +00:00
return RestoreDeviceObjects ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2014-11-24 19:50:05 +00:00
void CStdGL : : SetupMultiBlt ( C4ShaderCall & call , const C4BltTransform * pTransform , GLuint baseTex , GLuint overlayTex , GLuint normalTex , DWORD dwOverlayModClr )
2014-10-08 01:48:11 +00:00
{
2014-11-04 16:24:55 +00:00
// Initialize multi blit shader.
2014-10-08 01:48:11 +00:00
int iAdditive = dwBlitMode & C4GFXBLIT_ADDITIVE ;
glBlendFunc ( GL_SRC_ALPHA , iAdditive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA ) ;
2014-11-24 19:50:05 +00:00
call . Start ( ) ;
// Upload uniforms
2014-10-08 01:48:11 +00:00
const DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff ;
2014-11-24 19:50:05 +00:00
const float fMod [ 4 ] = {
2014-10-08 01:48:11 +00:00
( ( dwModClr > > 16 ) & 0xff ) / 255.0f ,
( ( dwModClr > > 8 ) & 0xff ) / 255.0f ,
( ( dwModClr ) & 0xff ) / 255.0f ,
( ( dwModClr > > 24 ) & 0xff ) / 255.0f
} ;
2014-11-24 19:50:05 +00:00
call . SetUniform4fv ( C4SSU_ClrMod , 1 , fMod ) ;
2014-10-08 01:48:11 +00:00
2014-11-24 19:50:05 +00:00
if ( baseTex ! = 0 )
2014-11-07 20:28:52 +00:00
{
2014-11-24 19:50:05 +00:00
call . AllocTexUnit ( C4SSU_BaseTex , GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , baseTex ) ;
2014-11-07 20:28:52 +00:00
}
2014-11-24 19:50:05 +00:00
if ( overlayTex ! = 0 )
2014-10-08 01:48:11 +00:00
{
2014-11-24 19:50:05 +00:00
call . AllocTexUnit ( C4SSU_OverlayTex , GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , overlayTex ) ;
2014-11-06 16:19:41 +00:00
2014-11-24 19:50:05 +00:00
const float fOverlayModClr [ 4 ] = {
( ( dwOverlayModClr > > 16 ) & 0xff ) / 255.0f ,
( ( dwOverlayModClr > > 8 ) & 0xff ) / 255.0f ,
( ( dwOverlayModClr ) & 0xff ) / 255.0f ,
( ( dwOverlayModClr > > 24 ) & 0xff ) / 255.0f
} ;
2014-11-19 16:18:07 +00:00
2014-11-24 19:50:05 +00:00
call . SetUniform4fv ( C4SSU_OverlayClr , 1 , fOverlayModClr ) ;
2014-10-08 01:48:11 +00:00
}
2014-11-24 19:50:05 +00:00
if ( pFoW ! = NULL & & normalTex ! = 0 )
2014-11-02 01:46:30 +00:00
{
2014-11-24 19:50:05 +00:00
call . AllocTexUnit ( C4SSU_NormalTex , GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , normalTex ) ;
2014-11-02 01:46:30 +00:00
}
2014-11-24 19:50:05 +00:00
if ( pFoW ! = NULL )
2014-10-08 04:21:05 +00:00
{
2014-11-24 19:50:05 +00:00
const C4Rect ClipRect = GetClipRect ( ) ;
const C4Rect LightRect = pFoW - > getRegion ( ) ;
// Dynamic Light
call . AllocTexUnit ( C4SSU_LightTex , GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , pFoW - > getSurface ( ) - > ppTex [ 0 ] - > texName ) ;
float lightTransform [ 6 ] ;
2014-12-22 16:15:46 +00:00
pFoW - > GetFragTransform ( ClipRect , lightTransform ) ;
2014-11-24 19:50:05 +00:00
call . SetUniformMatrix2x3fv ( C4SSU_LightTransform , 1 , lightTransform ) ;
// Ambient Light
call . AllocTexUnit ( C4SSU_AmbientTex , GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , pFoW - > getFoW ( ) - > Ambient . Tex ) ;
call . SetUniform1f ( C4SSU_AmbientBrightness , pFoW - > getFoW ( ) - > Ambient . GetBrightness ( ) ) ;
float ambientTransform [ 6 ] ;
pFoW - > getFoW ( ) - > Ambient . GetFragTransform ( LightRect , ClipRect , ambientTransform ) ;
call . SetUniformMatrix2x3fv ( C4SSU_AmbientTransform , 1 , ambientTransform ) ;
2014-10-08 04:21:05 +00:00
}
2014-10-08 01:48:11 +00:00
2014-11-02 01:46:30 +00:00
// Apply zoom and transform
2014-10-08 04:21:05 +00:00
glPushMatrix ( ) ;
2014-10-08 01:48:11 +00:00
glTranslatef ( ZoomX , ZoomY , 0.0f ) ;
2014-11-26 22:56:43 +00:00
// Scale Z as well so that we don't distort normals.
glScalef ( Zoom , Zoom , Zoom ) ;
2014-10-08 01:48:11 +00:00
glTranslatef ( - ZoomX , - ZoomY , 0.0f ) ;
2014-11-02 01:46:30 +00:00
if ( pTransform )
{
2014-11-26 22:56:43 +00:00
// Decompose scale factors and scale Z accordingly to X and Y, again to avoid distorting normals
// We could instead work around this by using the projection matrix, but then for object rotations (SetR)
// the normals would not be correct.
const float sx = sqrt ( pTransform - > mat [ 0 ] * pTransform - > mat [ 0 ] + pTransform - > mat [ 1 ] * pTransform - > mat [ 1 ] ) ;
const float sy = sqrt ( pTransform - > mat [ 3 ] * pTransform - > mat [ 3 ] + pTransform - > mat [ 4 ] * pTransform - > mat [ 4 ] ) ;
const float sz = sqrt ( sx * sy ) ;
const GLfloat transform [ 16 ] = { pTransform - > mat [ 0 ] , pTransform - > mat [ 3 ] , 0 , pTransform - > mat [ 6 ] , pTransform - > mat [ 1 ] , pTransform - > mat [ 4 ] , 0 , pTransform - > mat [ 7 ] , 0 , 0 , sz , 0 , pTransform - > mat [ 2 ] , pTransform - > mat [ 5 ] , 0 , pTransform - > mat [ 8 ] } ;
2014-11-02 01:46:30 +00:00
glMultMatrixf ( transform ) ;
}
2014-10-08 04:21:05 +00:00
}
2014-11-24 19:50:05 +00:00
void CStdGL : : ResetMultiBlt ( )
2014-10-08 04:21:05 +00:00
{
glPopMatrix ( ) ;
}
void CStdGL : : PerformMultiPix ( C4Surface * sfcTarget , const C4BltVertex * vertices , unsigned int n_vertices )
{
// Only direct rendering
assert ( sfcTarget - > IsRenderTarget ( ) ) ;
if ( ! PrepareRendering ( sfcTarget ) ) return ;
// Draw on pixel center:
glPushMatrix ( ) ;
glTranslatef ( 0.5f , 0.5f , 0.0f ) ;
// Feed the vertices to the GL
2014-11-24 19:50:05 +00:00
C4ShaderCall call ( GetSpriteShader ( false , false , false ) ) ;
SetupMultiBlt ( call , NULL , 0 , 0 , 0 , 0 ) ;
2014-10-08 01:48:11 +00:00
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
2014-10-08 02:51:34 +00:00
// This is a workaround. Instead of submitting the whole vertex array to the GL, we do it
// in batches of 256 vertices. The intel graphics driver on Linux crashes with
// significantly larger arrays, such as 400. It's not clear to me why, maybe POINT drawing
// is just not very well tested.
const unsigned int BATCH_SIZE = 256 ;
for ( unsigned int i = 0 ; i < n_vertices ; i + = BATCH_SIZE )
{
glVertexPointer ( 2 , GL_FLOAT , sizeof ( C4BltVertex ) , & vertices [ i ] . ftx ) ;
glColorPointer ( 4 , GL_UNSIGNED_BYTE , sizeof ( C4BltVertex ) , & vertices [ i ] . color [ 0 ] ) ;
glDrawArrays ( GL_POINTS , 0 , std : : min ( n_vertices - i , BATCH_SIZE ) ) ;
}
2014-10-08 01:48:11 +00:00
glDisableClientState ( GL_VERTEX_ARRAY ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
glPopMatrix ( ) ;
2014-10-08 04:21:05 +00:00
2014-11-24 19:50:05 +00:00
ResetMultiBlt ( ) ;
2014-10-08 04:21:05 +00:00
}
void CStdGL : : PerformMultiLines ( C4Surface * sfcTarget , const C4BltVertex * vertices , unsigned int n_vertices , float width )
{
// Only direct rendering
assert ( sfcTarget - > IsRenderTarget ( ) ) ;
if ( ! PrepareRendering ( sfcTarget ) ) return ;
// In a first step, we transform the lines array to a triangle array, so that we can draw
// the lines with some thickness.
// In principle, this step could be easily (and probably much more efficiently) performed
// by a geometry shader as well, however that would require OpenGL 3.2.
C4BltVertex * tri_vertices = new C4BltVertex [ n_vertices * 3 ] ;
for ( unsigned int i = 0 ; i < n_vertices ; i + = 2 )
{
const float x1 = vertices [ i ] . ftx ;
const float y1 = vertices [ i ] . fty ;
const float x2 = vertices [ i + 1 ] . ftx ;
const float y2 = vertices [ i + 1 ] . fty ;
float offx = y1 - y2 ;
float offy = x2 - x1 ;
float l = sqrtf ( offx * offx + offy * offy ) ;
// avoid division by zero
l + = 0.000000005f ;
offx * = width / l ;
offy * = width / l ;
tri_vertices [ 3 * i + 0 ] . ftx = x1 + offx ; tri_vertices [ 3 * i + 0 ] . fty = y1 + offy ;
tri_vertices [ 3 * i + 1 ] . ftx = x1 - offx ; tri_vertices [ 3 * i + 1 ] . fty = y1 - offy ;
tri_vertices [ 3 * i + 2 ] . ftx = x2 - offx ; tri_vertices [ 3 * i + 2 ] . fty = y2 - offy ;
tri_vertices [ 3 * i + 3 ] . ftx = x2 + offx ; tri_vertices [ 3 * i + 3 ] . fty = y2 + offy ;
for ( int j = 0 ; j < 4 ; + + j )
{
tri_vertices [ 3 * i + 0 ] . color [ j ] = vertices [ i ] . color [ j ] ;
tri_vertices [ 3 * i + 1 ] . color [ j ] = vertices [ i ] . color [ j ] ;
tri_vertices [ 3 * i + 2 ] . color [ j ] = vertices [ i + 1 ] . color [ j ] ;
tri_vertices [ 3 * i + 3 ] . color [ j ] = vertices [ i + 1 ] . color [ j ] ;
}
tri_vertices [ 3 * i + 0 ] . tx = 0.f ; tri_vertices [ 3 * i + 0 ] . ty = 0.f ;
tri_vertices [ 3 * i + 1 ] . tx = 0.f ; tri_vertices [ 3 * i + 1 ] . ty = 2.f ;
tri_vertices [ 3 * i + 2 ] . tx = 1.f ; tri_vertices [ 3 * i + 2 ] . ty = 2.f ;
tri_vertices [ 3 * i + 3 ] . tx = 1.f ; tri_vertices [ 3 * i + 3 ] . ty = 0.f ;
tri_vertices [ 3 * i + 4 ] = tri_vertices [ 3 * i + 2 ] ; // duplicate vertex
tri_vertices [ 3 * i + 5 ] = tri_vertices [ 3 * i + 0 ] ; // duplicate vertex
}
// Then, feed the vertices to the GL
2014-11-24 19:50:05 +00:00
C4ShaderCall call ( GetSpriteShader ( true , false , false ) ) ;
SetupMultiBlt ( call , NULL , lines_tex , 0 , 0 , 0 ) ;
2014-10-08 04:21:05 +00:00
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
2014-11-24 19:50:05 +00:00
glClientActiveTexture ( GL_TEXTURE0 ) ;
2014-10-08 04:21:05 +00:00
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( C4BltVertex ) , & tri_vertices [ 0 ] . tx ) ;
glVertexPointer ( 2 , GL_FLOAT , sizeof ( C4BltVertex ) , & tri_vertices [ 0 ] . ftx ) ;
glColorPointer ( 4 , GL_UNSIGNED_BYTE , sizeof ( C4BltVertex ) , & tri_vertices [ 0 ] . color [ 0 ] ) ;
glDrawArrays ( GL_TRIANGLES , 0 , n_vertices * 3 ) ;
delete [ ] tri_vertices ;
glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glDisableClientState ( GL_VERTEX_ARRAY ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
2014-11-24 19:50:05 +00:00
ResetMultiBlt ( ) ;
2014-10-08 01:48:11 +00:00
}
2014-11-07 20:28:52 +00:00
void CStdGL : : PerformMultiTris ( C4Surface * sfcTarget , const C4BltVertex * vertices , unsigned int n_vertices , const C4BltTransform * pTransform , C4TexRef * pTex , C4TexRef * pOverlay , C4TexRef * pNormal , DWORD dwOverlayModClr )
2014-10-08 17:35:55 +00:00
{
// Only direct rendering
assert ( sfcTarget - > IsRenderTarget ( ) ) ;
if ( ! PrepareRendering ( sfcTarget ) ) return ;
// Feed the vertices to the GL
2014-11-24 19:50:05 +00:00
C4ShaderCall call ( GetSpriteShader ( pTex ! = NULL , pOverlay ! = NULL , pNormal ! = NULL ) ) ;
SetupMultiBlt ( call , pTransform , pTex ? pTex - > texName : 0 , pOverlay ? pOverlay - > texName : 0 , pNormal ? pNormal - > texName : 0 , dwOverlayModClr ) ;
2014-10-08 17:35:55 +00:00
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glEnableClientState ( GL_COLOR_ARRAY ) ;
if ( pTex )
{
2014-11-02 01:46:30 +00:00
// We use the texture coordinate array in texture0 for
2014-11-24 19:50:05 +00:00
// the base, overlay and normal textures
glClientActiveTexture ( GL_TEXTURE0 ) ;
2014-10-08 17:35:55 +00:00
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( C4BltVertex ) , & vertices [ 0 ] . tx ) ;
}
glVertexPointer ( 2 , GL_FLOAT , sizeof ( C4BltVertex ) , & vertices [ 0 ] . ftx ) ;
glColorPointer ( 4 , GL_UNSIGNED_BYTE , sizeof ( C4BltVertex ) , & vertices [ 0 ] . color [ 0 ] ) ;
glDrawArrays ( GL_TRIANGLES , 0 , n_vertices ) ;
if ( pTex ) glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
glDisableClientState ( GL_VERTEX_ARRAY ) ;
glDisableClientState ( GL_COLOR_ARRAY ) ;
2014-11-24 19:50:05 +00:00
ResetMultiBlt ( ) ;
}
bool CStdGL : : CreateSpriteShader ( C4Shader & shader , const char * name , int ssc , C4GroupSet * pGroups )
{
static const char vertexSlice [ ] =
" gl_FrontColor = gl_Color; "
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; " ;
const char * uniformNames [ C4SSU_Count + 1 ] ;
uniformNames [ C4SSU_ClrMod ] = " clrMod " ;
uniformNames [ C4SSU_BaseTex ] = " baseTex " ;
uniformNames [ C4SSU_OverlayTex ] = " overlayTex " ;
uniformNames [ C4SSU_OverlayClr ] = " overlayClr " ;
uniformNames [ C4SSU_LightTex ] = " lightTex " ;
uniformNames [ C4SSU_LightTransform ] = " lightTransform " ;
uniformNames [ C4SSU_NormalTex ] = " normalTex " ;
uniformNames [ C4SSU_AmbientTex ] = " ambientTex " ;
uniformNames [ C4SSU_AmbientTransform ] = " ambientTransform " ;
uniformNames [ C4SSU_AmbientBrightness ] = " ambientBrightness " ;
uniformNames [ C4SSU_Count ] = NULL ;
// Clear previous content
shader . Clear ( ) ;
shader . ClearSlices ( ) ;
shader . AddVertexSlice ( C4Shader_Vertex_PositionPos , vertexSlice ) ;
// Add texture coordinate if we have base texture, overlay, or normal map
if ( ( ssc & ( C4SSC_BASE | C4SSC_OVERLAY | C4SSC_NORMAL ) ) ! = 0 )
shader . AddTexCoord ( " texcoord " ) ;
// Then load slices for fragment shader
2014-12-22 16:15:46 +00:00
shader . AddFragmentSlice ( - 1 , " #define OPENCLONK " ) ;
2014-11-24 19:50:05 +00:00
if ( ssc & C4SSC_MOD2 ) shader . AddFragmentSlice ( - 1 , " #define CLRMOD_MOD2 " ) ;
if ( ssc & C4SSC_NORMAL ) shader . AddFragmentSlice ( - 1 , " #define HAVE_NORMALMAP " ) ;
2014-12-03 15:47:33 +00:00
if ( ssc & C4SSC_LIGHT ) shader . AddFragmentSlice ( - 1 , " #define HAVE_LIGHT " ) ;
2014-11-25 16:54:36 +00:00
shader . LoadSlices ( pGroups , " UtilShader.glsl " ) ;
2014-12-03 15:47:33 +00:00
shader . LoadSlices ( pGroups , " ObjectBaseShader.glsl " ) ;
2014-11-24 19:50:05 +00:00
2014-11-25 16:54:36 +00:00
if ( ssc & C4SSC_BASE ) shader . LoadSlices ( pGroups , " SpriteTextureShader.glsl " ) ;
if ( ssc & C4SSC_OVERLAY ) shader . LoadSlices ( pGroups , " SpriteOverlayShader.glsl " ) ;
2014-11-24 19:50:05 +00:00
if ( ssc & C4SSC_LIGHT )
{
2014-12-03 15:47:33 +00:00
shader . LoadSlices ( pGroups , " ObjectLightShader.glsl " ) ;
2014-11-25 16:54:36 +00:00
shader . LoadSlices ( pGroups , " LightShader.glsl " ) ;
shader . LoadSlices ( pGroups , " AmbientShader.glsl " ) ;
2014-11-24 19:50:05 +00:00
}
if ( ! shader . Init ( name , uniformNames ) )
{
shader . ClearSlices ( ) ;
return false ;
}
return true ;
}
C4Shader * CStdGL : : GetSpriteShader ( bool haveBase , bool haveOverlay , bool haveNormal )
{
int ssc = 0 ;
if ( dwBlitMode & C4GFXBLIT_MOD2 ) ssc | = C4SSC_MOD2 ;
if ( haveBase ) ssc | = C4SSC_BASE ;
if ( haveBase & & haveOverlay ) ssc | = C4SSC_OVERLAY ;
if ( pFoW ! = NULL ) ssc | = C4SSC_LIGHT ;
if ( pFoW ! = NULL & & haveBase & & haveNormal ) ssc | = C4SSC_NORMAL ;
return GetSpriteShader ( ssc ) ;
}
C4Shader * CStdGL : : GetSpriteShader ( int ssc )
{
C4Shader * shaders [ 16 ] = {
& SpriteShader ,
& SpriteShaderMod2 ,
& SpriteShaderBase ,
& SpriteShaderBaseMod2 ,
& SpriteShaderBaseOverlay ,
& SpriteShaderBaseOverlayMod2 ,
& SpriteShaderLight ,
& SpriteShaderLightMod2 ,
& SpriteShaderLightBase ,
& SpriteShaderLightBaseMod2 ,
& SpriteShaderLightBaseOverlay ,
& SpriteShaderLightBaseOverlayMod2 ,
& SpriteShaderLightBaseNormal ,
& SpriteShaderLightBaseNormalMod2 ,
& SpriteShaderLightBaseNormalOverlay ,
& SpriteShaderLightBaseNormalOverlayMod2 ,
} ;
int index = 0 ;
if ( ssc & C4SSC_LIGHT ) index + = 6 ;
if ( ssc & C4SSC_BASE )
{
index + = 2 ;
if ( ssc & C4SSC_OVERLAY )
index + = 2 ;
if ( ( ssc & C4SSC_NORMAL ) & & ( ssc & C4SSC_LIGHT ) )
index + = 4 ;
}
if ( ssc & C4SSC_MOD2 )
index + = 1 ;
assert ( index < 16 ) ;
return shaders [ index ] ;
}
bool CStdGL : : InitShaders ( C4GroupSet * pGroups )
{
// Create sprite blitting shaders
if ( ! CreateSpriteShader ( SpriteShader , " sprite " , 0 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderMod2 , " spriteMod2 " , C4SSC_MOD2 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderBase , " spriteBase " , C4SSC_BASE , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderBaseMod2 , " spriteBaseMod2 " , C4SSC_MOD2 | C4SSC_BASE , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderBaseOverlay , " spriteBaseOverlay " , C4SSC_BASE | C4SSC_OVERLAY , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderBaseOverlayMod2 , " spriteBaseOverlayMod2 " , C4SSC_MOD2 | C4SSC_BASE | C4SSC_OVERLAY , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLight , " spriteLight " , C4SSC_LIGHT , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightMod2 , " spriteLightMod2 " , C4SSC_LIGHT | C4SSC_MOD2 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBase , " spriteLightBase " , C4SSC_LIGHT | C4SSC_BASE , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseMod2 , " spriteLightBaseMod2 " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_MOD2 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseOverlay , " spriteLightBaseOverlay " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseOverlayMod2 , " spriteLightBaseOverlayMod2 " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_MOD2 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseNormal , " spriteLightBaseNormal " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_NORMAL , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseNormalMod2 , " spriteLightBaseNormalMod2 " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_NORMAL | C4SSC_MOD2 , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseNormalOverlay , " spriteLightBaseNormalOverlay " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_NORMAL , pGroups ) )
return false ;
if ( ! CreateSpriteShader ( SpriteShaderLightBaseNormalOverlayMod2 , " spriteLightBaseNormalOverlayMod2 " , C4SSC_LIGHT | C4SSC_BASE | C4SSC_OVERLAY | C4SSC_NORMAL | C4SSC_MOD2 , pGroups ) )
return false ;
return true ;
2014-10-08 17:35:55 +00:00
}
2009-05-08 13:28:41 +00:00
bool CStdGL : : RestoreDeviceObjects ( )
2010-03-28 18:58:01 +00:00
{
2010-03-06 14:07:30 +00:00
assert ( pMainCtx ) ;
2009-05-08 13:28:41 +00:00
// delete any previous objects
InvalidateDeviceObjects ( ) ;
2010-02-18 20:19:04 +00:00
2010-03-06 14:07:30 +00:00
// set states
Active = pMainCtx - > Select ( ) ;
RenderTarget = pApp - > pWindow - > pSurface ;
2014-11-24 19:50:05 +00:00
// TODO: I think this should be updated. We need at least GLSL 1.20 now, which is OpenGL 2.1
2010-03-06 14:07:30 +00:00
// BGRA Pixel Formats, Multitexturing, Texture Combine Environment Modes
2012-03-03 22:25:50 +00:00
// Check for GL 1.2 and two functions from 1.3 we need.
if ( ! GLEW_VERSION_1_2 | |
glActiveTexture = = NULL | |
glClientActiveTexture = = NULL
) {
2010-08-03 17:02:00 +00:00
return Error ( " gl: OpenGL Version 1.3 or higher required. A better graphics driver will probably help. " ) ;
2010-03-28 18:58:01 +00:00
}
2010-03-06 14:07:30 +00:00
2010-02-18 20:19:04 +00:00
// lines texture
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
glGenTextures ( 1 , & lines_tex ) ;
glBindTexture ( GL_TEXTURE_2D , lines_tex ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_MIRRORED_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_MIRRORED_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
const char * linedata = byByteCnt = = 2 ? " \xff \xf0 \xff \xff " : " \xff \xff \xff \x00 \xff \xff \xff \xff " ;
glTexImage2D ( GL_TEXTURE_2D , 0 , 4 , 1 , 2 , 0 , GL_BGRA , byByteCnt = = 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV , linedata ) ;
MaxTexSize = 64 ;
GLint s = 0 ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & s ) ;
if ( s > 0 ) MaxTexSize = s ;
2009-05-08 13:28:41 +00:00
// restore gamma if active
if ( Active )
EnableGamma ( ) ;
// reset blit states
dwBlitMode = 0 ;
// done
return Active ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool CStdGL : : InvalidateDeviceObjects ( )
{
bool fSuccess = true ;
// clear gamma
2010-03-28 18:58:01 +00:00
# ifndef USE_SDL_MAINLOOP
2009-05-08 13:28:41 +00:00
DisableGamma ( ) ;
2010-03-28 18:58:01 +00:00
# endif
2009-05-08 13:28:41 +00:00
// deactivate
Active = false ;
// invalidate font objects
// invalidate primary surfaces
2010-02-18 20:19:04 +00:00
if ( lines_tex )
2010-03-28 18:58:01 +00:00
{
2010-02-18 20:19:04 +00:00
glDeleteTextures ( 1 , & lines_tex ) ;
lines_tex = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
return fSuccess ;
}
2014-01-03 14:13:09 +00:00
bool CStdGL : : EnsureAnyContext ( )
{
// Make sure some context is selected
if ( pCurrCtx ) return true ;
if ( ! pMainCtx ) return false ;
return pMainCtx - > Select ( ) ;
}
2010-08-03 17:02:00 +00:00
bool CStdGL : : Error ( const char * szMsg )
{
2012-06-06 15:13:51 +00:00
# ifdef USE_WIN32_WINDOWS
DWORD err = GetLastError ( ) ;
# endif
2012-06-06 14:49:40 +00:00
bool r = C4Draw : : Error ( szMsg ) ;
# ifdef USE_WIN32_WINDOWS
wchar_t * lpMsgBuf ;
FormatMessage (
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL ,
err ,
MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) ,
( LPTSTR ) & lpMsgBuf ,
0 , NULL ) ;
LogF ( " gl: GetLastError() = %d - %s " , err , StdStrBuf ( lpMsgBuf ) . getData ( ) ) ;
LocalFree ( lpMsgBuf ) ;
# endif
2010-08-03 17:02:00 +00:00
LogF ( " gl: %s " , glGetString ( GL_VENDOR ) ) ;
LogF ( " gl: %s " , glGetString ( GL_RENDERER ) ) ;
LogF ( " gl: %s " , glGetString ( GL_VERSION ) ) ;
LogF ( " gl: %s " , glGetString ( GL_EXTENSIONS ) ) ;
2012-06-06 14:49:40 +00:00
return r ;
2010-08-03 17:02:00 +00:00
}
2009-05-08 13:28:41 +00:00
bool CStdGL : : CheckGLError ( const char * szAtOp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
GLenum err = glGetError ( ) ;
if ( ! err ) return true ;
2014-11-24 18:42:15 +00:00
LogF ( " GL error with %s: %d - %s " , szAtOp , err , gluErrorString ( err ) ) ;
2010-03-28 18:58:01 +00:00
return false ;
}
2009-05-08 13:28:41 +00:00
CStdGL * pGL = NULL ;
2012-04-07 19:33:39 +00:00
# ifdef USE_WIN32_WINDOWS
2009-05-08 13:28:41 +00:00
void CStdGL : : TaskOut ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pCurrCtx ) pCurrCtx - > Deselect ( ) ;
2010-03-28 18:58:01 +00:00
}
2010-09-05 13:07:45 +00:00
# endif
2009-05-08 13:28:41 +00:00
bool CStdGL : : OnResolutionChanged ( unsigned int iXRes , unsigned int iYRes )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Re-create primary clipper to adapt to new size.
CreatePrimaryClipper ( iXRes , iYRes ) ;
2010-02-18 20:19:04 +00:00
RestoreDeviceObjects ( ) ;
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void CStdGL : : Default ( )
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:34:08 +00:00
C4Draw : : Default ( ) ;
2010-03-06 14:07:30 +00:00
pCurrCtx = NULL ;
2009-05-08 13:28:41 +00:00
iPixelFormat = 0 ;
sfcFmt = 0 ;
iClrDpt = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-10-29 13:27:18 +00:00
# endif // USE_CONSOLE