qboolean r_loadfog;
static qboolean r_loaddds;
static qboolean r_savedds;
+static qboolean r_gpuskeletal;
//
// screen size info
//=======================================================================================================================================================
-static const char *builtinshaderstring =
+static const char *builtinshaderstrings[] =
+{
#include "shader_glsl.h"
-;
+0
+};
-const char *builtinhlslshaderstring =
+const char *builtinhlslshaderstrings[] =
+{
#include "shader_hlsl.h"
-;
+0
+};
char *glslshaderstring = NULL;
char *hlslshaderstring = NULL;
typedef struct shadermodeinfo_s
{
- const char *vertexfilename;
- const char *geometryfilename;
- const char *fragmentfilename;
+ const char *filename;
const char *pretext;
const char *name;
}
// NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
{
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
- {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+ {"glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
+ {"glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
+ {"glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+ {"glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
+ {"glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+ {"glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
+ {"glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"},
+ {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+ {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+ {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+ {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+ {"glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+ {"glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
+ {"glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
+ {"glsl/default.glsl", "#define MODE_WATER\n", " water"},
+ {"glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+ {"glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
};
shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] =
{
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_WATER\n", " water"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
- {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+ {"hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"},
+ {"hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"},
+ {"hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+ {"hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
+ {"hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"},
+ {"hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+ {"hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
+ {"hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"},
+ {"hlsl/default.hlsl", "#define MODE_WATER\n", " water"},
+ {"hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+ {"hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
};
struct r_glsl_permutation_s;
return p;
}
-static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
+static char *R_ShaderStrCat(const char **strings)
+{
+ char *string, *s;
+ const char **p = strings;
+ const char *t;
+ size_t len = 0;
+ for (p = strings;(t = *p);p++)
+ len += strlen(t);
+ len++;
+ s = string = (char *)Mem_Alloc(r_main_mempool, len);
+ len = 0;
+ for (p = strings;(t = *p);p++)
+ {
+ len = strlen(t);
+ memcpy(s, t, len);
+ s += len;
+ }
+ *s = 0;
+ return string;
+}
+
+static char *R_GetShaderText(const char *filename, qboolean printfromdisknotice, qboolean builtinonly)
{
char *shaderstring;
if (!filename || !filename[0])
return NULL;
+ // LordHavoc: note that FS_LoadFile appends a 0 byte to make it a valid string, so does R_ShaderStrCat
if (!strcmp(filename, "glsl/default.glsl"))
{
+ if (builtinonly)
+ return R_ShaderStrCat(builtinshaderstrings);
if (!glslshaderstring)
{
glslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
if (glslshaderstring)
Con_DPrintf("Loading shaders from file %s...\n", filename);
else
- glslshaderstring = (char *)builtinshaderstring;
+ glslshaderstring = R_ShaderStrCat(builtinshaderstrings);
}
shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1);
memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1);
return shaderstring;
}
+ if (!strcmp(filename, "hlsl/default.hlsl"))
+ {
+ if (builtinonly)
+ return R_ShaderStrCat(builtinhlslshaderstrings);
+ if (!hlslshaderstring)
+ {
+ hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+ if (hlslshaderstring)
+ Con_DPrintf("Loading shaders from file %s...\n", filename);
+ else
+ hlslshaderstring = R_ShaderStrCat(builtinhlslshaderstrings);
+ }
+ shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1);
+ memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1);
+ return shaderstring;
+ }
+ // we don't have builtin strings for any other files
+ if (builtinonly)
+ return NULL;
shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
if (shaderstring)
{
int i;
int sampler;
shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode;
- char *vertexstring, *geometrystring, *fragmentstring;
+ char *sourcestring;
char permutationname[256];
int vertstrings_count = 0;
int geomstrings_count = 0;
p->program = 0;
permutationname[0] = 0;
- vertexstring = R_GLSL_GetText(modeinfo->vertexfilename, true);
- geometrystring = R_GLSL_GetText(modeinfo->geometryfilename, false);
- fragmentstring = R_GLSL_GetText(modeinfo->fragmentfilename, false);
+ sourcestring = R_GetShaderText(modeinfo->filename, true, false);
- strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
+ strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
// if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
if(vid.support.gl20shaders130)
fragstrings_count += shaderstaticparms_count;
// now append the shader text itself
- vertstrings_list[vertstrings_count++] = vertexstring;
- geomstrings_list[geomstrings_count++] = geometrystring;
- fragstrings_list[fragstrings_count++] = fragmentstring;
-
- // if any sources were NULL, clear the respective list
- if (!vertexstring)
- vertstrings_count = 0;
- if (!geometrystring)
- geomstrings_count = 0;
- if (!fragmentstring)
- fragstrings_count = 0;
+ vertstrings_list[vertstrings_count++] = sourcestring;
+ geomstrings_list[geomstrings_count++] = sourcestring;
+ fragstrings_list[fragstrings_count++] = sourcestring;
// compile the shader program
if (vertstrings_count + geomstrings_count + fragstrings_count)
Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname);
// free the strings
- if (vertexstring)
- Mem_Free(vertexstring);
- if (geometrystring)
- Mem_Free(geometrystring);
- if (fragmentstring)
- Mem_Free(fragmentstring);
+ if (sourcestring)
+ Mem_Free(sourcestring);
}
static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation)
}
if (i >= SHADERPERMUTATION_COUNT)
{
- //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+ //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
qglUseProgram(0);CHECKGLERROR
return; // no bit left to clear, entire mode is broken
return p;
}
-static char *R_HLSL_GetText(const char *filename, qboolean printfromdisknotice)
-{
- char *shaderstring;
- if (!filename || !filename[0])
- return NULL;
- if (!strcmp(filename, "hlsl/default.hlsl"))
- {
- if (!hlslshaderstring)
- {
- hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
- if (hlslshaderstring)
- Con_DPrintf("Loading shaders from file %s...\n", filename);
- else
- hlslshaderstring = (char *)builtinhlslshaderstring;
- }
- shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1);
- memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1);
- return shaderstring;
- }
- shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
- if (shaderstring)
- {
- if (printfromdisknotice)
- Con_DPrintf("from disk %s... ", filename);
- return shaderstring;
- }
- return shaderstring;
-}
-
#include <d3dx9.h>
//#include <d3dx9shader.h>
//#include <d3dx9mesh.h>
{"D3DXCompileShader", (void **) &qD3DXCompileShader},
{NULL, NULL}
};
+ // LordHavoc: the June 2010 SDK lacks these macros to make ID3DXBuffer usable in C, and to make it work in both C and C++ the macros are needed...
+#ifndef ID3DXBuffer_GetBufferPointer
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define ID3DXBuffer_GetBufferPointer(p) (p)->lpVtbl->GetBufferPointer(p)
+#define ID3DXBuffer_GetBufferSize(p) (p)->lpVtbl->GetBufferSize(p)
+#define ID3DXBuffer_Release(p) (p)->lpVtbl->Release(p)
+#else
+#define ID3DXBuffer_GetBufferPointer(p) (p)->GetBufferPointer()
+#define ID3DXBuffer_GetBufferSize(p) (p)->GetBufferSize()
+#define ID3DXBuffer_Release(p) (p)->Release()
+#endif
+#endif
if (Sys_LoadLibrary(dllnames_d3dx9, &d3dx9_dll, d3dx9_dllfuncs))
{
DWORD shaderflags = 0;
int geomstring_length = 0;
int fragstring_length = 0;
char *t;
- char *vertexstring, *geometrystring, *fragmentstring;
+ char *sourcestring;
char *vertstring, *geomstring, *fragstring;
char permutationname[256];
char cachename[256];
permutationname[0] = 0;
cachename[0] = 0;
- vertexstring = R_HLSL_GetText(modeinfo->vertexfilename, true);
- geometrystring = R_HLSL_GetText(modeinfo->geometryfilename, false);
- fragmentstring = R_HLSL_GetText(modeinfo->fragmentfilename, false);
+ sourcestring = R_GetShaderText(modeinfo->filename, true, false);
- strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
+ strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
strlcat(cachename, "hlsl/", sizeof(cachename));
// define HLSL so that the shader can tell apart the HLSL compiler and the Cg compiler
cachename[i] = '_';
// now append the shader text itself
- vertstrings_list[vertstrings_count++] = vertexstring;
- geomstrings_list[geomstrings_count++] = geometrystring;
- fragstrings_list[fragstrings_count++] = fragmentstring;
-
- // if any sources were NULL, clear the respective list
- if (!vertexstring)
- vertstrings_count = 0;
- if (!geometrystring)
- geomstrings_count = 0;
- if (!fragmentstring)
- fragstrings_count = 0;
+ vertstrings_list[vertstrings_count++] = sourcestring;
+ geomstrings_list[geomstrings_count++] = sourcestring;
+ fragstrings_list[fragstrings_count++] = sourcestring;
vertstring_length = 0;
for (i = 0;i < vertstrings_count;i++)
Mem_Free(geomstring);
if (fragstring)
Mem_Free(fragstring);
- if (vertexstring)
- Mem_Free(vertexstring);
- if (geometrystring)
- Mem_Free(geometrystring);
- if (fragmentstring)
- Mem_Free(fragmentstring);
+ if (sourcestring)
+ Mem_Free(sourcestring);
}
static inline void hlslVSSetParameter16f(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 4);}
}
if (i >= SHADERPERMUTATION_COUNT)
{
- //Con_Printf("Could not find a working HLSL shader for permutation %s %s\n", shadermodeinfo[mode].vertexfilename, shadermodeinfo[mode].pretext);
+ //Con_Printf("Could not find a working HLSL shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation);
return; // no bit left to clear, entire mode is broken
}
void R_GLSL_Restart_f(void)
{
unsigned int i, limit;
- if (glslshaderstring && glslshaderstring != builtinshaderstring)
+ if (glslshaderstring)
Mem_Free(glslshaderstring);
glslshaderstring = NULL;
- if (hlslshaderstring && hlslshaderstring != builtinhlslshaderstring)
+ if (hlslshaderstring)
Mem_Free(hlslshaderstring);
hlslshaderstring = NULL;
switch(vid.renderpath)
static void R_GLSL_DumpShader_f(void)
{
- int i;
+ int i, language, mode, dupe;
+ char *text;
+ shadermodeinfo_t *modeinfo;
qfile_t *file;
- file = FS_OpenRealFile("glsl/default.glsl", "w", false);
- if (file)
+ for (language = 0;language < 2;language++)
{
- FS_Print(file, "/* The engine may define the following macros:\n");
- FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
- for (i = 0;i < SHADERMODE_COUNT;i++)
- FS_Print(file, glslshadermodeinfo[i].pretext);
- for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
- FS_Print(file, shaderpermutationinfo[i].pretext);
- FS_Print(file, "*/\n");
- FS_Print(file, builtinshaderstring);
- FS_Close(file);
- Con_Printf("glsl/default.glsl written\n");
- }
- else
- Con_Printf("failed to write to glsl/default.glsl\n");
-
- file = FS_OpenRealFile("hlsl/default.hlsl", "w", false);
- if (file)
- {
- FS_Print(file, "/* The engine may define the following macros:\n");
- FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
- for (i = 0;i < SHADERMODE_COUNT;i++)
- FS_Print(file, hlslshadermodeinfo[i].pretext);
- for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
- FS_Print(file, shaderpermutationinfo[i].pretext);
- FS_Print(file, "*/\n");
- FS_Print(file, builtinhlslshaderstring);
- FS_Close(file);
- Con_Printf("hlsl/default.hlsl written\n");
+ modeinfo = (language == 0 ? glslshadermodeinfo : hlslshadermodeinfo);
+ for (mode = 0;mode < SHADERMODE_COUNT;mode++)
+ {
+ // don't dump the same file multiple times (most or all shaders come from the same file)
+ for (dupe = mode - 1;dupe >= 0;dupe--)
+ if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
+ break;
+ if (dupe >= 0)
+ continue;
+ text = R_GetShaderText(modeinfo[mode].filename, false, true);
+ if (!text)
+ continue;
+ file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
+ if (file)
+ {
+ FS_Print(file, "/* The engine may define the following macros:\n");
+ FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
+ for (i = 0;i < SHADERMODE_COUNT;i++)
+ FS_Print(file, modeinfo[i].pretext);
+ for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ FS_Print(file, shaderpermutationinfo[i].pretext);
+ FS_Print(file, "*/\n");
+ FS_Print(file, text);
+ FS_Close(file);
+ Con_Printf("%s written\n", modeinfo[mode].filename);
+ }
+ else
+ Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
+ Mem_Free(text);
+ }
}
- else
- Con_Printf("failed to write to hlsl/default.hlsl\n");
}
void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
case RENDERPATH_GL20:
case RENDERPATH_GLES2:
R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
- R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
- R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
+ if (r_glsl_permutation->tex_Texture_First >= 0)
+ R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
+ if (r_glsl_permutation->tex_Texture_Second >= 0)
+ R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
break;
case RENDERPATH_GLES1:
R_Mesh_TexBind(0, first );
R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+ R_Mesh_TexMatrix(0, NULL);
R_Mesh_TexBind(1, second);
if (second)
+ {
R_Mesh_TexCombine(1, texturemode, texturemode, rgbscale, 1);
+ R_Mesh_TexMatrix(1, NULL);
+ }
break;
case RENDERPATH_GL11:
R_Mesh_TexBind(0, first );
+ R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+ R_Mesh_TexMatrix(0, NULL);
break;
case RENDERPATH_SOFT:
R_SetupShader_SetPermutationSoft(SHADERMODE_GENERIC, permutation);
}
}
-void R_SetupShader_ShowDepth(qboolean notrippy)
-{
- int permutation = 0;
- if (r_trippy.integer && !notrippy)
- permutation |= SHADERPERMUTATION_TRIPPY;
- if (vid.allowalphatocoverage)
- GL_AlphaToCoverage(false);
- switch (vid.renderpath)
- {
- case RENDERPATH_D3D9:
-#ifdef SUPPORTHLSL
- R_SetupShader_SetPermutationHLSL(SHADERMODE_SHOWDEPTH, permutation);
-#endif
- break;
- case RENDERPATH_D3D10:
- Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_D3D11:
- Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
- break;
- case RENDERPATH_GL20:
- case RENDERPATH_GLES2:
- R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, permutation);
- break;
- case RENDERPATH_GL13:
- case RENDERPATH_GLES1:
- break;
- case RENDERPATH_GL11:
- break;
- case RENDERPATH_SOFT:
- R_SetupShader_SetPermutationSoft(SHADERMODE_SHOWDEPTH, permutation);
- break;
- }
-}
-
extern qboolean r_shadow_usingdeferredprepass;
extern rtexture_t *r_shadow_attenuationgradienttexture;
extern rtexture_t *r_shadow_attenuation2dtexture;
r_framedata_mem->current += size;
// count the usage for stats
- r_refdef.stats.framedatacurrent = max(r_refdef.stats.framedatacurrent, (int)r_framedata_mem->current);
- r_refdef.stats.framedatasize = max(r_refdef.stats.framedatasize, (int)r_framedata_mem->size);
+ r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
+ r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
return (void *)data;
}
// TODO: upload vertex3f buffer?
if (ent->animcache_vertexmesh)
{
+ r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
+ r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
+ r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
for (i = 0;i < numvertices;i++)
memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
dp_model_t *model = ent->model;
int numvertices;
- // cache skeletal animation data first (primarily for gpu-skinning)
- if (!ent->animcache_skeletaltransform3x4 && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
+ // see if this ent is worth caching
+ if (!model || !model->Draw || !model->AnimateVertices)
+ return false;
+ // nothing to cache if it contains no animations and has no skeleton
+ if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
+ return false;
+ // see if it is already cached for gpuskeletal
+ if (ent->animcache_skeletaltransform3x4)
+ return false;
+ // see if it is already cached as a mesh
+ if (ent->animcache_vertex3f)
{
+ // check if we need to add normals or tangents
+ if (ent->animcache_normal3f)
+ wantnormals = false;
+ if (ent->animcache_svector3f)
+ wanttangents = false;
+ if (!wantnormals && !wanttangents)
+ return false;
+ }
+
+ // check which kind of cache we need to generate
+ if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
+ {
+ // cache the skeleton so the vertex shader can use it
int i;
int blends;
const skeleton_t *skeleton = ent->skeleton;
float *boneposerelative;
float m[12];
static float bonepose[256][12];
- ent->animcache_skeletaltransform3x4 = R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
+ r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
+ r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
+ r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
+ ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
boneposerelative = ent->animcache_skeletaltransform3x4;
if (skeleton && !skeleton->relativetransforms)
skeleton = NULL;
}
}
}
-
- // see if it's already cached this frame
- if (ent->animcache_vertex3f)
+ else if (ent->animcache_vertex3f)
{
- // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc)
+ // mesh was already cached but we may need to add normals/tangents
+ // (this only happens with multiple views, reflections, cameras, etc)
if (wantnormals || wanttangents)
{
- if (ent->animcache_normal3f)
- wantnormals = false;
- if (ent->animcache_svector3f)
- wanttangents = false;
- if (wantnormals || wanttangents)
+ numvertices = model->surfmesh.num_vertices;
+ if (wantnormals)
+ ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ if (wanttangents)
{
- numvertices = model->surfmesh.num_vertices;
- if (wantnormals)
- ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- if (wanttangents)
- {
- ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
- }
- model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
- R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
+ ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
+ ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
}
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
+ R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
+ r_refdef.stats[r_stat_animcache_shade_count] += 1;
+ r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
+ r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
}
}
else
{
- // see if this ent is worth caching
- if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices)
- return false;
- // skip entity if the shader backend has a cheaper way
- if (model->surfmesh.data_skeletalindex4ub && r_glsl_skeletal.integer)
- {
- switch (vid.renderpath)
- {
- case RENDERPATH_GL20:
- return false;
- case RENDERPATH_GL11:
- case RENDERPATH_GL13:
- case RENDERPATH_GLES1:
- case RENDERPATH_GLES2:
- case RENDERPATH_D3D9:
- case RENDERPATH_D3D10:
- case RENDERPATH_D3D11:
- case RENDERPATH_SOFT:
- break;
- }
- }
- // get some memory for this entity and generate mesh data
+ // generate mesh cache
numvertices = model->surfmesh.num_vertices;
ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
if (wantnormals)
}
model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
+ if (wantnormals || wanttangents)
+ {
+ r_refdef.stats[r_stat_animcache_shade_count] += 1;
+ r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
+ r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
+ }
+ r_refdef.stats[r_stat_animcache_shape_count] += 1;
+ r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
+ r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
}
return true;
}
if (!r_refdef.viewcache.entityvisible[i])
continue;
ent = r_refdef.scene.entities[i];
- r_refdef.stats.entities++;
+ r_refdef.stats[r_stat_entities]++;
/*
if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
{
rtexture_t *intex;
float colorscale = r_bloom_colorscale.value;
- r_refdef.stats.bloom++;
+ r_refdef.stats[r_stat_bloom]++;
#if 0
// this copy is unnecessary since it happens in R_BlendView already
if (!r_fb.fbo)
{
R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
- r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
#endif
// TODO: do boxfilter scale-down in shader?
R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true, true);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
- r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
+ r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
// we now have a properly scaled bloom image
if (!r_fb.bloomfbo[r_fb.bloomindex])
{
// copy it into the bloom texture
R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
- r_refdef.stats.bloom_copypixels += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
}
// multiply bloom image by itself as many times as desired
R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f);
R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
- r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
+ r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
if (!r_fb.bloomfbo[r_fb.bloomindex])
{
// copy the darkened image to a texture
R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
- r_refdef.stats.bloom_copypixels += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
}
}
GL_Color(r, r, r, 1);
R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
- r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
+ r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
GL_BlendFunc(GL_ONE, GL_ONE);
}
{
// copy the vertically or horizontally blurred bloom view to a texture
R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height);
- r_refdef.stats.bloom_copypixels += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
}
}
}
if (!r_fb.fbo)
{
R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
- r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
}
R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
}
// updates old view angles for next pass
// copy view into the ghost texture
R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
- r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+ r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
r_fb.ghosttexture_valid = true;
}
}
break;
}
R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
- r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+ r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
break;
case RENDERPATH_GL11:
case RENDERPATH_GL13:
r_refdef.lightmapintensity = 0;
}
+ r_gpuskeletal = false;
switch(vid.renderpath)
{
case RENDERPATH_GL20:
+ r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
if (r_timereport_active)
R_TimeReport("beginscene");
- r_refdef.stats.renders++;
+ r_refdef.stats[r_stat_renders]++;
R_UpdateFog();
{
if (ent->animcache_vertex3f)
{
+ r_refdef.stats[r_stat_batch_entitycache_count]++;
+ r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = ent->animcache_vertex3f;
rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
}
else if (wanttangents)
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
}
else if (wantnormals)
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
}
else
{
+ r_refdef.stats[r_stat_batch_entityanimate_count]++;
+ r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
}
else
{
+ if (rsurface.entityskeletaltransform3x4)
+ {
+ r_refdef.stats[r_stat_batch_entityskeletal_count]++;
+ r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
+ }
+ else
+ {
+ r_refdef.stats[r_stat_batch_entitystatic_count]++;
+ r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
+ r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
+ r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
+ }
rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
rsurface.basepolygonoffset = r_refdef.polygonoffset;
rsurface.entityskeletaltransform3x4 = NULL;
rsurface.entityskeletalnumtransforms = 0;
+ r_refdef.stats[r_stat_batch_entitycustom_count]++;
+ r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
+ r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
+ r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
if (wanttangents)
{
rsurface.modelvertex3f = (float *)vertex3f;
int surfacefirstvertex;
int surfaceendvertex;
int surfacenumvertices;
+ int batchnumsurfaces = texturenumsurfaces;
int batchnumvertices;
int batchnumtriangles;
int needsupdate;
batchnumtriangles += surfacenumtriangles;
}
+ r_refdef.stats[r_stat_batch_batches]++;
+ if (gaps)
+ r_refdef.stats[r_stat_batch_withgaps]++;
+ r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
+
// we now know the vertex range used, and if there are any gaps in it
rsurface.batchfirstvertex = firstvertex;
rsurface.batchnumvertices = endvertex - firstvertex;
// a cvar to force the dynamic vertex path to be taken, for debugging
if (r_batch_debugdynamicvertexpath.integer)
+ {
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
+ }
dynamicvertex = true;
+ }
// if there is a chance of animated vertex colors, it's a dynamic batch
if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
{
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
+ }
dynamicvertex = true;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
}
case Q3DEFORM_NONE:
break;
case Q3DEFORM_AUTOSPRITE:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
break;
case Q3DEFORM_AUTOSPRITE2:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
break;
case Q3DEFORM_NORMAL:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
case Q3DEFORM_WAVE:
if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
break; // if wavefunc is a nop, ignore this transform
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
break;
case Q3DEFORM_BULGE:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
case Q3DEFORM_MOVE:
if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
break; // if wavefunc is a nop, ignore this transform
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
case Q3TCGEN_TEXTURE:
break;
case Q3TCGEN_LIGHTMAP:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
break;
case Q3TCGEN_VECTOR:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX;
needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
break;
case Q3TCGEN_ENVIRONMENT:
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
}
if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
{
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
+ }
dynamicvertex = true;
batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
{
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
+ }
dynamicvertex = true;
needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
}
// when the model data has no vertex buffer (dynamic mesh), we need to
// eliminate gaps
- if (vid.useinterleavedarrays ? !rsurface.modelvertexmeshbuffer : !rsurface.modelvertex3f_vertexbuffer)
+ if (vid.useinterleavedarrays && !rsurface.modelvertexmeshbuffer)
batchneed |= BATCHNEED_NOGAPS;
// the caller can specify BATCHNEED_NOGAPS to force a batch with
// firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
// we ensure this by treating the vertex batch as dynamic...
if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
+ {
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
+ }
dynamicvertex = true;
+ }
if (dynamicvertex)
{
// if needsupdate, we have to do a dynamic vertex batch for sure
if (needsupdate & batchneed)
+ {
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
+ }
dynamicvertex = true;
+ }
// see if we need to build vertexmesh from arrays
if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
+ {
+ if (!dynamicvertex)
+ {
+ r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
+ }
dynamicvertex = true;
+ }
// if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
if (dynamicvertex && rsurface.entityskeletaltransform3x4)
// otherwise use the original static buffer with an appropriate offset
if (gaps)
{
+ r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
+ r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
{
rsurface.batchmultidraw = true;
rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
}
}
+ else
+ {
+ r_refdef.stats[r_stat_batch_fast_batches] += 1;
+ r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
+ }
return;
}
// we only directly handle separate array data in this case and then
// generate interleaved data if needed...
rsurface.batchgeneratedvertex = true;
+ r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
+ r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
// now copy the vertex data into a combined array and make an index array
// (this is what Quake3 does all the time)
float w[4];
float m[3][4], n[3][4];
float tp[3], ts[3], tt[3], tn[3];
+ r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
+ r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
+ r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
+ r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
si = rsurface.batchskeletalindex4ub;
sw = rsurface.batchskeletalweight4ub;
vp = rsurface.batchvertex3f;
R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset);
GL_Color(r, g, b, a);
R_Mesh_TexBind(0, rsurface.lightmaptexture);
+ R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
+ R_Mesh_TexMatrix(0, NULL);
RSurf_DrawBatch();
}
if (numtris > 0)
{
- r_refdef.stats.drawndecals += numtris;
+ r_refdef.stats[r_stat_drawndecals] += numtris;
// now render the decals all at once
// (this assumes they all use one particle font texture!)
for (i = 0;i < r_refdef.scene.numentities;i++)
numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
- r_refdef.stats.totaldecals += numdecals;
+ r_refdef.stats[r_stat_totaldecals] += numdecals;
if (r_showsurfaces.integer)
return;
// add to stats if desired
if (r_speeds.integer && !skysurfaces && !depthonly)
{
- r_refdef.stats.world_surfaces += numsurfacelist;
+ r_refdef.stats[r_stat_world_surfaces] += numsurfacelist;
for (j = 0;j < numsurfacelist;j++)
- r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles;
+ r_refdef.stats[r_stat_world_triangles] += r_surfacelist[j]->num_triangles;
}
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
// add to stats if desired
if (r_speeds.integer && !skysurfaces && !depthonly)
{
- r_refdef.stats.entities_surfaces += numsurfacelist;
+ r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
for (j = 0;j < numsurfacelist;j++)
- r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles;
+ r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
}
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity