mirror of
https://github.com/ioquake/ioq3.git
synced 2024-11-10 07:11:46 +00:00
Merge pull request #664 from zturtleman/opengles2
This commit is contained in:
commit
980147721a
18 changed files with 799 additions and 202 deletions
15
README.md
15
README.md
|
@ -160,6 +160,21 @@ Makefile.local:
|
||||||
The defaults for these variables differ depending on the target platform.
|
The defaults for these variables differ depending on the target platform.
|
||||||
|
|
||||||
|
|
||||||
|
# OpenGL ES support
|
||||||
|
|
||||||
|
The opengl2 renderer (the default) supports OpenGL ES 2+. Though there
|
||||||
|
are many missing features and the performance may not be sufficient for
|
||||||
|
embedded System-on-a-Chip and mobile platforms.
|
||||||
|
|
||||||
|
The opengl1 renderer does not have OpenGL ES support.
|
||||||
|
|
||||||
|
The `r_useOpenGLES` cvar controls whether to use OpenGL or OpenGL ES API.
|
||||||
|
Set to -1 for auto (default), 0 for OpenGL, and 1 for OpenGL ES. It should be
|
||||||
|
set using command line arguments:
|
||||||
|
|
||||||
|
ioquake3 +set cl_renderer opengl2 +set r_useOpenGLES 1
|
||||||
|
|
||||||
|
|
||||||
# Console
|
# Console
|
||||||
|
|
||||||
## New cvars
|
## New cvars
|
||||||
|
|
|
@ -357,11 +357,12 @@ qboolean CL_OpenAVIForWriting( const char *fileName )
|
||||||
else
|
else
|
||||||
afd.motionJpeg = qfalse;
|
afd.motionJpeg = qfalse;
|
||||||
|
|
||||||
// Buffers only need to store RGB pixels.
|
// Capture buffer stores RGB pixels but OpenGL ES reads RGBA and converts to RGB in-place.
|
||||||
|
// Encode buffer only needs to store RGB pixels.
|
||||||
// Allocate a bit more space for the capture buffer to account for possible
|
// Allocate a bit more space for the capture buffer to account for possible
|
||||||
// padding at the end of pixel lines, and padding for alignment
|
// padding at the end of pixel lines, and padding for alignment
|
||||||
#define MAX_PACK_LEN 16
|
#define MAX_PACK_LEN 16
|
||||||
afd.cBuffer = Z_Malloc((afd.width * 3 + MAX_PACK_LEN - 1) * afd.height + MAX_PACK_LEN - 1);
|
afd.cBuffer = Z_Malloc((afd.width * 4 + MAX_PACK_LEN - 1) * afd.height + MAX_PACK_LEN - 1);
|
||||||
// raw avi files have pixel lines start on 4-byte boundaries
|
// raw avi files have pixel lines start on 4-byte boundaries
|
||||||
afd.eBuffer = Z_Malloc(PAD(afd.width * 3, AVI_LINE_PADDING) * afd.height);
|
afd.eBuffer = Z_Malloc(PAD(afd.width * 3, AVI_LINE_PADDING) * afd.height);
|
||||||
|
|
||||||
|
|
|
@ -732,6 +732,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
|
||||||
}
|
}
|
||||||
|
|
||||||
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
|
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
|
||||||
|
byte *buffer;
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
|
|
||||||
if (!tr.scratchImage[client])
|
if (!tr.scratchImage[client])
|
||||||
|
@ -746,7 +747,18 @@ void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int
|
||||||
if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
|
if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
|
||||||
tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
|
tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
|
||||||
tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
|
tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
|
||||||
|
|
||||||
|
if ( qglesMajorVersion >= 1 ) {
|
||||||
|
buffer = ri.Hunk_AllocateTempMemory( 3 * cols * rows );
|
||||||
|
|
||||||
|
R_ConvertTextureFormat( data, cols, rows, GL_RGB, GL_UNSIGNED_BYTE, buffer );
|
||||||
|
qglTextureImage2DEXT(texture, GL_TEXTURE_2D, 0, GL_RGB, cols, rows, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
|
||||||
|
ri.Hunk_FreeTempMemory( buffer );
|
||||||
|
} else {
|
||||||
qglTextureImage2DEXT(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
qglTextureImage2DEXT(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
}
|
||||||
|
|
||||||
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||||
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -755,10 +767,19 @@ void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int
|
||||||
if (dirty) {
|
if (dirty) {
|
||||||
// otherwise, just subimage upload it so that drivers can tell we are going to be changing
|
// otherwise, just subimage upload it so that drivers can tell we are going to be changing
|
||||||
// it and don't try and do a texture compression
|
// it and don't try and do a texture compression
|
||||||
|
if ( qglesMajorVersion >= 1 ) {
|
||||||
|
buffer = ri.Hunk_AllocateTempMemory( 3 * cols * rows );
|
||||||
|
|
||||||
|
R_ConvertTextureFormat( data, cols, rows, GL_RGB, GL_UNSIGNED_BYTE, buffer );
|
||||||
|
qglTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGB, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
|
||||||
|
ri.Hunk_FreeTempMemory( buffer );
|
||||||
|
} else {
|
||||||
qglTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
qglTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1140,14 +1161,14 @@ const void *RB_DrawSurfs( const void *data ) {
|
||||||
if (glRefConfig.occlusionQuery)
|
if (glRefConfig.occlusionQuery)
|
||||||
{
|
{
|
||||||
tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
|
tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
|
||||||
qglBeginQuery(GL_SAMPLES_PASSED, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
|
qglBeginQuery(glRefConfig.occlusionQueryTarget, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
RB_DrawSun(0.3, tr.sunFlareShader);
|
RB_DrawSun(0.3, tr.sunFlareShader);
|
||||||
|
|
||||||
if (glRefConfig.occlusionQuery)
|
if (glRefConfig.occlusionQuery)
|
||||||
{
|
{
|
||||||
qglEndQuery(GL_SAMPLES_PASSED);
|
qglEndQuery(glRefConfig.occlusionQueryTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
FBO_Bind(oldFbo);
|
FBO_Bind(oldFbo);
|
||||||
|
|
|
@ -276,7 +276,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) {
|
||||||
tr.deluxemaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low );
|
tr.deluxemaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low );
|
||||||
|
|
||||||
textureInternalFormat = GL_RGBA8;
|
textureInternalFormat = GL_RGBA8;
|
||||||
if (r_hdr->integer)
|
if (r_hdr->integer && !qglesMajorVersion)
|
||||||
{
|
{
|
||||||
// Check for the first hdr lightmap, if it exists, use GL_RGBA16 for textures.
|
// Check for the first hdr lightmap, if it exists, use GL_RGBA16 for textures.
|
||||||
char filename[MAX_QPATH];
|
char filename[MAX_QPATH];
|
||||||
|
|
|
@ -348,7 +348,13 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
||||||
//
|
//
|
||||||
if ( r_measureOverdraw->integer )
|
if ( r_measureOverdraw->integer )
|
||||||
{
|
{
|
||||||
if ( glConfig.stencilBits < 4 )
|
if ( qglesMajorVersion >= 1 && !glRefConfig.readStencil )
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_WARNING, "OpenGL ES needs GL_NV_read_stencil to read stencil bits to measure overdraw\n" );
|
||||||
|
ri.Cvar_Set( "r_measureOverdraw", "0" );
|
||||||
|
r_measureOverdraw->modified = qfalse;
|
||||||
|
}
|
||||||
|
else if ( glConfig.stencilBits < 4 )
|
||||||
{
|
{
|
||||||
ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
|
ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
|
||||||
ri.Cvar_Set( "r_measureOverdraw", "0" );
|
ri.Cvar_Set( "r_measureOverdraw", "0" );
|
||||||
|
@ -426,6 +432,13 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (qglesMajorVersion >= 1 && r_anaglyphMode->integer)
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_WARNING, "OpenGL ES does not support drawing to separate buffer for anaglyph mode\n" );
|
||||||
|
ri.Cvar_Set( "r_anaglyphMode", "0" );
|
||||||
|
r_anaglyphMode->modified = qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
if(r_anaglyphMode->integer)
|
if(r_anaglyphMode->integer)
|
||||||
{
|
{
|
||||||
if(r_anaglyphMode->modified)
|
if(r_anaglyphMode->modified)
|
||||||
|
|
|
@ -45,6 +45,17 @@ void GLimp_InitExtraExtensions(void)
|
||||||
if (strstr((char *)qglGetString(GL_RENDERER), "Intel"))
|
if (strstr((char *)qglGetString(GL_RENDERER), "Intel"))
|
||||||
glRefConfig.intelGraphics = qtrue;
|
glRefConfig.intelGraphics = qtrue;
|
||||||
|
|
||||||
|
if (qglesMajorVersion)
|
||||||
|
{
|
||||||
|
glRefConfig.vaoCacheGlIndexType = GL_UNSIGNED_SHORT;
|
||||||
|
glRefConfig.vaoCacheGlIndexSize = sizeof(unsigned short);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glRefConfig.vaoCacheGlIndexType = GL_UNSIGNED_INT;
|
||||||
|
glRefConfig.vaoCacheGlIndexSize = sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
// set DSA fallbacks
|
// set DSA fallbacks
|
||||||
#define GLE(ret, name, ...) qgl##name = GLDSA_##name;
|
#define GLE(ret, name, ...) qgl##name = GLDSA_##name;
|
||||||
QGL_EXT_direct_state_access_PROCS;
|
QGL_EXT_direct_state_access_PROCS;
|
||||||
|
@ -53,8 +64,96 @@ void GLimp_InitExtraExtensions(void)
|
||||||
// GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a
|
// GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a
|
||||||
#define GLE(ret, name, ...) qgl##name = (name##proc *) SDL_GL_GetProcAddress("gl" #name);
|
#define GLE(ret, name, ...) qgl##name = (name##proc *) SDL_GL_GetProcAddress("gl" #name);
|
||||||
|
|
||||||
|
//
|
||||||
|
// OpenGL ES extensions
|
||||||
|
//
|
||||||
|
if (qglesMajorVersion)
|
||||||
|
{
|
||||||
|
if (!r_allowExtensions->integer)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
extension = "GL_EXT_occlusion_query_boolean";
|
||||||
|
if (SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.occlusionQuery = qtrue;
|
||||||
|
glRefConfig.occlusionQueryTarget = GL_ANY_SAMPLES_PASSED;
|
||||||
|
|
||||||
|
QGL_ARB_occlusion_query_PROCS;
|
||||||
|
|
||||||
|
ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_NV_read_depth
|
||||||
|
extension = "GL_NV_read_depth";
|
||||||
|
if (SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.readDepth = qtrue;
|
||||||
|
ri.Printf(PRINT_ALL, result[glRefConfig.readDepth], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_NV_read_stencil
|
||||||
|
extension = "GL_NV_read_stencil";
|
||||||
|
if (SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.readStencil = qtrue;
|
||||||
|
ri.Printf(PRINT_ALL, result[glRefConfig.readStencil], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_EXT_shadow_samplers
|
||||||
|
extension = "GL_EXT_shadow_samplers";
|
||||||
|
if (qglesMajorVersion >= 3 || SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.shadowSamplers = qtrue;
|
||||||
|
ri.Printf(PRINT_ALL, result[glRefConfig.shadowSamplers], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_OES_standard_derivatives
|
||||||
|
extension = "GL_OES_standard_derivatives";
|
||||||
|
if (qglesMajorVersion >= 3 || SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.standardDerivatives = qtrue;
|
||||||
|
ri.Printf(PRINT_ALL, result[glRefConfig.standardDerivatives], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_OES_element_index_uint
|
||||||
|
extension = "GL_OES_element_index_uint";
|
||||||
|
if (SDL_GL_ExtensionSupported(extension))
|
||||||
|
{
|
||||||
|
glRefConfig.vaoCacheGlIndexType = GL_UNSIGNED_INT;
|
||||||
|
glRefConfig.vaoCacheGlIndexSize = sizeof(unsigned int);
|
||||||
|
ri.Printf(PRINT_ALL, result[1], extension);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// OpenGL 1.5 - GL_ARB_occlusion_query
|
// OpenGL 1.5 - GL_ARB_occlusion_query
|
||||||
glRefConfig.occlusionQuery = qtrue;
|
glRefConfig.occlusionQuery = qtrue;
|
||||||
|
glRefConfig.occlusionQueryTarget = GL_SAMPLES_PASSED;
|
||||||
QGL_ARB_occlusion_query_PROCS;
|
QGL_ARB_occlusion_query_PROCS;
|
||||||
|
|
||||||
// OpenGL 3.0 - GL_ARB_framebuffer_object
|
// OpenGL 3.0 - GL_ARB_framebuffer_object
|
||||||
|
@ -146,18 +245,6 @@ void GLimp_InitExtraExtensions(void)
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine GLSL version
|
|
||||||
if (1)
|
|
||||||
{
|
|
||||||
char version[256];
|
|
||||||
|
|
||||||
Q_strncpyz(version, (char *)qglGetString(GL_SHADING_LANGUAGE_VERSION), sizeof(version));
|
|
||||||
|
|
||||||
sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
|
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
glRefConfig.memInfo = MI_NONE;
|
glRefConfig.memInfo = MI_NONE;
|
||||||
|
|
||||||
// GL_NVX_gpu_memory_info
|
// GL_NVX_gpu_memory_info
|
||||||
|
@ -249,5 +336,26 @@ void GLimp_InitExtraExtensions(void)
|
||||||
ri.Printf(PRINT_ALL, result[2], extension);
|
ri.Printf(PRINT_ALL, result[2], extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
// Determine GLSL version
|
||||||
|
if (1)
|
||||||
|
{
|
||||||
|
char version[256], *version_p;
|
||||||
|
|
||||||
|
Q_strncpyz(version, (char *)qglGetString(GL_SHADING_LANGUAGE_VERSION), sizeof(version));
|
||||||
|
|
||||||
|
// Skip leading text such as "OpenGL ES GLSL ES "
|
||||||
|
version_p = version;
|
||||||
|
while ( *version_p && !isdigit( *version_p ) )
|
||||||
|
{
|
||||||
|
version_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(version_p, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
|
||||||
|
|
||||||
|
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
|
||||||
|
}
|
||||||
|
|
||||||
#undef GLE
|
#undef GLE
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,6 +478,14 @@ void RB_RenderFlares (void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( r_flares->modified ) {
|
||||||
|
if ( qglesMajorVersion >= 1 && !glRefConfig.readDepth ) {
|
||||||
|
ri.Printf( PRINT_WARNING, "OpenGL ES needs GL_NV_read_depth to read depth to determine if flares are visible\n" );
|
||||||
|
ri.Cvar_Set( "r_flares", "0" );
|
||||||
|
}
|
||||||
|
r_flares->modified = qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
if(r_flareCoeff->modified)
|
if(r_flareCoeff->modified)
|
||||||
{
|
{
|
||||||
R_SetFlareCoeff();
|
R_SetFlareCoeff();
|
||||||
|
|
|
@ -249,11 +249,25 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *
|
||||||
// HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
|
// HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
|
||||||
if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30))
|
if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30))
|
||||||
{
|
{
|
||||||
if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 50))
|
if (qglesMajorVersion >= 3 && glRefConfig.glslMajorVersion >= 3)
|
||||||
|
Q_strcat(dest, size, "#version 300 es\n");
|
||||||
|
else if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 50))
|
||||||
Q_strcat(dest, size, "#version 150\n");
|
Q_strcat(dest, size, "#version 150\n");
|
||||||
else
|
else
|
||||||
Q_strcat(dest, size, "#version 130\n");
|
Q_strcat(dest, size, "#version 130\n");
|
||||||
|
|
||||||
|
// `extra' may contain #extension which must be directly after #version
|
||||||
|
if (extra)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qglesMajorVersion >= 2)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, "precision mediump float;\n");
|
||||||
|
Q_strcat(dest, size, "precision mediump sampler2DShadow;\n");
|
||||||
|
}
|
||||||
|
|
||||||
if(shaderType == GL_VERTEX_SHADER)
|
if(shaderType == GL_VERTEX_SHADER)
|
||||||
{
|
{
|
||||||
Q_strcat(dest, size, "#define attribute in\n");
|
Q_strcat(dest, size, "#define attribute in\n");
|
||||||
|
@ -271,10 +285,36 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (qglesMajorVersion >= 2)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, "#version 100\n");
|
||||||
|
|
||||||
|
if (extra)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_strcat(dest, size, "precision mediump float;\n");
|
||||||
|
|
||||||
|
if (glRefConfig.shadowSamplers)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, "precision mediump sampler2DShadow;\n");
|
||||||
|
Q_strcat(dest, size, "#define shadow2D(a,b) shadow2DEXT(a,b)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Q_strcat(dest, size, "#version 120\n");
|
Q_strcat(dest, size, "#version 120\n");
|
||||||
|
|
||||||
|
if (extra)
|
||||||
|
{
|
||||||
|
Q_strcat(dest, size, extra);
|
||||||
|
}
|
||||||
|
|
||||||
Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r\n");
|
Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HACK: add some macros to avoid extra uniforms and save speed and code maintenance
|
// HACK: add some macros to avoid extra uniforms and save speed and code maintenance
|
||||||
//Q_strcat(dest, size,
|
//Q_strcat(dest, size,
|
||||||
|
@ -361,11 +401,6 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *
|
||||||
Q_strcat(dest, size, va("#define ROUGHNESS_MIPS float(%d)\n", numRoughnessMips));
|
Q_strcat(dest, size, va("#define ROUGHNESS_MIPS float(%d)\n", numRoughnessMips));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extra)
|
|
||||||
{
|
|
||||||
Q_strcat(dest, size, extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line
|
// OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line
|
||||||
// so we have to reset the line counting
|
// so we have to reset the line counting
|
||||||
Q_strcat(dest, size, "#line 0\n");
|
Q_strcat(dest, size, "#line 0\n");
|
||||||
|
@ -933,6 +968,15 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
startTime = ri.Milliseconds();
|
startTime = ri.Milliseconds();
|
||||||
|
|
||||||
|
// OpenGL ES may not have enough attributes to fit ones used for vertex animation
|
||||||
|
if ( glRefConfig.maxVertexAttribs > ATTR_INDEX_NORMAL2 ) {
|
||||||
|
ri.Printf(PRINT_ALL, "Using GPU vertex animation\n");
|
||||||
|
glRefConfig.gpuVertexAnimation = qtrue;
|
||||||
|
} else {
|
||||||
|
ri.Printf(PRINT_ALL, "Using CPU vertex animation\n");
|
||||||
|
glRefConfig.gpuVertexAnimation = qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < GENERICDEF_COUNT; i++)
|
for (i = 0; i < GENERICDEF_COUNT; i++)
|
||||||
{
|
{
|
||||||
if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION))
|
if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION))
|
||||||
|
@ -955,6 +999,9 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
if (i & GENERICDEF_USE_VERTEX_ANIMATION)
|
if (i & GENERICDEF_USE_VERTEX_ANIMATION)
|
||||||
{
|
{
|
||||||
|
if (!glRefConfig.gpuVertexAnimation)
|
||||||
|
continue;
|
||||||
|
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
||||||
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
}
|
}
|
||||||
|
@ -1006,6 +1053,9 @@ void GLSL_InitGPUShaders(void)
|
||||||
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION))
|
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && !glRefConfig.gpuVertexAnimation)
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1186,7 +1236,11 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION)
|
if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION)
|
||||||
{
|
{
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
|
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
|
||||||
|
|
||||||
|
if (glRefConfig.gpuVertexAnimation)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
||||||
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
|
|
||||||
if (r_normalMapping->integer)
|
if (r_normalMapping->integer)
|
||||||
|
@ -1194,6 +1248,7 @@ void GLSL_InitGPUShaders(void)
|
||||||
attribs |= ATTR_TANGENT2;
|
attribs |= ATTR_TANGENT2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION)
|
else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION)
|
||||||
{
|
{
|
||||||
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
|
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
|
||||||
|
@ -1226,6 +1281,9 @@ void GLSL_InitGPUShaders(void)
|
||||||
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION))
|
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && !glRefConfig.gpuVertexAnimation)
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1350,9 +1408,18 @@ void GLSL_InitGPUShaders(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GLSL 1.10+ or GL_EXT_shadow_samplers extension are required for sampler2DShadow type
|
||||||
|
if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 10)
|
||||||
|
|| glRefConfig.shadowSamplers)
|
||||||
|
{
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
|
if (qglesMajorVersion < 3 && glRefConfig.shadowSamplers)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#extension GL_EXT_shadow_samplers : enable\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (r_shadowFilter->integer >= 1)
|
if (r_shadowFilter->integer >= 1)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n");
|
Q_strcat(extradefines, 1024, "#define USE_SHADOW_FILTER\n");
|
||||||
|
|
||||||
|
@ -1365,7 +1432,6 @@ void GLSL_InitGPUShaders(void)
|
||||||
Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %f\n", r_shadowMapSize->value));
|
Q_strcat(extradefines, 1024, va("#define r_shadowMapSize %f\n", r_shadowMapSize->value));
|
||||||
Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value));
|
Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value));
|
||||||
|
|
||||||
|
|
||||||
if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp))
|
if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp))
|
||||||
{
|
{
|
||||||
ri.Error(ERR_FATAL, "Could not load shadowmask shader!");
|
ri.Error(ERR_FATAL, "Could not load shadowmask shader!");
|
||||||
|
@ -1382,11 +1448,21 @@ void GLSL_InitGPUShaders(void)
|
||||||
GLSL_FinishGPUShader(&tr.shadowmaskShader);
|
GLSL_FinishGPUShader(&tr.shadowmaskShader);
|
||||||
|
|
||||||
numEtcShaders++;
|
numEtcShaders++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GLSL 1.10+ or GL_OES_standard_derivatives extension are required for dFdx() and dFdy() GLSL functions
|
||||||
|
if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 10)
|
||||||
|
|| glRefConfig.standardDerivatives)
|
||||||
|
{
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
|
if (qglesMajorVersion < 3 && glRefConfig.standardDerivatives)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#extension GL_OES_standard_derivatives : enable\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp))
|
if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp))
|
||||||
{
|
{
|
||||||
ri.Error(ERR_FATAL, "Could not load ssao shader!");
|
ri.Error(ERR_FATAL, "Could not load ssao shader!");
|
||||||
|
@ -1406,6 +1482,11 @@ void GLSL_InitGPUShaders(void)
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
|
if (qglesMajorVersion < 3 && glRefConfig.standardDerivatives)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#extension GL_OES_standard_derivatives : enable\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (i & 1)
|
if (i & 1)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n");
|
Q_strcat(extradefines, 1024, "#define USE_VERTICAL_BLUR\n");
|
||||||
else
|
else
|
||||||
|
@ -1429,6 +1510,7 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
numEtcShaders++;
|
numEtcShaders++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD;
|
||||||
|
@ -1462,7 +1544,7 @@ void GLSL_ShutdownGPUShaders(void)
|
||||||
|
|
||||||
ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n");
|
ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n");
|
||||||
|
|
||||||
for (i = 0; i < ATTR_INDEX_COUNT; i++)
|
for (i = 0; i < ATTR_INDEX_COUNT && i < glRefConfig.maxVertexAttribs; i++)
|
||||||
qglDisableVertexAttribArray(i);
|
qglDisableVertexAttribArray(i);
|
||||||
|
|
||||||
GL_BindNullProgram();
|
GL_BindNullProgram();
|
||||||
|
|
|
@ -1455,6 +1455,106 @@ byte mipBlendColors[16][4] = {
|
||||||
{0,0,255,128},
|
{0,0,255,128},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
R_ConvertTextureFormat
|
||||||
|
|
||||||
|
Convert RGBA unsigned byte to specified format and type
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
#define ROW_PADDING( width, bpp, alignment ) PAD( (width) * (bpp), (alignment) ) - (width) * (bpp)
|
||||||
|
void R_ConvertTextureFormat( const byte *in, int width, int height, GLenum format, GLenum type, byte *out )
|
||||||
|
{
|
||||||
|
int x, y, rowPadding;
|
||||||
|
int unpackAlign = 4; // matches GL_UNPACK_ALIGNMENT default
|
||||||
|
|
||||||
|
if ( format == GL_RGB && type == GL_UNSIGNED_BYTE )
|
||||||
|
{
|
||||||
|
rowPadding = ROW_PADDING( width, 3, unpackAlign );
|
||||||
|
|
||||||
|
for ( y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
for ( x = 0; x < width; x++ )
|
||||||
|
{
|
||||||
|
*out++ = *in++;
|
||||||
|
*out++ = *in++;
|
||||||
|
*out++ = *in++;
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
|
||||||
|
out += rowPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( format == GL_LUMINANCE && type == GL_UNSIGNED_BYTE )
|
||||||
|
{
|
||||||
|
rowPadding = ROW_PADDING( width, 1, unpackAlign );
|
||||||
|
|
||||||
|
for ( y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
for ( x = 0; x < width; x++ )
|
||||||
|
{
|
||||||
|
*out++ = *in++; // red
|
||||||
|
in += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
out += rowPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( format == GL_LUMINANCE_ALPHA && type == GL_UNSIGNED_BYTE )
|
||||||
|
{
|
||||||
|
rowPadding = ROW_PADDING( width, 2, unpackAlign );
|
||||||
|
|
||||||
|
for ( y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
for ( x = 0; x < width; x++ )
|
||||||
|
{
|
||||||
|
*out++ = *in++; // red
|
||||||
|
in += 2;
|
||||||
|
*out++ = *in++; // alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
out += rowPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 )
|
||||||
|
{
|
||||||
|
rowPadding = ROW_PADDING( width, 2, unpackAlign );
|
||||||
|
|
||||||
|
for ( y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
for ( x = 0; x < width; x++, in += 4, out += 2 )
|
||||||
|
{
|
||||||
|
*((unsigned short*)out) = ( (unsigned short)( in[0] >> 3 ) << 11 )
|
||||||
|
| ( (unsigned short)( in[1] >> 2 ) << 5 )
|
||||||
|
| ( (unsigned short)( in[2] >> 3 ) << 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
out += rowPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4 )
|
||||||
|
{
|
||||||
|
rowPadding = ROW_PADDING( width, 2, unpackAlign );
|
||||||
|
|
||||||
|
for ( y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
for ( x = 0; x < width; x++, in += 4, out += 2 )
|
||||||
|
{
|
||||||
|
*((unsigned short*)out) = ( (unsigned short)( in[0] >> 4 ) << 12 )
|
||||||
|
| ( (unsigned short)( in[1] >> 4 ) << 8 )
|
||||||
|
| ( (unsigned short)( in[2] >> 4 ) << 4 )
|
||||||
|
| ( (unsigned short)( in[3] >> 4 ) << 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
out += rowPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Error( ERR_DROP, "Unable to convert RGBA image to OpenGL format 0x%X and type 0x%X", format, type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void RawImage_SwizzleRA( byte *data, int width, int height )
|
static void RawImage_SwizzleRA( byte *data, int width, int height )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1944,18 +2044,20 @@ static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
|
static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, GLenum dataFormat, GLenum dataType, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
|
||||||
{
|
{
|
||||||
GLenum dataFormat, dataType;
|
|
||||||
qboolean rgtc = internalFormat == GL_COMPRESSED_RG_RGTC2;
|
qboolean rgtc = internalFormat == GL_COMPRESSED_RG_RGTC2;
|
||||||
qboolean rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT;
|
qboolean rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT;
|
||||||
qboolean rgba = rgba8 || picFormat == GL_RGBA16;
|
qboolean rgba = rgba8 || picFormat == GL_RGBA16;
|
||||||
qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
|
qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
|
||||||
int size, miplevel;
|
int size, miplevel;
|
||||||
qboolean lastMip = qfalse;
|
qboolean lastMip = qfalse;
|
||||||
|
byte *formatBuffer = NULL;
|
||||||
|
|
||||||
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
if (qglesMajorVersion && rgba8 && (dataFormat != GL_RGBA || dataType != GL_UNSIGNED_BYTE))
|
||||||
dataType = picFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
|
{
|
||||||
|
formatBuffer = ri.Hunk_AllocateTempMemory(4 * width * height);
|
||||||
|
}
|
||||||
|
|
||||||
miplevel = 0;
|
miplevel = 0;
|
||||||
do
|
do
|
||||||
|
@ -1974,6 +2076,11 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
|
||||||
|
|
||||||
if (rgba8 && rgtc)
|
if (rgba8 && rgtc)
|
||||||
RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data);
|
RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data);
|
||||||
|
else if (formatBuffer)
|
||||||
|
{
|
||||||
|
R_ConvertTextureFormat(data, width, height, dataFormat, dataType, formatBuffer);
|
||||||
|
qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, formatBuffer);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
|
qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
|
||||||
}
|
}
|
||||||
|
@ -2007,6 +2114,9 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!lastMip);
|
while (!lastMip);
|
||||||
|
|
||||||
|
if (formatBuffer != NULL)
|
||||||
|
ri.Hunk_FreeTempMemory(formatBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2016,7 +2126,7 @@ Upload32
|
||||||
|
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image, qboolean scaled)
|
static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, GLenum dataFormat, GLenum dataType, int numMips, image_t *image, qboolean scaled)
|
||||||
{
|
{
|
||||||
int i, c;
|
int i, c;
|
||||||
byte *scan;
|
byte *scan;
|
||||||
|
@ -2071,7 +2181,7 @@ static void Upload32(byte *data, int x, int y, int width, int height, GLenum pic
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
int w2 = width, h2 = height;
|
int w2 = width, h2 = height;
|
||||||
RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, picFormat, numMips, internalFormat, type, flags, qfalse);
|
RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, picFormat, dataFormat, dataType, numMips, internalFormat, type, flags, qfalse);
|
||||||
for (c = numMips; c; c--)
|
for (c = numMips; c; c--)
|
||||||
{
|
{
|
||||||
data += CalculateMipSize(w2, h2, picFormat);
|
data += CalculateMipSize(w2, h2, picFormat);
|
||||||
|
@ -2082,7 +2192,7 @@ static void Upload32(byte *data, int x, int y, int width, int height, GLenum pic
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, numMips, internalFormat, type, flags, qfalse);
|
RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, dataFormat, dataType, numMips, internalFormat, type, flags, qfalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_CheckErrors();
|
GL_CheckErrors();
|
||||||
|
@ -2108,7 +2218,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
qboolean picmip = !!(flags & IMGFLAG_PICMIP);
|
qboolean picmip = !!(flags & IMGFLAG_PICMIP);
|
||||||
qboolean lastMip;
|
qboolean lastMip;
|
||||||
GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
|
||||||
GLenum dataFormat;
|
GLenum dataFormat, dataType;
|
||||||
|
|
||||||
if (strlen(name) >= MAX_QPATH ) {
|
if (strlen(name) >= MAX_QPATH ) {
|
||||||
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
|
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name);
|
||||||
|
@ -2140,6 +2250,53 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
if (!internalFormat)
|
if (!internalFormat)
|
||||||
internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
|
internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
|
||||||
|
|
||||||
|
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
||||||
|
dataType = picFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
// Convert image data format for OpenGL ES, data is converted for each mip level
|
||||||
|
if (qglesMajorVersion)
|
||||||
|
{
|
||||||
|
switch (internalFormat)
|
||||||
|
{
|
||||||
|
case GL_LUMINANCE:
|
||||||
|
case GL_LUMINANCE8:
|
||||||
|
internalFormat = GL_LUMINANCE;
|
||||||
|
dataFormat = GL_LUMINANCE;
|
||||||
|
dataType = GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
|
case GL_LUMINANCE_ALPHA:
|
||||||
|
case GL_LUMINANCE8_ALPHA8:
|
||||||
|
internalFormat = GL_LUMINANCE_ALPHA;
|
||||||
|
dataFormat = GL_LUMINANCE_ALPHA;
|
||||||
|
dataType = GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
|
case GL_RGB:
|
||||||
|
case GL_RGB8:
|
||||||
|
internalFormat = GL_RGB;
|
||||||
|
dataFormat = GL_RGB;
|
||||||
|
dataType = GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
|
case GL_RGB5:
|
||||||
|
internalFormat = GL_RGB;
|
||||||
|
dataFormat = GL_RGB;
|
||||||
|
dataType = GL_UNSIGNED_SHORT_5_6_5;
|
||||||
|
break;
|
||||||
|
case GL_RGBA:
|
||||||
|
case GL_RGBA8:
|
||||||
|
internalFormat = GL_RGBA;
|
||||||
|
dataFormat = GL_RGBA;
|
||||||
|
dataType = GL_UNSIGNED_BYTE;
|
||||||
|
break;
|
||||||
|
case GL_RGBA4:
|
||||||
|
internalFormat = GL_RGBA;
|
||||||
|
dataFormat = GL_RGBA;
|
||||||
|
dataType = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ri.Error( ERR_DROP, "Missing OpenGL ES support for image '%s' with internal format 0x%X\n", name, internalFormat );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
image->internalFormat = internalFormat;
|
image->internalFormat = internalFormat;
|
||||||
|
|
||||||
// Possibly scale image before uploading.
|
// Possibly scale image before uploading.
|
||||||
|
@ -2164,7 +2321,6 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
image->uploadHeight = height;
|
image->uploadHeight = height;
|
||||||
|
|
||||||
// Allocate texture storage so we don't have to worry about it later.
|
// Allocate texture storage so we don't have to worry about it later.
|
||||||
dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
|
|
||||||
mipWidth = width;
|
mipWidth = width;
|
||||||
mipHeight = height;
|
mipHeight = height;
|
||||||
miplevel = 0;
|
miplevel = 0;
|
||||||
|
@ -2176,11 +2332,11 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
|
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, dataType, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
|
qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, dataType, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mipWidth = MAX(1, mipWidth >> 1);
|
mipWidth = MAX(1, mipWidth >> 1);
|
||||||
|
@ -2191,7 +2347,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
|
||||||
|
|
||||||
// Upload data.
|
// Upload data.
|
||||||
if (pic)
|
if (pic)
|
||||||
Upload32(pic, 0, 0, width, height, picFormat, numMips, image, scaled);
|
Upload32(pic, 0, 0, width, height, picFormat, dataFormat, dataType, numMips, image, scaled);
|
||||||
|
|
||||||
if (resampledBuffer != NULL)
|
if (resampledBuffer != NULL)
|
||||||
ri.Hunk_FreeTempMemory(resampledBuffer);
|
ri.Hunk_FreeTempMemory(resampledBuffer);
|
||||||
|
@ -2252,7 +2408,13 @@ image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgTy
|
||||||
|
|
||||||
void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat )
|
void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat )
|
||||||
{
|
{
|
||||||
Upload32(pic, x, y, width, height, picFormat, 0, image, qfalse);
|
GLenum dataFormat, dataType;
|
||||||
|
|
||||||
|
// TODO: This is fine for lightmaps but (unused) general RGBA images need to store dataFormat / dataType in image_t for OpenGL ES?
|
||||||
|
dataFormat = PixelDataFormatFromInternalFormat(image->internalFormat);
|
||||||
|
dataType = picFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
Upload32(pic, x, y, width, height, picFormat, dataFormat, dataType, 0, image, qfalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
|
|
|
@ -279,6 +279,9 @@ static void InitOpenGL( void )
|
||||||
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp );
|
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp );
|
||||||
glConfig.numTextureUnits = temp;
|
glConfig.numTextureUnits = temp;
|
||||||
|
|
||||||
|
qglGetIntegerv( GL_MAX_VERTEX_ATTRIBS, &temp );
|
||||||
|
glRefConfig.maxVertexAttribs = temp;
|
||||||
|
|
||||||
// reserve 160 components for other uniforms
|
// reserve 160 components for other uniforms
|
||||||
qglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS, &temp );
|
qglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS, &temp );
|
||||||
glRefConfig.glslMaxAnimatedBones = Com_Clamp( 0, IQM_MAX_JOINTS, ( temp - 160 ) / 16 );
|
glRefConfig.glslMaxAnimatedBones = Com_Clamp( 0, IQM_MAX_JOINTS, ( temp - 160 ) / 16 );
|
||||||
|
@ -451,20 +454,42 @@ Return value must be freed with ri.Hunk_FreeTempMemory()
|
||||||
byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen)
|
byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen)
|
||||||
{
|
{
|
||||||
byte *buffer, *bufstart;
|
byte *buffer, *bufstart;
|
||||||
int padwidth, linelen;
|
int padwidth, linelen, bytesPerPixel;
|
||||||
GLint packAlign;
|
int yin, xin, xout;
|
||||||
|
GLint packAlign, format;
|
||||||
|
|
||||||
|
// OpenGL ES is only required to support reading GL_RGBA
|
||||||
|
if (qglesMajorVersion >= 1) {
|
||||||
|
format = GL_RGBA;
|
||||||
|
bytesPerPixel = 4;
|
||||||
|
} else {
|
||||||
|
format = GL_RGB;
|
||||||
|
bytesPerPixel = 3;
|
||||||
|
}
|
||||||
|
|
||||||
qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
|
qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
|
||||||
|
|
||||||
linelen = width * 3;
|
linelen = width * bytesPerPixel;
|
||||||
padwidth = PAD(linelen, packAlign);
|
padwidth = PAD(linelen, packAlign);
|
||||||
|
|
||||||
// Allocate a few more bytes so that we can choose an alignment we like
|
// Allocate a few more bytes so that we can choose an alignment we like
|
||||||
buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
|
buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
|
||||||
|
|
||||||
bufstart = PADP((intptr_t) buffer + *offset, packAlign);
|
bufstart = PADP((intptr_t) buffer + *offset, packAlign);
|
||||||
|
qglReadPixels(x, y, width, height, format, GL_UNSIGNED_BYTE, bufstart);
|
||||||
|
|
||||||
qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
|
linelen = width * 3;
|
||||||
|
|
||||||
|
// Convert RGBA to RGB, in place, line by line
|
||||||
|
if (format == GL_RGBA) {
|
||||||
|
for (yin = 0; yin < height; yin++) {
|
||||||
|
for (xin = 0, xout = 0; xout < linelen; xin += 4, xout += 3) {
|
||||||
|
bufstart[yin*padwidth + xout + 0] = bufstart[yin*padwidth + xin + 0];
|
||||||
|
bufstart[yin*padwidth + xout + 1] = bufstart[yin*padwidth + xin + 1];
|
||||||
|
bufstart[yin*padwidth + xout + 2] = bufstart[yin*padwidth + xin + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*offset = bufstart - buffer;
|
*offset = bufstart - buffer;
|
||||||
*padlen = padwidth - linelen;
|
*padlen = padwidth - linelen;
|
||||||
|
@ -877,9 +902,10 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
||||||
{
|
{
|
||||||
const videoFrameCommand_t *cmd;
|
const videoFrameCommand_t *cmd;
|
||||||
byte *cBuf;
|
byte *cBuf;
|
||||||
size_t memcount, linelen;
|
size_t memcount, bytesPerPixel, linelen, avilinelen;
|
||||||
int padwidth, avipadwidth, padlen, avipadlen;
|
int padwidth, avipadwidth, padlen, avipadlen;
|
||||||
GLint packAlign;
|
int yin, xin, xout;
|
||||||
|
GLint packAlign, format;
|
||||||
|
|
||||||
// finish any 2D drawing if needed
|
// finish any 2D drawing if needed
|
||||||
if(tess.numIndexes)
|
if(tess.numIndexes)
|
||||||
|
@ -887,20 +913,32 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
||||||
|
|
||||||
cmd = (const videoFrameCommand_t *)data;
|
cmd = (const videoFrameCommand_t *)data;
|
||||||
|
|
||||||
|
// OpenGL ES is only required to support reading GL_RGBA
|
||||||
|
if (qglesMajorVersion >= 1) {
|
||||||
|
format = GL_RGBA;
|
||||||
|
bytesPerPixel = 4;
|
||||||
|
} else {
|
||||||
|
format = GL_RGB;
|
||||||
|
bytesPerPixel = 3;
|
||||||
|
}
|
||||||
|
|
||||||
qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
|
qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
|
||||||
|
|
||||||
linelen = cmd->width * 3;
|
linelen = cmd->width * bytesPerPixel;
|
||||||
|
|
||||||
// Alignment stuff for glReadPixels
|
// Alignment stuff for glReadPixels
|
||||||
padwidth = PAD(linelen, packAlign);
|
padwidth = PAD(linelen, packAlign);
|
||||||
padlen = padwidth - linelen;
|
padlen = padwidth - linelen;
|
||||||
|
|
||||||
|
avilinelen = cmd->width * 3;
|
||||||
|
|
||||||
// AVI line padding
|
// AVI line padding
|
||||||
avipadwidth = PAD(linelen, AVI_LINE_PADDING);
|
avipadwidth = PAD(avilinelen, AVI_LINE_PADDING);
|
||||||
avipadlen = avipadwidth - linelen;
|
avipadlen = avipadwidth - avilinelen;
|
||||||
|
|
||||||
cBuf = PADP(cmd->captureBuffer, packAlign);
|
cBuf = PADP(cmd->captureBuffer, packAlign);
|
||||||
|
|
||||||
qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
|
qglReadPixels(0, 0, cmd->width, cmd->height, format,
|
||||||
GL_UNSIGNED_BYTE, cBuf);
|
GL_UNSIGNED_BYTE, cBuf);
|
||||||
|
|
||||||
memcount = padwidth * cmd->height;
|
memcount = padwidth * cmd->height;
|
||||||
|
@ -911,7 +949,21 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
||||||
|
|
||||||
if(cmd->motionJpeg)
|
if(cmd->motionJpeg)
|
||||||
{
|
{
|
||||||
memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
|
// Convert RGBA to RGB, in place, line by line
|
||||||
|
if (format == GL_RGBA) {
|
||||||
|
linelen = cmd->width * 3;
|
||||||
|
padlen = padwidth - linelen;
|
||||||
|
|
||||||
|
for (yin = 0; yin < cmd->height; yin++) {
|
||||||
|
for (xin = 0, xout = 0; xout < linelen; xin += 4, xout += 3) {
|
||||||
|
cBuf[yin*padwidth + xout + 0] = cBuf[yin*padwidth + xin + 0];
|
||||||
|
cBuf[yin*padwidth + xout + 1] = cBuf[yin*padwidth + xin + 1];
|
||||||
|
cBuf[yin*padwidth + xout + 2] = cBuf[yin*padwidth + xin + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, avilinelen * cmd->height,
|
||||||
r_aviMotionJpegQuality->integer,
|
r_aviMotionJpegQuality->integer,
|
||||||
cmd->width, cmd->height, cBuf, padlen);
|
cmd->width, cmd->height, cBuf, padlen);
|
||||||
ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
|
ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
|
||||||
|
@ -934,7 +986,7 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
||||||
*destptr++ = srcptr[2];
|
*destptr++ = srcptr[2];
|
||||||
*destptr++ = srcptr[1];
|
*destptr++ = srcptr[1];
|
||||||
*destptr++ = srcptr[0];
|
*destptr++ = srcptr[0];
|
||||||
srcptr += 3;
|
srcptr += bytesPerPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Com_Memset(destptr, '\0', avipadlen);
|
Com_Memset(destptr, '\0', avipadlen);
|
||||||
|
|
|
@ -49,8 +49,10 @@ QGL_ARB_vertex_array_object_PROCS;
|
||||||
QGL_EXT_direct_state_access_PROCS;
|
QGL_EXT_direct_state_access_PROCS;
|
||||||
#undef GLE
|
#undef GLE
|
||||||
|
|
||||||
#define GL_INDEX_TYPE GL_UNSIGNED_INT
|
#define GL_INDEX_TYPE GL_UNSIGNED_SHORT
|
||||||
typedef unsigned int glIndex_t;
|
typedef unsigned short glIndex_t;
|
||||||
|
|
||||||
|
typedef unsigned int vaoCacheGlIndex_t;
|
||||||
|
|
||||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||||
|
|
||||||
|
@ -1406,6 +1408,7 @@ typedef struct {
|
||||||
qboolean intelGraphics;
|
qboolean intelGraphics;
|
||||||
|
|
||||||
qboolean occlusionQuery;
|
qboolean occlusionQuery;
|
||||||
|
GLenum occlusionQueryTarget;
|
||||||
|
|
||||||
int glslMajorVersion;
|
int glslMajorVersion;
|
||||||
int glslMinorVersion;
|
int glslMinorVersion;
|
||||||
|
@ -1429,6 +1432,18 @@ typedef struct {
|
||||||
|
|
||||||
qboolean vertexArrayObject;
|
qboolean vertexArrayObject;
|
||||||
qboolean directStateAccess;
|
qboolean directStateAccess;
|
||||||
|
|
||||||
|
int maxVertexAttribs;
|
||||||
|
qboolean gpuVertexAnimation;
|
||||||
|
|
||||||
|
GLenum vaoCacheGlIndexType; // GL_UNSIGNED_INT or GL_UNSIGNED_SHORT
|
||||||
|
size_t vaoCacheGlIndexSize; // must be <= sizeof( vaoCacheGlIndex_t )
|
||||||
|
|
||||||
|
// OpenGL ES extensions
|
||||||
|
qboolean readDepth;
|
||||||
|
qboolean readStencil;
|
||||||
|
qboolean shadowSamplers;
|
||||||
|
qboolean standardDerivatives;
|
||||||
} glRefConfig_t;
|
} glRefConfig_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2213,6 +2228,7 @@ void R_VaoList_f(void);
|
||||||
void RB_UpdateTessVao(unsigned int attribBits);
|
void RB_UpdateTessVao(unsigned int attribBits);
|
||||||
|
|
||||||
void VaoCache_Commit(void);
|
void VaoCache_Commit(void);
|
||||||
|
void VaoCache_DrawElements(int numIndexes, int firstIndex);
|
||||||
void VaoCache_Init(void);
|
void VaoCache_Init(void);
|
||||||
void VaoCache_BindVao(void);
|
void VaoCache_BindVao(void);
|
||||||
void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes);
|
void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes);
|
||||||
|
@ -2502,5 +2518,7 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
|
||||||
void RE_TakeVideoFrame( int width, int height,
|
void RE_TakeVideoFrame( int width, int height,
|
||||||
byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
|
byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
|
||||||
|
|
||||||
|
void R_ConvertTextureFormat( const byte *in, int width, int height, GLenum format, GLenum type, byte *out );
|
||||||
|
|
||||||
|
|
||||||
#endif //TR_LOCAL_H
|
#endif //TR_LOCAL_H
|
||||||
|
|
|
@ -282,9 +282,10 @@ R_AddMD3Surfaces
|
||||||
*/
|
*/
|
||||||
void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
||||||
int i;
|
int i;
|
||||||
mdvModel_t *model = NULL;
|
mdvModel_t *model;
|
||||||
mdvSurface_t *surface = NULL;
|
mdvSurface_t *surface;
|
||||||
shader_t *shader = NULL;
|
void *drawSurf;
|
||||||
|
shader_t *shader;
|
||||||
int cull;
|
int cull;
|
||||||
int lod;
|
int lod;
|
||||||
int fogNum;
|
int fogNum;
|
||||||
|
@ -382,6 +383,12 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
||||||
shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ];
|
shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( model->numVaoSurfaces > 0 ) {
|
||||||
|
drawSurf = &model->vaoSurfaces[i];
|
||||||
|
} else {
|
||||||
|
drawSurf = surface;
|
||||||
|
}
|
||||||
|
|
||||||
// we will add shadows even if the main object isn't visible in the view
|
// we will add shadows even if the main object isn't visible in the view
|
||||||
|
|
||||||
// stencil shadows can't do personal models unless I polyhedron clip
|
// stencil shadows can't do personal models unless I polyhedron clip
|
||||||
|
@ -390,7 +397,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
||||||
&& fogNum == 0
|
&& fogNum == 0
|
||||||
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
|
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
|
||||||
&& shader->sort == SS_OPAQUE ) {
|
&& shader->sort == SS_OPAQUE ) {
|
||||||
R_AddDrawSurf( (void *)&model->vaoSurfaces[i], tr.shadowShader, 0, qfalse, qfalse, 0 );
|
R_AddDrawSurf( drawSurf, tr.shadowShader, 0, qfalse, qfalse, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// projection shadows work fine with personal models
|
// projection shadows work fine with personal models
|
||||||
|
@ -398,12 +405,12 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
|
||||||
&& fogNum == 0
|
&& fogNum == 0
|
||||||
&& (ent->e.renderfx & RF_SHADOW_PLANE )
|
&& (ent->e.renderfx & RF_SHADOW_PLANE )
|
||||||
&& shader->sort == SS_OPAQUE ) {
|
&& shader->sort == SS_OPAQUE ) {
|
||||||
R_AddDrawSurf( (void *)&model->vaoSurfaces[i], tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
|
R_AddDrawSurf( drawSurf, tr.projectionShadowShader, 0, qfalse, qfalse, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't add third_person objects if not viewing through a portal
|
// don't add third_person objects if not viewing through a portal
|
||||||
if ( !personalModel ) {
|
if ( !personalModel ) {
|
||||||
R_AddDrawSurf((void *)&model->vaoSurfaces[i], shader, fogNum, qfalse, qfalse, cubemapIndex );
|
R_AddDrawSurf( drawSurf, shader, fogNum, qfalse, qfalse, cubemapIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
surface++;
|
surface++;
|
||||||
|
|
|
@ -664,6 +664,12 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize,
|
||||||
surf++;
|
surf++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mdvModel->numFrames > 1 && !glRefConfig.gpuVertexAnimation)
|
||||||
|
{
|
||||||
|
mdvModel->numVaoSurfaces = 0;
|
||||||
|
mdvModel->vaoSurfaces = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
srfVaoMdvMesh_t *vaoSurf;
|
srfVaoMdvMesh_t *vaoSurf;
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,8 @@ static qboolean RB_UpdateSunFlareVis(void)
|
||||||
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
|
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: On desktop OpenGL this is a sample count (glRefConfig.occlusionQueryTarget == GL_SAMPLES_PASSED)
|
||||||
|
// but on OpenGL ES this is a boolean (glRefConfig.occlusionQueryTarget == GL_ANY_SAMPLES_PASSED)
|
||||||
qglGetQueryObjectuiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT, &sampleCount);
|
qglGetQueryObjectuiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT, &sampleCount);
|
||||||
return sampleCount > 0;
|
return sampleCount > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,16 @@ R_DrawElements
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void R_DrawElements( int numIndexes, int firstIndex )
|
void R_DrawElements( int numIndexes, int firstIndex )
|
||||||
|
{
|
||||||
|
if (tess.useCacheVao)
|
||||||
|
{
|
||||||
|
VaoCache_DrawElements(numIndexes, firstIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
|
qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1720,6 +1727,8 @@ void RB_EndSurface( void ) {
|
||||||
tess.numIndexes = 0;
|
tess.numIndexes = 0;
|
||||||
tess.numVertexes = 0;
|
tess.numVertexes = 0;
|
||||||
tess.firstIndex = 0;
|
tess.firstIndex = 0;
|
||||||
|
tess.useCacheVao = qfalse;
|
||||||
|
tess.useInternalVao = qfalse;
|
||||||
|
|
||||||
GLimp_LogComment( "----------\n" );
|
GLimp_LogComment( "----------\n" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,7 +676,7 @@ static struct
|
||||||
srfVert_t vertexes[VAOCACHE_QUEUE_MAX_VERTEXES];
|
srfVert_t vertexes[VAOCACHE_QUEUE_MAX_VERTEXES];
|
||||||
int vertexCommitSize;
|
int vertexCommitSize;
|
||||||
|
|
||||||
glIndex_t indexes[VAOCACHE_QUEUE_MAX_INDEXES];
|
vaoCacheGlIndex_t indexes[VAOCACHE_QUEUE_MAX_INDEXES];
|
||||||
int indexCommitSize;
|
int indexCommitSize;
|
||||||
}
|
}
|
||||||
vcq;
|
vcq;
|
||||||
|
@ -687,18 +687,13 @@ vcq;
|
||||||
// srfVert_t is 60 bytes
|
// srfVert_t is 60 bytes
|
||||||
// assuming each vert is referenced 4 times, need 16 bytes (4 glIndex_t) per vert
|
// assuming each vert is referenced 4 times, need 16 bytes (4 glIndex_t) per vert
|
||||||
// -> need about 4/15ths the space for indexes as vertexes
|
// -> need about 4/15ths the space for indexes as vertexes
|
||||||
#if GL_INDEX_TYPE == GL_UNSIGNED_SHORT
|
|
||||||
#define VAOCACHE_VERTEX_BUFFER_SIZE (sizeof(srfVert_t) * USHRT_MAX)
|
|
||||||
#define VAOCACHE_INDEX_BUFFER_SIZE (sizeof(glIndex_t) * USHRT_MAX * 4)
|
|
||||||
#else // GL_UNSIGNED_INT
|
|
||||||
#define VAOCACHE_VERTEX_BUFFER_SIZE (16 * 1024 * 1024)
|
#define VAOCACHE_VERTEX_BUFFER_SIZE (16 * 1024 * 1024)
|
||||||
#define VAOCACHE_INDEX_BUFFER_SIZE (5 * 1024 * 1024)
|
#define VAOCACHE_INDEX_BUFFER_SIZE (5 * 1024 * 1024)
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct buffered_s
|
typedef struct buffered_s
|
||||||
{
|
{
|
||||||
void *data;
|
glIndex_t *indexes;
|
||||||
int size;
|
int numIndexes;
|
||||||
int bufferOffset;
|
int bufferOffset;
|
||||||
}
|
}
|
||||||
buffered_t;
|
buffered_t;
|
||||||
|
@ -736,7 +731,7 @@ void VaoCache_Commit(void)
|
||||||
buffered_t *indexSet2 = indexSet;
|
buffered_t *indexSet2 = indexSet;
|
||||||
for (surf = vcq.surfaces; surf < end; surf++, indexSet2++)
|
for (surf = vcq.surfaces; surf < end; surf++, indexSet2++)
|
||||||
{
|
{
|
||||||
if (surf->indexes != indexSet2->data || (surf->numIndexes * sizeof(glIndex_t)) != indexSet2->size)
|
if (surf->indexes != indexSet2->indexes || surf->numIndexes != indexSet2->numIndexes)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +745,7 @@ void VaoCache_Commit(void)
|
||||||
// If found, use it
|
// If found, use it
|
||||||
if (indexSet < vc.surfaceIndexSets + vc.numSurfaces)
|
if (indexSet < vc.surfaceIndexSets + vc.numSurfaces)
|
||||||
{
|
{
|
||||||
tess.firstIndex = indexSet->bufferOffset / sizeof(glIndex_t);
|
tess.firstIndex = indexSet->bufferOffset / glRefConfig.vaoCacheGlIndexSize;
|
||||||
//ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d as %d\n", tess.firstIndex, tess.numIndexes, (int)(batchLength - vc.batchLengths));
|
//ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d as %d\n", tess.firstIndex, tess.numIndexes, (int)(batchLength - vc.batchLengths));
|
||||||
//ri.Printf(PRINT_ALL, "vc.numSurfaces %d vc.numBatches %d\n", vc.numSurfaces, vc.numBatches);
|
//ri.Printf(PRINT_ALL, "vc.numSurfaces %d vc.numBatches %d\n", vc.numSurfaces, vc.numBatches);
|
||||||
}
|
}
|
||||||
|
@ -759,20 +754,21 @@ void VaoCache_Commit(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
srfVert_t *dstVertex = vcq.vertexes;
|
srfVert_t *dstVertex = vcq.vertexes;
|
||||||
glIndex_t *dstIndex = vcq.indexes;
|
vaoCacheGlIndex_t *dstIndex = vcq.indexes;
|
||||||
|
unsigned short *dstIndexUshort = (unsigned short *)vcq.indexes;
|
||||||
|
|
||||||
batchLength = vc.batchLengths + vc.numBatches;
|
batchLength = vc.batchLengths + vc.numBatches;
|
||||||
*batchLength = vcq.numSurfaces;
|
*batchLength = vcq.numSurfaces;
|
||||||
vc.numBatches++;
|
vc.numBatches++;
|
||||||
|
|
||||||
tess.firstIndex = vc.indexOffset / sizeof(glIndex_t);
|
tess.firstIndex = vc.indexOffset / glRefConfig.vaoCacheGlIndexSize;
|
||||||
vcq.vertexCommitSize = 0;
|
vcq.vertexCommitSize = 0;
|
||||||
vcq.indexCommitSize = 0;
|
vcq.indexCommitSize = 0;
|
||||||
for (surf = vcq.surfaces; surf < end; surf++)
|
for (surf = vcq.surfaces; surf < end; surf++)
|
||||||
{
|
{
|
||||||
glIndex_t *srcIndex = surf->indexes;
|
glIndex_t *srcIndex = surf->indexes;
|
||||||
int vertexesSize = surf->numVerts * sizeof(srfVert_t);
|
int vertexesSize = surf->numVerts * sizeof(srfVert_t);
|
||||||
int indexesSize = surf->numIndexes * sizeof(glIndex_t);
|
int indexesSize = surf->numIndexes * glRefConfig.vaoCacheGlIndexSize;
|
||||||
int i, indexOffset = (vc.vertexOffset + vcq.vertexCommitSize) / sizeof(srfVert_t);
|
int i, indexOffset = (vc.vertexOffset + vcq.vertexCommitSize) / sizeof(srfVert_t);
|
||||||
|
|
||||||
Com_Memcpy(dstVertex, surf->vertexes, vertexesSize);
|
Com_Memcpy(dstVertex, surf->vertexes, vertexesSize);
|
||||||
|
@ -781,13 +777,21 @@ void VaoCache_Commit(void)
|
||||||
vcq.vertexCommitSize += vertexesSize;
|
vcq.vertexCommitSize += vertexesSize;
|
||||||
|
|
||||||
indexSet = vc.surfaceIndexSets + vc.numSurfaces;
|
indexSet = vc.surfaceIndexSets + vc.numSurfaces;
|
||||||
indexSet->data = surf->indexes;
|
indexSet->indexes = surf->indexes;
|
||||||
indexSet->size = indexesSize;
|
indexSet->numIndexes = surf->numIndexes;
|
||||||
indexSet->bufferOffset = vc.indexOffset + vcq.indexCommitSize;
|
indexSet->bufferOffset = vc.indexOffset + vcq.indexCommitSize;
|
||||||
vc.numSurfaces++;
|
vc.numSurfaces++;
|
||||||
|
|
||||||
|
if (glRefConfig.vaoCacheGlIndexType == GL_UNSIGNED_SHORT)
|
||||||
|
{
|
||||||
|
for (i = 0; i < surf->numIndexes; i++)
|
||||||
|
*dstIndexUshort++ = *srcIndex++ + indexOffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < surf->numIndexes; i++)
|
for (i = 0; i < surf->numIndexes; i++)
|
||||||
*dstIndex++ = *srcIndex++ + indexOffset;
|
*dstIndex++ = *srcIndex++ + indexOffset;
|
||||||
|
}
|
||||||
|
|
||||||
vcq.indexCommitSize += indexesSize;
|
vcq.indexCommitSize += indexesSize;
|
||||||
}
|
}
|
||||||
|
@ -810,9 +814,30 @@ void VaoCache_Commit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VaoCache_DrawElements(int numIndexes, int firstIndex)
|
||||||
|
{
|
||||||
|
assert( glState.currentVao == vc.vao );
|
||||||
|
|
||||||
|
qglDrawElements(GL_TRIANGLES, numIndexes, glRefConfig.vaoCacheGlIndexType, BUFFER_OFFSET(firstIndex * glRefConfig.vaoCacheGlIndexSize));
|
||||||
|
}
|
||||||
|
|
||||||
void VaoCache_Init(void)
|
void VaoCache_Init(void)
|
||||||
{
|
{
|
||||||
vc.vao = R_CreateVao("VaoCache", NULL, VAOCACHE_VERTEX_BUFFER_SIZE, NULL, VAOCACHE_INDEX_BUFFER_SIZE, VAO_USAGE_DYNAMIC);
|
int vertexBufferSize;
|
||||||
|
int indexBufferSize;
|
||||||
|
|
||||||
|
if (glRefConfig.vaoCacheGlIndexType == GL_UNSIGNED_SHORT)
|
||||||
|
{
|
||||||
|
vertexBufferSize = sizeof(srfVert_t) * USHRT_MAX;
|
||||||
|
indexBufferSize = sizeof(unsigned short) * USHRT_MAX * 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertexBufferSize = VAOCACHE_VERTEX_BUFFER_SIZE;
|
||||||
|
indexBufferSize = VAOCACHE_INDEX_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vc.vao = R_CreateVao("VaoCache", NULL, vertexBufferSize, NULL, indexBufferSize, VAO_USAGE_DYNAMIC);
|
||||||
|
|
||||||
vc.vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
|
vc.vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
|
||||||
vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
|
vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
|
||||||
|
@ -881,7 +906,7 @@ void VaoCache_BindVao(void)
|
||||||
void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes)
|
void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes)
|
||||||
{
|
{
|
||||||
int vertexesSize = sizeof(srfVert_t) * numVerts;
|
int vertexesSize = sizeof(srfVert_t) * numVerts;
|
||||||
int indexesSize = sizeof(glIndex_t) * numIndexes;
|
int indexesSize = glRefConfig.vaoCacheGlIndexSize * numIndexes;
|
||||||
|
|
||||||
if (vc.vao->vertexesSize < vc.vertexOffset + vcq.vertexCommitSize + vertexesSize)
|
if (vc.vao->vertexesSize < vc.vertexOffset + vcq.vertexCommitSize + vertexesSize)
|
||||||
{
|
{
|
||||||
|
@ -924,7 +949,7 @@ void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboo
|
||||||
*endSurface = qtrue;
|
*endSurface = qtrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VAOCACHE_QUEUE_MAX_INDEXES * sizeof(glIndex_t) < vcq.indexCommitSize + indexesSize)
|
if (VAOCACHE_QUEUE_MAX_INDEXES * glRefConfig.vaoCacheGlIndexSize < vcq.indexCommitSize + indexesSize)
|
||||||
{
|
{
|
||||||
//ri.Printf(PRINT_ALL, "out of queued indexes\n");
|
//ri.Printf(PRINT_ALL, "out of queued indexes\n");
|
||||||
*endSurface = qtrue;
|
*endSurface = qtrue;
|
||||||
|
@ -964,5 +989,5 @@ void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int
|
||||||
vcq.numSurfaces++;
|
vcq.numSurfaces++;
|
||||||
|
|
||||||
vcq.vertexCommitSize += sizeof(srfVert_t) * numVerts;
|
vcq.vertexCommitSize += sizeof(srfVert_t) * numVerts;
|
||||||
vcq.indexCommitSize += sizeof(glIndex_t) * numIndexes;
|
vcq.indexCommitSize += glRefConfig.vaoCacheGlIndexSize * numIndexes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obta
|
||||||
cvar_t *r_allowResize; // make window resizable
|
cvar_t *r_allowResize; // make window resizable
|
||||||
cvar_t *r_centerWindow;
|
cvar_t *r_centerWindow;
|
||||||
cvar_t *r_sdlDriver;
|
cvar_t *r_sdlDriver;
|
||||||
|
cvar_t *r_useOpenGLES;
|
||||||
|
|
||||||
int qglMajorVersion, qglMinorVersion;
|
int qglMajorVersion, qglMinorVersion;
|
||||||
int qglesMajorVersion, qglesMinorVersion;
|
int qglesMajorVersion, qglesMinorVersion;
|
||||||
|
@ -230,6 +231,27 @@ static void GLimp_DetectAvailableModes(void)
|
||||||
SDL_free( modes );
|
SDL_free( modes );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
OpenGL ES compatibility
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static void APIENTRY GLimp_GLES_ClearDepth( GLclampd depth ) {
|
||||||
|
qglClearDepthf( depth );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GLimp_GLES_DepthRange( GLclampd near_val, GLclampd far_val ) {
|
||||||
|
qglDepthRangef( near_val, far_val );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GLimp_GLES_DrawBuffer( GLenum mode ) {
|
||||||
|
// unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GLimp_GLES_PolygonMode( GLenum face, GLenum mode ) {
|
||||||
|
// unsupported
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
GLimp_GetProcAddresses
|
GLimp_GetProcAddresses
|
||||||
|
@ -306,8 +328,11 @@ static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) {
|
||||||
QGL_1_3_PROCS;
|
QGL_1_3_PROCS;
|
||||||
QGL_1_5_PROCS;
|
QGL_1_5_PROCS;
|
||||||
QGL_2_0_PROCS;
|
QGL_2_0_PROCS;
|
||||||
// error so this doesn't segfault due to NULL desktop GL functions being used
|
|
||||||
Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s", version );
|
qglClearDepth = GLimp_GLES_ClearDepth;
|
||||||
|
qglDepthRange = GLimp_GLES_DepthRange;
|
||||||
|
qglDrawBuffer = GLimp_GLES_DrawBuffer;
|
||||||
|
qglPolygonMode = GLimp_GLES_PolygonMode;
|
||||||
} else {
|
} else {
|
||||||
Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required", version );
|
Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required", version );
|
||||||
}
|
}
|
||||||
|
@ -633,23 +658,47 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
|
||||||
|
|
||||||
if (!fixedFunction)
|
if (!fixedFunction)
|
||||||
{
|
{
|
||||||
int profileMask, majorVersion, minorVersion;
|
int profileMask;
|
||||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profileMask);
|
|
||||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
|
|
||||||
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
|
|
||||||
|
|
||||||
|
SDL_GL_GetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, &profileMask );
|
||||||
|
|
||||||
|
if ( r_useOpenGLES->integer == 1 || ( r_useOpenGLES->integer == -1 && profileMask == SDL_GL_CONTEXT_PROFILE_ES ) )
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_ALL, "Trying to get an OpenGL ES 2.0 context\n" );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
|
||||||
|
|
||||||
|
SDL_glContext = SDL_GL_CreateContext( SDL_window );
|
||||||
|
if ( !SDL_glContext )
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_ALL, "SDL_GL_CreateContext succeeded.\n" );
|
||||||
|
|
||||||
|
if ( !GLimp_GetProcAddresses( fixedFunction ) )
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL ES 2.0 context\n" );
|
||||||
|
GLimp_ClearProcAddresses();
|
||||||
|
SDL_GL_DeleteContext( SDL_glContext );
|
||||||
|
SDL_glContext = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !SDL_glContext )
|
||||||
|
{
|
||||||
ri.Printf( PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n" );
|
ri.Printf( PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n" );
|
||||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
|
||||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
|
||||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
|
||||||
if ((SDL_glContext = SDL_GL_CreateContext(SDL_window)) == NULL)
|
|
||||||
|
SDL_glContext = SDL_GL_CreateContext( SDL_window );
|
||||||
|
if ( !SDL_glContext )
|
||||||
{
|
{
|
||||||
ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() );
|
ri.Printf( PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError() );
|
||||||
ri.Printf(PRINT_ALL, "Reverting to default context\n");
|
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -667,7 +716,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
|
||||||
renderer = NULL;
|
renderer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderer || (strstr(renderer, "Software Renderer") || strstr(renderer, "Software Rasterizer")))
|
if ( !renderer || strstr( renderer, "Software Renderer" ) || strstr( renderer, "Software Rasterizer" ) )
|
||||||
{
|
{
|
||||||
if ( renderer )
|
if ( renderer )
|
||||||
ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer);
|
ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer);
|
||||||
|
@ -675,15 +724,25 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
|
||||||
GLimp_ClearProcAddresses();
|
GLimp_ClearProcAddresses();
|
||||||
SDL_GL_DeleteContext( SDL_glContext );
|
SDL_GL_DeleteContext( SDL_glContext );
|
||||||
SDL_glContext = NULL;
|
SDL_glContext = NULL;
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !SDL_glContext )
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_ALL, "Trying to get an OpenGL 2.0 context\n" );
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, 0 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 1 );
|
||||||
|
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
|
||||||
|
|
||||||
SDL_glContext = NULL;
|
SDL_glContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,7 +874,7 @@ static void GLimp_InitExtensions( qboolean fixedFunction )
|
||||||
glConfig.textureCompression = TC_NONE;
|
glConfig.textureCompression = TC_NONE;
|
||||||
|
|
||||||
// GL_EXT_texture_compression_s3tc
|
// GL_EXT_texture_compression_s3tc
|
||||||
if ( SDL_GL_ExtensionSupported( "GL_ARB_texture_compression" ) &&
|
if ( ( QGLES_VERSION_ATLEAST( 2, 0 ) || SDL_GL_ExtensionSupported( "GL_ARB_texture_compression" ) ) &&
|
||||||
SDL_GL_ExtensionSupported( "GL_EXT_texture_compression_s3tc" ) )
|
SDL_GL_ExtensionSupported( "GL_EXT_texture_compression_s3tc" ) )
|
||||||
{
|
{
|
||||||
if ( r_ext_compressed_textures->value )
|
if ( r_ext_compressed_textures->value )
|
||||||
|
@ -996,6 +1055,7 @@ void GLimp_Init( qboolean fixedFunction )
|
||||||
r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM );
|
r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM );
|
||||||
r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH );
|
r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH );
|
||||||
r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH );
|
r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH );
|
||||||
|
r_useOpenGLES = ri.Cvar_Get( "r_useOpenGLES", "-1", CVAR_ARCHIVE | CVAR_LATCH );
|
||||||
|
|
||||||
if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) )
|
if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,6 +63,14 @@ For Win32:
|
||||||
CVARS
|
CVARS
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Cvars for API:
|
||||||
|
|
||||||
|
* `r_useOpenGLES` - This enables using OpenGL ES 2+.
|
||||||
|
Many features are not supported such as sun shadows and HDR.
|
||||||
|
1 - Use OpenGL ES.
|
||||||
|
0 - Use desktop OpenGL.
|
||||||
|
-1 - Automatically pick (default).
|
||||||
|
|
||||||
Cvars for simple rendering features:
|
Cvars for simple rendering features:
|
||||||
|
|
||||||
* `r_ext_compressed_textures` - Automatically compress textures.
|
* `r_ext_compressed_textures` - Automatically compress textures.
|
||||||
|
|
Loading…
Reference in a new issue