extern LPDIRECT3DDEVICE9 vid_d3d9dev;
#endif
+#ifdef WIN32
+// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
+#ifdef __cplusplus
+extern "C" {
+#endif
+__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+#ifdef __cplusplus
+}
+#endif
+#endif
+
mempool_t *r_main_mempool;
rtexturepool_t *r_main_texturepool;
qboolean r_loadfog;
static qboolean r_loaddds;
static qboolean r_savedds;
+static qboolean r_gpuskeletal;
//
// screen size info
cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
+cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
+cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
+cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
+cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
+cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
+{
+ {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
+ {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
+ {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
+ {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
+};
extern cvar_t v_glslgamma;
extern cvar_t v_glslgamma_2d;
/// shadow volume bsp struct with automatically growing nodes buffer
svbsp_t r_svbsp;
+int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
+
rtexture_t *r_texture_blanknormalmap;
rtexture_t *r_texture_white;
rtexture_t *r_texture_grey128;
//=======================================================================================================================================================
-static const char *builtinshaderstring =
+static const char *builtinshaderstrings[] =
+{
#include "shader_glsl.h"
-;
+0
+};
-const char *builtinhlslshaderstring =
+const char *builtinhlslshaderstrings[] =
+{
#include "shader_hlsl.h"
-;
-
-char *glslshaderstring = NULL;
-char *hlslshaderstring = NULL;
+0
+};
//=======================================================================================================================================================
typedef struct shadermodeinfo_s
{
- const char *vertexfilename;
- const char *geometryfilename;
- const char *fragmentfilename;
+ const char *sourcebasename;
+ const char *extension;
+ const char **builtinshaderstrings;
const char *pretext;
const char *name;
+ char *filename;
+ char *builtinstring;
+ int builtincrc;
}
shadermodeinfo_t;
{"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
{"#define USETRIPPY\n", " trippy"},
{"#define USEDEPTHRGB\n", " depthrgb"},
- {"#define USEALPHAGENVERTEX\n", "alphagenvertex"}
+ {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
+ {"#define USESKELETAL\n", " skeletal"},
+ {"#define USEOCCLUDE\n", " occlude"}
};
// 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"},
-};
-
-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"},
+shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
+{
+ // SHADERLANGUAGE_GLSL
+ {
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+ {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+ },
+ // SHADERLANGUAGE_HLSL
+ {
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_GENERIC\n", " generic"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_WATER\n", " water"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
+ {"combined", "hlsl", builtinhlslshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
+ },
};
struct r_glsl_permutation_s;
int loc_ShadowMap_Parameters;
int loc_ShadowMap_TextureScale;
int loc_SpecularPower;
+ int loc_Skeletal_Transform12;
int loc_UserVec1;
int loc_UserVec2;
int loc_UserVec3;
int loc_NormalmapScrollBlend;
int loc_BounceGridMatrix;
int loc_BounceGridIntensity;
+ /// uniform block bindings
+ int ubibind_Skeletal_Transform12_UniformBlock;
+ /// uniform block indices
+ int ubiloc_Skeletal_Transform12_UniformBlock;
}
r_glsl_permutation_t;
SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
+ SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
};
-#define SHADERSTATICPARMS_COUNT 13
+#define SHADERSTATICPARMS_COUNT 14
static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
static int shaderstaticparms_count = 0;
extern int r_shadow_shadowmappcf;
qboolean R_CompileShader_CheckStaticParms(void)
{
- static int r_compileshader_staticparms_save[1];
+ static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
if (r_glsl_postprocess_uservec4_enable.integer)
R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
}
+ if (r_fxaa.integer)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
}
/// information about each possible shader permutation
return p;
}
-static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
+static char *R_ShaderStrCat(const char **strings)
{
- char *shaderstring;
- if (!filename || !filename[0])
- return NULL;
- if (!strcmp(filename, "glsl/default.glsl"))
+ 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++)
{
- if (!glslshaderstring)
+ len = strlen(t);
+ memcpy(s, t, len);
+ s += len;
+ }
+ *s = 0;
+ return string;
+}
+
+static char *R_ShaderStrCat(const char **strings);
+static void R_InitShaderModeInfo(void)
+{
+ int i, language;
+ shadermodeinfo_t *modeinfo;
+ // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
+ for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
+ {
+ for (i = 0; i < SHADERMODE_COUNT; i++)
{
- 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;
+ char filename[MAX_QPATH];
+ modeinfo = &shadermodeinfo[language][i];
+ modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
+ modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
+ dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
+ modeinfo->filename = Mem_strdup(r_main_mempool, filename);
}
- shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1);
- memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1);
- return shaderstring;
}
- shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+}
+
+static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
+{
+ char *shaderstring;
+ // if the mode has no filename we have to return the builtin string
+ if (builtinonly || !modeinfo->filename)
+ return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
+ // note that FS_LoadFile appends a 0 byte to make it a valid string
+ shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
if (shaderstring)
{
if (printfromdisknotice)
- Con_DPrintf("from disk %s... ", filename);
+ Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
return shaderstring;
}
- return shaderstring;
+ // fall back to builtinstring
+ return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
}
static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation)
{
int i;
+ int ubibind;
int sampler;
- shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode;
- char *vertexstring, *geometrystring, *fragmentstring;
+ shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
+ 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 = ShaderModeInfo_GetShaderText(modeinfo, true, false);
- strlcat(permutationname, modeinfo->vertexfilename, sizeof(permutationname));
+ strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
+ // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
+ if(vid.support.glshaderversion >= 140)
+ {
+ vertstrings_list[vertstrings_count++] = "#version 140\n";
+ geomstrings_list[geomstrings_count++] = "#version 140\n";
+ fragstrings_list[fragstrings_count++] = "#version 140\n";
+ vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
+ geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
+ fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
+ }
// if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
- if(vid.support.gl20shaders130)
+ else if(vid.support.glshaderversion >= 130)
{
vertstrings_list[vertstrings_count++] = "#version 130\n";
geomstrings_list[geomstrings_count++] = "#version 130\n";
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)
// look up all the uniform variable names we care about, so we don't
// have to look them up every time we set them
+#if 0
+ // debugging aid
+ {
+ GLint activeuniformindex = 0;
+ GLint numactiveuniforms = 0;
+ char uniformname[128];
+ GLsizei uniformnamelength = 0;
+ GLint uniformsize = 0;
+ GLenum uniformtype = 0;
+ memset(uniformname, 0, sizeof(uniformname));
+ qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
+ Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
+ for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
+ {
+ qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
+ Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
+ }
+ }
+#endif
+
p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First");
p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second");
p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps");
p->tex_Texture_ReflectMask = -1;
p->tex_Texture_ReflectCube = -1;
p->tex_Texture_BounceGrid = -1;
+ // bind the texture samplers in use
sampler = 0;
if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;}
if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;}
if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;}
if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;}
if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;}
+ // get the uniform block indices so we can bind them
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
+ if (vid.support.arb_uniform_buffer_object)
+ p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
+ else
+#endif
+ p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
+ // clear the uniform block bindings
+ p->ubibind_Skeletal_Transform12_UniformBlock = -1;
+ // bind the uniform blocks in use
+ ubibind = 0;
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
+ if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
+#endif
+ // we're done compiling and setting up the shader, at least until it is used
CHECKGLERROR
Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
}
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 (!r_glsl_permutation->program)
{
if (!r_glsl_permutation->compiled)
+ {
+ Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
R_GLSL_CompilePermutation(perm, mode, permutation);
+ }
if (!r_glsl_permutation->program)
{
// remove features until we find a valid 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
if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
+ CHECKGLERROR
}
#ifdef SUPPORTD3D
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;
vsresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
}
else
- vsresult = qD3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
+ vsresult = qD3DXCompileShader(vertstring, (unsigned int)strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
if (vsbuffer)
{
vsbinsize = ID3DXBuffer_GetBufferSize(vsbuffer);
psresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
}
else
- psresult = qD3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
+ psresult = qD3DXCompileShader(fragstring, (unsigned int)strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
if (psbuffer)
{
psbinsize = ID3DXBuffer_GetBufferSize(psbuffer);
static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode, unsigned int permutation)
{
int i;
- shadermodeinfo_t *modeinfo = hlslshadermodeinfo + mode;
+ shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_HLSL][mode];
int vertstring_length = 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 = ShaderModeInfo_GetShaderText(modeinfo, 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++)
- vertstring_length += strlen(vertstrings_list[i]);
+ vertstring_length += (int)strlen(vertstrings_list[i]);
vertstring = t = (char *)Mem_Alloc(tempmempool, vertstring_length + 1);
- for (i = 0;i < vertstrings_count;t += strlen(vertstrings_list[i]), i++)
+ for (i = 0;i < vertstrings_count;t += (int)strlen(vertstrings_list[i]), i++)
memcpy(t, vertstrings_list[i], strlen(vertstrings_list[i]));
geomstring_length = 0;
for (i = 0;i < geomstrings_count;i++)
- geomstring_length += strlen(geomstrings_list[i]);
+ geomstring_length += (int)strlen(geomstrings_list[i]);
geomstring = t = (char *)Mem_Alloc(tempmempool, geomstring_length + 1);
- for (i = 0;i < geomstrings_count;t += strlen(geomstrings_list[i]), i++)
+ for (i = 0;i < geomstrings_count;t += (int)strlen(geomstrings_list[i]), i++)
memcpy(t, geomstrings_list[i], strlen(geomstrings_list[i]));
fragstring_length = 0;
for (i = 0;i < fragstrings_count;i++)
- fragstring_length += strlen(fragstrings_list[i]);
+ fragstring_length += (int)strlen(fragstrings_list[i]);
fragstring = t = (char *)Mem_Alloc(tempmempool, fragstring_length + 1);
- for (i = 0;i < fragstrings_count;t += strlen(fragstrings_list[i]), i++)
+ for (i = 0;i < fragstrings_count;t += (int)strlen(fragstrings_list[i]), i++)
memcpy(t, fragstrings_list[i], strlen(fragstrings_list[i]));
// try to load the cached shader, or generate one
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)
- Mem_Free(glslshaderstring);
- glslshaderstring = NULL;
- if (hlslshaderstring && hlslshaderstring != builtinhlslshaderstring)
- Mem_Free(hlslshaderstring);
- hlslshaderstring = NULL;
switch(vid.renderpath)
{
case RENDERPATH_D3D9:
{
r_hlsl_permutation_t *p;
r_hlsl_permutation = NULL;
- limit = Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
+ limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray);
for (i = 0;i < limit;i++)
{
if ((p = (r_hlsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_hlsl_permutationarray, i)))
{
r_glsl_permutation_t *p;
r_glsl_permutation = NULL;
- limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+ limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
for (i = 0;i < limit;i++)
{
if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
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 < SHADERLANGUAGE_COUNT;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 = shadermodeinfo[language];
+ 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 = modeinfo[mode].builtinstring;
+ 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);
+ }
}
- 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);
R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
}
-void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb)
+void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
{
unsigned int permutation = 0;
if (r_trippy.integer && !notrippy)
permutation |= SHADERPERMUTATION_TRIPPY;
if (depthrgb)
permutation |= SHADERPERMUTATION_DEPTHRGB;
+ if (skeletal)
+ permutation |= SHADERPERMUTATION_SKELETAL;
+
if (vid.allowalphatocoverage)
GL_AlphaToCoverage(false);
switch (vid.renderpath)
case RENDERPATH_GL20:
case RENDERPATH_GLES2:
R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
+ if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
break;
case RENDERPATH_GL13:
case RENDERPATH_GLES1:
}
}
-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;
extern rtexture_t *r_shadow_attenuation3dtexture;
extern qboolean r_shadow_usingshadowmap2d;
extern qboolean r_shadow_usingshadowmaportho;
-extern float r_shadow_shadowmap_texturescale[2];
-extern float r_shadow_shadowmap_parameters[4];
+extern float r_shadow_modelshadowmap_texturescale[4];
+extern float r_shadow_modelshadowmap_parameters[4];
+extern float r_shadow_lightshadowmap_texturescale[4];
+extern float r_shadow_lightshadowmap_parameters[4];
extern qboolean r_shadow_shadowmapvsdct;
extern rtexture_t *r_shadow_shadowmap2ddepthbuffer;
extern rtexture_t *r_shadow_shadowmap2ddepthtexture;
extern rtexture_t *r_shadow_shadowmapvsdcttexture;
extern matrix4x4_t r_shadow_shadowmapmatrix;
-extern int r_shadow_shadowmaplod; // changes for each light based on distance
extern int r_shadow_prepass_width;
extern int r_shadow_prepass_height;
extern rtexture_t *r_shadow_prepassgeometrydepthbuffer;
permutation |= SHADERPERMUTATION_TRIPPY;
if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
permutation |= SHADERPERMUTATION_ALPHAKILL;
+ if (rsurface.texture->currentmaterialflags & MATERIALFLAG_OCCLUDE)
+ permutation |= SHADERPERMUTATION_OCCLUDE;
if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
if (rsurfacepass == RSURFPASS_BACKGROUND)
permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
if (rsurface.texture->reflectmasktexture)
permutation |= SHADERPERMUTATION_REFLECTCUBE;
- if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
+ if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
{
permutation |= SHADERPERMUTATION_BOUNCEGRID;
- if (r_shadow_bouncegriddirectional)
+ if (r_shadow_bouncegrid_state.directional)
permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
}
GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
if (rsurface.texture->reflectmasktexture)
permutation |= SHADERPERMUTATION_REFLECTCUBE;
- if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
+ if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
{
permutation |= SHADERPERMUTATION_BOUNCEGRID;
- if (r_shadow_bouncegriddirectional)
+ if (r_shadow_bouncegrid_state.directional)
permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
}
GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
// ordinary vertex coloring (q3bsp)
mode = SHADERMODE_VERTEXCOLOR;
}
- if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
+ if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
{
permutation |= SHADERPERMUTATION_BOUNCEGRID;
- if (r_shadow_bouncegriddirectional)
+ if (r_shadow_bouncegrid_state.directional)
permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
}
GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
case RENDERPATH_D3D9:
#ifdef SUPPORTD3D
RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
- R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer);
+ R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
R_SetupShader_SetPermutationHLSL(mode, permutation);
Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);hlslPSSetParameter16f(D3DPSREGISTER_ModelToReflectCube, m16f);
if (mode == SHADERMODE_LIGHTSOURCE)
if (mode == SHADERMODE_WATER)
hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]);
}
- hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+ {
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+ }
+ else
+ {
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+ }
hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
hlslPSSetParameter3f(D3DPSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
+ R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
+ R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
+ R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
}
else
{
- RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
- R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
+ R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
}
+ // this has to be after RSurf_PrepareVerticesForBatch
+ if (rsurface.batchskeletaltransform3x4buffer)
+ permutation |= SHADERPERMUTATION_SKELETAL;
R_SetupShader_SetPermutationGLSL(mode, permutation);
+#ifndef USE_GLES2 /* FIXME: GLES3 only */
+ if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
+#endif
if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
if (mode == SHADERMODE_LIGHTSOURCE)
{
if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
- if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+ {
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+ if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+ }
+ else
+ {
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+ }
if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias);
if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
- if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
- if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegridintensity*r_refdef.view.colorscale);
+ if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
+ if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white );
if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white );
if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture );
}
}
- if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegridtexture);
+ if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
CHECKGLERROR
break;
case RENDERPATH_GL11:
{Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_TexMatrixM1, 1, false, m16f);}
{Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, 1, false, m16f);}
{Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ShadowMapMatrixM1, 1, false, m16f);}
- DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
+ {
+ DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
+ DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
+ }
+ else
+ {
+ DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
+ }
DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]);
DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
GL_AlphaToCoverage(false);
Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
- Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
+ Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
switch(vid.renderpath)
{
hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
- hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height);
if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
- if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f( r_glsl_permutation->loc_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_TextureScale , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_Parameters , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f( r_glsl_permutation->loc_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f( r_glsl_permutation->loc_ScreenToDepth , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height);
DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
- DPSOFTRAST_Uniform2f( DPSOFTRAST_UNIFORM_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
- DPSOFTRAST_Uniform4f( DPSOFTRAST_UNIFORM_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
+ DPSOFTRAST_Uniform4f( DPSOFTRAST_UNIFORM_ShadowMap_TextureScale , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
+ DPSOFTRAST_Uniform4f( DPSOFTRAST_UNIFORM_ShadowMap_Parameters , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
DPSOFTRAST_Uniform1f( DPSOFTRAST_UNIFORM_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
DPSOFTRAST_Uniform2f( DPSOFTRAST_UNIFORM_ScreenToDepth , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
typedef struct
{
- int loadsequence; // incremented each level change
+ unsigned int loadsequence; // incremented each level change
memexpandablearray_t array;
skinframe_t *hash[SKINFRAME_HASH];
}
skinframe->fog = NULL;
skinframe->reflect = NULL;
skinframe->hasalpha = false;
+ // we could store the q2animname here too
if (ddsbase)
{
skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
{
int i;
- unsigned char *temp1, *temp2;
skinframe_t *skinframe;
char vabuf[1024];
if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
{
- temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
- temp2 = temp1 + width * height * 4;
- Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
- skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
- Mem_Free(temp1);
+ unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+ unsigned char *b = a + width * height * 4;
+ Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
+ skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+ Mem_Free(a);
}
skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
if (textureflags & TEXF_ALPHA)
featuresmask |= palette_featureflags[skindata[i]];
skinframe->hasalpha = false;
+ // fence textures
+ if (name[0] == '{')
+ skinframe->hasalpha = true;
skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
skinframe->qgeneratemerged = true;
if (skinframe->qgeneratenmap)
{
- unsigned char *temp1, *temp2;
+ unsigned char *a, *b;
skinframe->qgeneratenmap = false;
- temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
- temp2 = temp1 + width * height * 4;
+ a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+ b = a + width * height * 4;
// use either a custom palette or the quake palette
- Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete);
- Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
- skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
- Mem_Free(temp1);
+ Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
+ Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
+ skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+ Mem_Free(a);
}
if (skinframe->qgenerateglow)
{
skinframe->qgenerateglow = false;
- skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
+ if (skinframe->hasalpha) // fence textures
+ skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
+ else
+ skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
}
if (colormapped)
else
{
skinframe->qgeneratemerged = false;
- skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
+ if (skinframe->hasalpha) // fence textures
+ skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
+ else
+ skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
}
if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
r_texture_fogheighttexture = NULL;
r_texture_gammaramps = NULL;
r_texture_numcubemaps = 0;
+ r_uniformbufferalignment = 32;
r_loaddds = r_texture_dds_load.integer != 0;
r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
r_loadnormalmap = true;
r_loadgloss = true;
r_loadfog = false;
- break;
+#ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
+ if (vid.support.arb_uniform_buffer_object)
+ qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
+#endif
+ break;
case RENDERPATH_GL13:
case RENDERPATH_GLES1:
Cvar_SetValueQuick(&r_textureunits, vid.texunits);
R_AnimCache_Free();
R_FrameData_Reset();
+ R_BufferData_Reset();
r_numqueries = 0;
r_maxqueries = 0;
r_glsl_permutation = NULL;
memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
- glslshaderstring = NULL;
#ifdef SUPPORTD3D
r_hlsl_permutation = NULL;
memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash));
Mem_ExpandableArray_NewArray(&r_hlsl_permutationarray, r_main_mempool, sizeof(r_hlsl_permutation_t), 256);
#endif
- hlslshaderstring = NULL;
memset(&r_svbsp, 0, sizeof (r_svbsp));
memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
r_texture_numcubemaps = 0;
r_refdef.fogmasktable_density = 0;
+
+#ifdef __ANDROID__
+ // For Steelstorm Android
+ // FIXME CACHE the program and reload
+ // FIXME see possible combinations for SS:BR android
+ Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
+ R_SetupShader_SetPermutationGLSL(0, 12);
+ R_SetupShader_SetPermutationGLSL(0, 13);
+ R_SetupShader_SetPermutationGLSL(0, 8388621);
+ R_SetupShader_SetPermutationGLSL(3, 0);
+ R_SetupShader_SetPermutationGLSL(3, 2048);
+ R_SetupShader_SetPermutationGLSL(5, 0);
+ R_SetupShader_SetPermutationGLSL(5, 2);
+ R_SetupShader_SetPermutationGLSL(5, 2048);
+ R_SetupShader_SetPermutationGLSL(5, 8388608);
+ R_SetupShader_SetPermutationGLSL(11, 1);
+ R_SetupShader_SetPermutationGLSL(11, 2049);
+ R_SetupShader_SetPermutationGLSL(11, 8193);
+ R_SetupShader_SetPermutationGLSL(11, 10241);
+ Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
+#endif
}
static void gl_main_shutdown(void)
{
R_AnimCache_Free();
R_FrameData_Reset();
+ R_BufferData_Reset();
R_Main_FreeViewCache();
case RENDERPATH_GL20:
case RENDERPATH_GLES1:
case RENDERPATH_GLES2:
-#ifdef GL_SAMPLES_PASSED_ARB
+#if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
if (r_maxqueries)
qglDeleteQueriesARB(r_maxqueries, r_queries);
#endif
r_glsl_permutation = NULL;
memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
- glslshaderstring = NULL;
#ifdef SUPPORTD3D
r_hlsl_permutation = NULL;
memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash));
Mem_ExpandableArray_FreeArray(&r_hlsl_permutationarray);
#endif
- hlslshaderstring = NULL;
}
static void gl_main_newmap(void)
R_Main_FreeViewCache();
R_FrameData_Reset();
+ R_BufferData_Reset();
}
void GL_Main_Init(void)
{
+ int i;
r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
+ R_InitShaderModeInfo();
Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
Cvar_RegisterVariable(&r_celoutlines);
Cvar_RegisterVariable(&r_water);
+ Cvar_RegisterVariable(&r_water_cameraentitiesonly);
Cvar_RegisterVariable(&r_water_resolutionmultiplier);
Cvar_RegisterVariable(&r_water_clippingplanebias);
Cvar_RegisterVariable(&r_water_refractdistort);
Cvar_RegisterVariable(&r_test);
Cvar_RegisterVariable(&r_batch_multidraw);
Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
+ Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
+ Cvar_RegisterVariable(&r_glsl_skeletal);
Cvar_RegisterVariable(&r_glsl_saturation);
Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
Cvar_RegisterVariable(&r_framedatasize);
+ for (i = 0;i < R_BUFFERDATA_COUNT;i++)
+ Cvar_RegisterVariable(&r_buffermegs[i]);
+ Cvar_RegisterVariable(&r_batch_dynamicbuffer);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
+#ifdef DP_MOBILETOUCH
+ // GLES devices have terrible depth precision in general, so...
+ Cvar_SetValueQuick(&r_nearclip, 4);
+ Cvar_SetValueQuick(&r_farclip_base, 4096);
+ Cvar_SetValueQuick(&r_farclip_world, 0);
+ Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
+#endif
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
}
VID_CheckExtensions();
// LordHavoc: report supported extensions
+#ifdef CONFIG_MENU
Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
+#else
+ Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
+#endif
// clear to black (loading plaque will be seen over this)
GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
return false;
for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
{
- // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
- if (i == 4)
- continue;
p = r_refdef.view.frustum + i;
switch(p->signbits)
{
}
}
-static void R_FrameData_Resize(void)
+static void R_FrameData_Resize(qboolean mustgrow)
{
size_t wantedsize;
wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
wantedsize = bound(65536, wantedsize, 1000*1024*1024);
- if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize)
+ if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
{
r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
newmem->wantedsize = wantedsize;
void R_FrameData_NewFrame(void)
{
- R_FrameData_Resize();
+ R_FrameData_Resize(false);
if (!r_framedata_mem)
return;
// if we ran out of space on the last frame, free the old memory now
void *R_FrameData_Alloc(size_t size)
{
void *data;
+ float newvalue;
// align to 16 byte boundary - the data pointer is already aligned, so we
// only need to ensure the size of every allocation is also aligned
while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
{
// emergency - we ran out of space, allocate more memory
- Cvar_SetValueQuick(&r_framedatasize, bound(0.25f, r_framedatasize.value * 2.0f, 128.0f));
- R_FrameData_Resize();
+ // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
+ newvalue = r_framedatasize.value * 2.0f;
+ // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
+ if (sizeof(size_t) >= 8)
+ newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
+ else
+ newvalue = bound(0.25f, newvalue, (float)(1 << 10));
+ // this might not be a growing it, but we'll allocate another buffer every time
+ Cvar_SetValueQuick(&r_framedatasize, newvalue);
+ R_FrameData_Resize(true);
}
data = r_framedata_mem->data + r_framedata_mem->current;
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;
}
//==================================================================================
+// avoid reusing the same buffer objects on consecutive frames
+#define R_BUFFERDATA_CYCLE 3
+
+typedef struct r_bufferdata_buffer_s
+{
+ struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
+ size_t size; // how much usable space
+ size_t current; // how much space in use
+ r_meshbuffer_t *buffer; // the buffer itself
+}
+r_bufferdata_buffer_t;
+
+static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
+static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
+
+/// frees all dynamic buffers
+void R_BufferData_Reset(void)
+{
+ int cycle, type;
+ r_bufferdata_buffer_t **p, *mem;
+ for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
+ {
+ for (type = 0;type < R_BUFFERDATA_COUNT;type++)
+ {
+ // free all buffers
+ p = &r_bufferdata_buffer[cycle][type];
+ while (*p)
+ {
+ mem = *p;
+ *p = (*p)->purge;
+ if (mem->buffer)
+ R_Mesh_DestroyMeshBuffer(mem->buffer);
+ Mem_Free(mem);
+ }
+ }
+ }
+}
+
+// resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
+static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
+{
+ r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
+ size_t size;
+ float newvalue = r_buffermegs[type].value;
+
+ // increase the cvar if we have to (but only if we already have a mem)
+ if (mustgrow && mem)
+ newvalue *= 2.0f;
+ newvalue = bound(0.25f, newvalue, 256.0f);
+ while (newvalue * 1024*1024 < minsize)
+ newvalue *= 2.0f;
+
+ // clamp the cvar to valid range
+ newvalue = bound(0.25f, newvalue, 256.0f);
+ if (r_buffermegs[type].value != newvalue)
+ Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
+
+ // calculate size in bytes
+ size = (size_t)(newvalue * 1024*1024);
+ size = bound(131072, size, 256*1024*1024);
+
+ // allocate a new buffer if the size is different (purge old one later)
+ // or if we were told we must grow the buffer
+ if (!mem || mem->size != size || mustgrow)
+ {
+ mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
+ mem->size = size;
+ mem->current = 0;
+ if (type == R_BUFFERDATA_VERTEX)
+ mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
+ else if (type == R_BUFFERDATA_INDEX16)
+ mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
+ else if (type == R_BUFFERDATA_INDEX32)
+ mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
+ else if (type == R_BUFFERDATA_UNIFORM)
+ mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
+ mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
+ r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
+ }
+}
+
+void R_BufferData_NewFrame(void)
+{
+ int type;
+ r_bufferdata_buffer_t **p, *mem;
+ // cycle to the next frame's buffers
+ r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
+ // if we ran out of space on the last time we used these buffers, free the old memory now
+ for (type = 0;type < R_BUFFERDATA_COUNT;type++)
+ {
+ if (r_bufferdata_buffer[r_bufferdata_cycle][type])
+ {
+ R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
+ // free all but the head buffer, this is how we recycle obsolete
+ // buffers after they are no longer in use
+ p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
+ while (*p)
+ {
+ mem = *p;
+ *p = (*p)->purge;
+ if (mem->buffer)
+ R_Mesh_DestroyMeshBuffer(mem->buffer);
+ Mem_Free(mem);
+ }
+ // reset the current offset
+ r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
+ }
+ }
+}
+
+r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
+{
+ r_bufferdata_buffer_t *mem;
+ int offset = 0;
+ int padsize;
+
+ *returnbufferoffset = 0;
+
+ // align size to a byte boundary appropriate for the buffer type, this
+ // makes all allocations have aligned start offsets
+ if (type == R_BUFFERDATA_UNIFORM)
+ padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
+ else
+ padsize = (datasize + 15) & ~15;
+
+ // if we ran out of space in this buffer we must allocate a new one
+ if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+ R_BufferData_Resize(type, true, padsize);
+
+ // if the resize did not give us enough memory, fail
+ if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
+ Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
+
+ mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
+ offset = (int)mem->current;
+ mem->current += padsize;
+
+ // upload the data to the buffer at the chosen offset
+ if (offset == 0)
+ R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
+ R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
+
+ // count the usage for stats
+ r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
+ r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
+
+ // return the buffer offset
+ *returnbufferoffset = offset;
+
+ return mem->buffer;
+}
+
+//==================================================================================
+
// LordHavoc: animcache originally written by Echon, rewritten since then
/**
{
ent = r_refdef.scene.entities[i];
ent->animcache_vertex3f = NULL;
+ ent->animcache_vertex3f_vertexbuffer = NULL;
+ ent->animcache_vertex3f_bufferoffset = 0;
ent->animcache_normal3f = NULL;
+ ent->animcache_normal3f_vertexbuffer = NULL;
+ ent->animcache_normal3f_bufferoffset = 0;
ent->animcache_svector3f = NULL;
+ ent->animcache_svector3f_vertexbuffer = NULL;
+ ent->animcache_svector3f_bufferoffset = 0;
ent->animcache_tvector3f = NULL;
+ ent->animcache_tvector3f_vertexbuffer = NULL;
+ ent->animcache_tvector3f_bufferoffset = 0;
ent->animcache_vertexmesh = NULL;
- ent->animcache_vertex3fbuffer = NULL;
- ent->animcache_vertexmeshbuffer = NULL;
+ ent->animcache_vertexmesh_vertexbuffer = NULL;
+ ent->animcache_vertexmesh_bufferoffset = 0;
+ ent->animcache_skeletaltransform3x4 = NULL;
+ ent->animcache_skeletaltransform3x4buffer = NULL;
+ ent->animcache_skeletaltransform3x4offset = 0;
+ ent->animcache_skeletaltransform3x4size = 0;
}
}
if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
- // TODO: upload vertex3f buffer?
+ // TODO: upload vertexbuffer?
if (ent->animcache_vertexmesh)
{
- memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
+ 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.data_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]));
if (ent->animcache_svector3f)
if (ent->animcache_normal3f)
for (i = 0;i < numvertices;i++)
memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
- // TODO: upload vertexmeshbuffer?
}
}
{
dp_model_t *model = ent->model;
int numvertices;
- // see if it's already cached this frame
+
+ // 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)
{
- // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc)
+ // 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
+ 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);
+ Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
+ // note: this can fail if the buffer is at the grow limit
+ ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
+ ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
+ }
+ else if (ent->animcache_vertex3f)
+ {
+ // 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;
- // 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;
}
int samples;
entity_render_t *ent;
- renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
- : r_fb.water.hideplayer ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
- : (chase_active.integer || r_fb.water.renderingscene) ? RENDER_VIEWMODEL
- : RENDER_EXTERIORMODEL;
+ if (r_refdef.envmap || r_fb.water.hideplayer)
+ renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
+ else if (chase_active.integer || r_fb.water.renderingscene)
+ renderimask = RENDER_VIEWMODEL;
+ else
+ renderimask = RENDER_EXTERIORMODEL;
if (!r_drawviewmodel.integer)
renderimask |= RENDER_VIEWMODEL;
if (!r_drawexteriormodel.integer)
renderimask |= RENDER_EXTERIORMODEL;
+ memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
{
// worldmodel can check visibility
- memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
for (i = 0;i < r_refdef.scene.numentities;i++)
{
ent = r_refdef.scene.entities[i];
for (i = 0;i < r_refdef.scene.numentities;i++)
{
ent = r_refdef.scene.entities[i];
- r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
+ if (!(ent->flags & renderimask))
+ if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
+ r_refdef.viewcache.entityvisible[i] = true;
}
}
- if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
+ if(r_cullentities_trace.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
// sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling
{
for (i = 0;i < r_refdef.scene.numentities;i++)
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))
{
case RENDERPATH_GL11:
case RENDERPATH_GL13:
case RENDERPATH_GLES1:
+#ifndef USE_GLES2
qglLoadMatrixf(gl_modelview16f);CHECKGLERROR
+#endif
break;
case RENDERPATH_SOFT:
DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f);
Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
VectorNegate(r_refdef.view.left, r_refdef.view.right);
// make an inverted copy of the view matrix for tracking sprites
- Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
+ Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
}
void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture);
}
else
{
- for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
- for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
- for (camerawidth = 1;camerawidth <= waterwidth; camerawidth *= 2); camerawidth /= 2;
- for (cameraheight = 1;cameraheight <= waterheight;cameraheight *= 2); cameraheight /= 2;
+ for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
+ for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
+ for (camerawidth = 1;camerawidth * 2 <= waterwidth ;camerawidth *= 2);
+ for (cameraheight = 1;cameraheight * 2 <= waterheight;cameraheight *= 2);
}
// allocate textures as needed
}
}
planeindex = bestplaneindex;
- p = r_fb.water.waterplanes + planeindex;
// if this surface does not fit any known plane rendered this frame, add one
- if ((planeindex < 0 || bestplanescore > 0.001f) && r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+ if (planeindex < 0 || bestplanescore > 0.001f)
{
- // store the new plane
- planeindex = r_fb.water.numwaterplanes++;
- p = r_fb.water.waterplanes + planeindex;
- p->plane = plane;
- // clear materialflags and pvs
- p->materialflags = 0;
- p->pvsvalid = false;
- p->camera_entity = t->camera_entity;
- VectorCopy(mins, p->mins);
- VectorCopy(maxs, p->maxs);
+ if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
+ {
+ // store the new plane
+ planeindex = r_fb.water.numwaterplanes++;
+ p = r_fb.water.waterplanes + planeindex;
+ p->plane = plane;
+ // clear materialflags and pvs
+ p->materialflags = 0;
+ p->pvsvalid = false;
+ p->camera_entity = t->camera_entity;
+ VectorCopy(mins, p->mins);
+ VectorCopy(maxs, p->maxs);
+ }
+ else
+ {
+ // We're totally screwed.
+ return;
+ }
}
else
{
// merge mins/maxs when we're adding this surface to the plane
+ p = r_fb.water.waterplanes + planeindex;
p->mins[0] = min(p->mins[0], mins[0]);
p->mins[1] = min(p->mins[1], mins[1]);
p->mins[2] = min(p->mins[2], mins[2]);
if(!(p->materialflags & MATERIALFLAG_CAMERA))
{
// merge this surface's PVS into the waterplane
- if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
+ if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
&& r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
{
r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
// make sure enough textures are allocated
for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
{
+ if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
+ continue;
if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
{
if (!p->texture_refraction)
r_fb.water.renderingscene = true;
for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
{
+ if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
+ continue;
if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
{
r_refdef.view = myview;
memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
}
- r_fb.water.hideplayer = r_water_hideplayer.integer >= 2;
+ r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
R_ResetViewRendering3D(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection);
R_ClearScreen(r_refdef.fogenabled);
if(r_water_scissormode.integer & 2)
continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible
}
- r_fb.water.hideplayer = r_water_hideplayer.integer >= 1;
+ r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
r_refdef.view.clipplane = p->plane;
VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
Cvar_SetValueQuick(&r_damageblur, 0);
}
- if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
+ if (!((r_glsl_postprocess.integer || r_fxaa.integer) || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))
&& !r_bloom.integer
&& (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0))
&& !useviewfbo
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 = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
case RENDERPATH_D3D9:
case RENDERPATH_D3D10:
case RENDERPATH_D3D11:
R_SortEntities();
R_AnimCache_ClearCache();
- R_FrameData_NewFrame();
/* adjust for stereo display */
if(R_Stereo_Active())
static void R_DrawModelDecals(void);
extern cvar_t cl_decals_newsystem;
extern qboolean r_shadow_usingdeferredprepass;
+extern int r_shadow_shadowmapatlas_modelshadows_size;
void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
{
qboolean shadowmapping = false;
if (r_timereport_active)
R_TimeReport("beginscene");
- r_refdef.stats.renders++;
+ r_refdef.stats[r_stat_renders]++;
R_UpdateFog();
}
}
+ R_Shadow_PrepareModelShadows();
R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
- if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
- R_Shadow_PrepareModelShadows();
if (r_timereport_active)
R_TimeReport("preparelights");
- if (R_Shadow_ShadowMappingEnabled())
- shadowmapping = true;
+ // render all the shadowmaps that will be used for this view
+ shadowmapping = R_Shadow_ShadowMappingEnabled();
+ if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
+ {
+ R_Shadow_DrawShadowMaps();
+ if (r_timereport_active)
+ R_TimeReport("shadowmaps");
+ }
+ // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
if (r_shadow_usingdeferredprepass)
R_Shadow_DrawPrepass();
+ // now we begin the forward pass of the view render
if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
{
r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
R_TimeReport("modeldepth");
}
- if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0)
- {
- R_ResetViewRendering3D(fbo, depthtexture, colortexture);
- R_DrawModelShadowMaps(fbo, depthtexture, colortexture);
- R_ResetViewRendering3D(fbo, depthtexture, colortexture);
- // don't let sound skip if going slow
- if (r_refdef.scene.extraupdate)
- S_ExtraUpdate ();
- }
-
if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
{
r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
{
R_ResetViewRendering3D(fbo, depthtexture, colortexture);
- R_DrawModelShadows(fbo, depthtexture, colortexture);
+ R_Shadow_DrawModelShadows();
R_ResetViewRendering3D(fbo, depthtexture, colortexture);
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
{
R_ResetViewRendering3D(fbo, depthtexture, colortexture);
- R_DrawModelShadows(fbo, depthtexture, colortexture);
+ R_Shadow_DrawModelShadows();
R_ResetViewRendering3D(fbo, depthtexture, colortexture);
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
{
int w, h, idx;
- double f;
- double offsetd[2];
+ float shadertime;
+ float f;
+ float offsetd[2];
float tcmat[12];
matrix4x4_t matrix, temp;
+ // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
+ // it's better to have one huge fixup every 9 hours than gradual
+ // degradation over time which looks consistently bad after many hours.
+ //
+ // tcmod scroll in particular suffers from this degradation which can't be
+ // effectively worked around even with floor() tricks because we don't
+ // know if tcmod scroll is the last tcmod being applied, and for clampmap
+ // a workaround involving floor() would be incorrect anyway...
+ shadertime = rsurface.shadertime;
+ if (shadertime >= 32768.0f)
+ shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
switch(tcmod->tcmod)
{
case Q3TCMOD_COUNT:
Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
break;
case Q3TCMOD_ROTATE:
- f = tcmod->parms[0] * rsurface.shadertime;
Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
- Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1);
+ Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
break;
case Q3TCMOD_SCALE:
Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
break;
case Q3TCMOD_SCROLL:
- // extra care is needed because of precision breakdown with large values of time
+ // this particular tcmod is a "bug for bug" compatible one with regards to
+ // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
+ // specifically did the wrapping and so we must mimic that...
offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
{
// use an alternate animation if the entity's frame is not 0,
// and only if the texture has an alternate animation
- if (rsurface.ent_alttextures && t->anim_total[1])
+ if (t->animated == 2) // q2bsp
+ t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
+ else if (rsurface.ent_alttextures && t->anim_total[1])
t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
else
t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
t->currentskinframe = r_qwskincache[i].skinframe;
- if (t->currentskinframe == NULL)
- t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
+ if (t->materialshaderpass && t->currentskinframe == NULL)
+ t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
}
- else if (t->numskinframes >= 2)
- t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
- if (t->backgroundnumskinframes >= 2)
- t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)];
+ else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
+ t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
+ if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
+ t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
t->currentmaterialflags = t->basematerialflags;
- t->currentalpha = rsurface.colormod[3];
+ t->currentalpha = rsurface.colormod[3] * t->basealpha;
if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
t->currentalpha *= r_wateralpha.value;
if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
- if (t->backgroundnumskinframes)
+ if (t->backgroundshaderpass)
t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
{
Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
}
- for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
- R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
- for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
- R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
+ if (t->materialshaderpass)
+ for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
if (t->currentskinframe->qpixels)
t->glowtexture = t->currentskinframe->glow;
t->fogtexture = t->currentskinframe->fog;
t->reflectmasktexture = t->currentskinframe->reflect;
- if (t->backgroundnumskinframes)
+ if (t->backgroundshaderpass)
{
+ for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
t->backgroundglosstexture = r_texture_black;
}
}
- return t->currentframe;
+ return t;
}
rsurfacestate_t rsurface;
rsurface.ent_alttextures = false;
rsurface.basepolygonfactor = r_refdef.polygonfactor;
rsurface.basepolygonoffset = r_refdef.polygonoffset;
+ rsurface.entityskeletaltransform3x4 = NULL;
+ rsurface.entityskeletaltransform3x4buffer = NULL;
+ rsurface.entityskeletaltransform3x4offset = 0;
+ rsurface.entityskeletaltransform3x4size = 0;;
+ rsurface.entityskeletalnumtransforms = 0;
rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
+ rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
+ rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
+ rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
+ rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
rsurface.modelelement3i = model->surfmesh.data_element3i;
rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
rsurface.modelnumvertices = model->surfmesh.num_vertices;
rsurface.modelnumtriangles = model->surfmesh.num_triangles;
rsurface.modelsurfaces = model->data_surfaces;
- rsurface.modelvertexmesh = model->surfmesh.vertexmesh;
- rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer;
- rsurface.modelvertex3fbuffer = model->surfmesh.vertex3fbuffer;
+ rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
+ rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
rsurface.modelgeneratedvertex = false;
rsurface.batchgeneratedvertex = false;
rsurface.batchfirstvertex = 0;
rsurface.batchtexcoordlightmap2f = NULL;
rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
+ rsurface.batchskeletalindex4ub = NULL;
+ rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalindex4ub_bufferoffset = 0;
+ rsurface.batchskeletalweight4ub = NULL;
+ rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalweight4ub_bufferoffset = 0;
rsurface.batchvertexmesh = NULL;
- rsurface.batchvertexmeshbuffer = NULL;
- rsurface.batchvertex3fbuffer = NULL;
+ rsurface.batchvertexmesh_vertexbuffer = NULL;
+ rsurface.batchvertexmesh_bufferoffset = 0;
rsurface.batchelement3i = NULL;
rsurface.batchelement3i_indexbuffer = NULL;
rsurface.batchelement3i_bufferoffset = 0;
rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
}
- if (model->surfmesh.isanimated && model->AnimateVertices)
+ // if the animcache code decided it should use the shader path, skip the deform step
+ rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
+ rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
+ rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
+ rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
+ rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
+ if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
{
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.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
+ rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
+ rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
+ rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
+ rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
+ rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
+ rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
+ rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
rsurface.modelvertexmesh = ent->animcache_vertexmesh;
- rsurface.modelvertexmeshbuffer = ent->animcache_vertexmeshbuffer;
- rsurface.modelvertex3fbuffer = ent->animcache_vertex3fbuffer;
+ rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
+ rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
}
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]));
rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
rsurface.modelvertexmesh = NULL;
- rsurface.modelvertexmeshbuffer = NULL;
- rsurface.modelvertex3fbuffer = NULL;
+ rsurface.modelvertexmesh_vertexbuffer = NULL;
+ rsurface.modelvertexmesh_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = NULL;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = 0;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelsvector3f_vertexbuffer = 0;
+ rsurface.modelsvector3f_bufferoffset = 0;
+ rsurface.modeltvector3f_vertexbuffer = 0;
+ rsurface.modeltvector3f_bufferoffset = 0;
+ rsurface.modelnormal3f_vertexbuffer = 0;
+ rsurface.modelnormal3f_bufferoffset = 0;
}
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;
rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
rsurface.modelvertexmesh = NULL;
- rsurface.modelvertexmeshbuffer = NULL;
- rsurface.modelvertex3fbuffer = NULL;
+ rsurface.modelvertexmesh_vertexbuffer = NULL;
+ rsurface.modelvertexmesh_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = NULL;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = 0;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelsvector3f_vertexbuffer = 0;
+ rsurface.modelsvector3f_bufferoffset = 0;
+ rsurface.modeltvector3f_vertexbuffer = 0;
+ rsurface.modeltvector3f_bufferoffset = 0;
+ rsurface.modelnormal3f_vertexbuffer = 0;
+ rsurface.modelnormal3f_bufferoffset = 0;
}
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;
rsurface.modelnormal3f = NULL;
model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
rsurface.modelvertexmesh = NULL;
- rsurface.modelvertexmeshbuffer = NULL;
- rsurface.modelvertex3fbuffer = NULL;
- }
- rsurface.modelvertex3f_vertexbuffer = 0;
- rsurface.modelvertex3f_bufferoffset = 0;
- rsurface.modelsvector3f_vertexbuffer = 0;
- rsurface.modelsvector3f_bufferoffset = 0;
- rsurface.modeltvector3f_vertexbuffer = 0;
- rsurface.modeltvector3f_bufferoffset = 0;
- rsurface.modelnormal3f_vertexbuffer = 0;
- rsurface.modelnormal3f_bufferoffset = 0;
+ rsurface.modelvertexmesh_vertexbuffer = NULL;
+ rsurface.modelvertexmesh_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = NULL;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelvertex3f_vertexbuffer = 0;
+ rsurface.modelvertex3f_bufferoffset = 0;
+ rsurface.modelsvector3f_vertexbuffer = 0;
+ rsurface.modelsvector3f_bufferoffset = 0;
+ rsurface.modeltvector3f_vertexbuffer = 0;
+ rsurface.modeltvector3f_bufferoffset = 0;
+ rsurface.modelnormal3f_vertexbuffer = 0;
+ rsurface.modelnormal3f_bufferoffset = 0;
+ }
rsurface.modelgeneratedvertex = true;
}
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.modelnormal3f = model->surfmesh.data_normal3f;
rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
- rsurface.modelvertexmesh = model->surfmesh.vertexmesh;
- rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer;
- rsurface.modelvertex3fbuffer = model->surfmesh.vertex3fbuffer;
+ rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
+ rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
rsurface.modelgeneratedvertex = false;
}
rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
+ rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
+ rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
+ rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
+ rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
+ rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
rsurface.modelelement3i = model->surfmesh.data_element3i;
rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
rsurface.batchtexcoordlightmap2f = NULL;
rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
+ rsurface.batchskeletalindex4ub = NULL;
+ rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalindex4ub_bufferoffset = 0;
+ rsurface.batchskeletalweight4ub = NULL;
+ rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalweight4ub_bufferoffset = 0;
rsurface.batchvertexmesh = NULL;
- rsurface.batchvertexmeshbuffer = NULL;
- rsurface.batchvertex3fbuffer = NULL;
+ rsurface.batchvertexmesh_vertexbuffer = NULL;
+ rsurface.batchvertexmesh_bufferoffset = 0;
rsurface.batchelement3i = NULL;
rsurface.batchelement3i_indexbuffer = NULL;
rsurface.batchelement3i_bufferoffset = 0;
rsurface.ent_alttextures = false;
rsurface.basepolygonfactor = r_refdef.polygonfactor;
rsurface.basepolygonoffset = r_refdef.polygonoffset;
+ rsurface.entityskeletaltransform3x4 = NULL;
+ rsurface.entityskeletaltransform3x4buffer = NULL;
+ rsurface.entityskeletaltransform3x4offset = 0;
+ rsurface.entityskeletaltransform3x4size = 0;
+ 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;
rsurface.modelnormal3f = NULL;
}
rsurface.modelvertexmesh = NULL;
- rsurface.modelvertexmeshbuffer = NULL;
- rsurface.modelvertex3fbuffer = NULL;
+ rsurface.modelvertexmesh_vertexbuffer = NULL;
+ rsurface.modelvertexmesh_bufferoffset = 0;
rsurface.modelvertex3f_vertexbuffer = 0;
rsurface.modelvertex3f_bufferoffset = 0;
rsurface.modelsvector3f_vertexbuffer = 0;
rsurface.modeltexcoordlightmap2f = NULL;
rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
+ rsurface.modelskeletalindex4ub = NULL;
+ rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
+ rsurface.modelskeletalindex4ub_bufferoffset = 0;
+ rsurface.modelskeletalweight4ub = NULL;
+ rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
+ rsurface.modelskeletalweight4ub_bufferoffset = 0;
rsurface.modelelement3i = (int *)element3i;
rsurface.modelelement3i_indexbuffer = NULL;
rsurface.modelelement3i_bufferoffset = 0;
rsurface.batchtexcoordlightmap2f = NULL;
rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
+ rsurface.batchskeletalindex4ub = NULL;
+ rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalindex4ub_bufferoffset = 0;
+ rsurface.batchskeletalweight4ub = NULL;
+ rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalweight4ub_bufferoffset = 0;
rsurface.batchvertexmesh = NULL;
- rsurface.batchvertexmeshbuffer = NULL;
- rsurface.batchvertex3fbuffer = NULL;
+ rsurface.batchvertexmesh_vertexbuffer = NULL;
+ rsurface.batchvertexmesh_bufferoffset = 0;
rsurface.batchelement3i = NULL;
rsurface.batchelement3i_indexbuffer = NULL;
rsurface.batchelement3i_bufferoffset = 0;
int surfacefirstvertex;
int surfaceendvertex;
int surfacenumvertices;
+ int batchnumsurfaces = texturenumsurfaces;
int batchnumvertices;
int batchnumtriangles;
int needsupdate;
qboolean dynamicvertex;
float amplitude;
float animpos;
- float scale;
float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
float waveparms[4];
+ unsigned char *ub;
q3shaderinfo_deform_t *deform;
const msurface_t *surface, *firstsurface;
r_vertexmesh_t *vertexmesh;
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;
// check if any dynamic vertex processing must occur
dynamicvertex = false;
+ // 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;
- batchneed |= BATCHNEED_NOGAPS;
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 | BATCHNEED_NOGAPS;
+ 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 | BATCHNEED_NOGAPS;
+ 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 | BATCHNEED_NOGAPS;
+ batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
break;
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 | BATCHNEED_NOGAPS;
+ 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 | BATCHNEED_NOGAPS;
+ batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
break;
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 | BATCHNEED_NOGAPS;
+ batchneed |= BATCHNEED_ARRAY_VERTEX;
needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
break;
}
}
- switch(rsurface.texture->tcgen.tcgen)
+ if (rsurface.texture->materialshaderpass)
{
- default:
- case Q3TCGEN_TEXTURE:
- break;
- case Q3TCGEN_LIGHTMAP:
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_LIGHTMAP | BATCHNEED_NOGAPS;
- needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
- break;
- case Q3TCGEN_VECTOR:
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
- break;
- case Q3TCGEN_ENVIRONMENT:
- dynamicvertex = true;
- batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
- break;
+ switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
+ {
+ default:
+ 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;
+ break;
+ }
+ if (rsurface.texture->materialshaderpass->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.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
+
+ 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;
- batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS;
- needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
+ needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
}
- if (!rsurface.modelvertexmesh && (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.modelvertexmesh_vertexbuffer)
+ 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;
- batchneed |= BATCHNEED_NOGAPS;
- needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
}
- if (dynamicvertex || gaps || rsurface.batchfirstvertex)
+ if (dynamicvertex)
{
// when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX;
if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD;
if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
+ if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL;
}
- // when the model data has no vertex buffer (dynamic mesh), we need to
- // eliminate gaps
- if (vid.useinterleavedarrays ? !rsurface.modelvertexmeshbuffer : !rsurface.modelvertex3f_vertexbuffer)
- batchneed |= BATCHNEED_NOGAPS;
-
// 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 gaps are unacceptable, and there are gaps, it's a dynamic batch...
- // also some drivers strongly dislike firstvertex
- if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex))
- 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)
+ batchneed |= BATCHNEED_ARRAY_SKELETAL;
rsurface.batchvertex3f = rsurface.modelvertex3f;
rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
- rsurface.batchvertex3fbuffer = rsurface.modelvertex3fbuffer;
+ rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
+ rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
+ rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
+ rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
+ rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
+ rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
rsurface.batchvertexmesh = rsurface.modelvertexmesh;
- rsurface.batchvertexmeshbuffer = rsurface.modelvertexmeshbuffer;
+ rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
+ rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
rsurface.batchelement3i = rsurface.modelelement3i;
rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
rsurface.batchelement3s = rsurface.modelelement3s;
rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
+ rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
+ rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
+ rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
+ rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
+ rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
// if any dynamic vertex processing has to occur in software, we copy the
// entire surface list together before processing to rebase the vertices
// 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;
for (i = 0;i < numtriangles*3;i++)
rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
}
+ // upload buffer data for the copytriangles batch
+ if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
+ {
+ if (rsurface.batchelement3s)
+ rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
+ else if (rsurface.batchelement3i)
+ rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
+ }
+ }
+ 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)
- //if (gaps || rsurface.batchfirstvertex)
+ // we also apply any skeletal animation here that would have been done in
+ // the vertex shader, because most of the dynamic vertex animation cases
+ // need actual vertex positions and normals
+ //if (dynamicvertex)
{
- rsurface.batchvertex3fbuffer = NULL;
rsurface.batchvertexmesh = NULL;
- rsurface.batchvertexmeshbuffer = NULL;
+ rsurface.batchvertexmesh_vertexbuffer = NULL;
+ rsurface.batchvertexmesh_bufferoffset = 0;
rsurface.batchvertex3f = NULL;
rsurface.batchvertex3f_vertexbuffer = NULL;
rsurface.batchvertex3f_bufferoffset = 0;
rsurface.batchtexcoordlightmap2f = NULL;
rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
+ rsurface.batchskeletalindex4ub = NULL;
+ rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalindex4ub_bufferoffset = 0;
+ rsurface.batchskeletalweight4ub = NULL;
+ rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
+ rsurface.batchskeletalweight4ub_bufferoffset = 0;
rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
rsurface.batchelement3i_indexbuffer = NULL;
rsurface.batchelement3i_bufferoffset = 0;
rsurface.batchelement3s = NULL;
rsurface.batchelement3s_indexbuffer = NULL;
rsurface.batchelement3s_bufferoffset = 0;
+ rsurface.batchskeletaltransform3x4buffer = NULL;
+ rsurface.batchskeletaltransform3x4offset = 0;
+ rsurface.batchskeletaltransform3x4size = 0;
// we'll only be setting up certain arrays as needed
if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+ if (batchneed & BATCHNEED_ARRAY_SKELETAL)
+ {
+ rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
+ rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
+ }
numvertices = 0;
numtriangles = 0;
for (i = 0;i < texturenumsurfaces;i++)
else
memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
}
+ if (batchneed & BATCHNEED_ARRAY_SKELETAL)
+ {
+ if (rsurface.modelskeletalindex4ub)
+ {
+ memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
+ memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
+ }
+ else
+ {
+ memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
+ memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
+ ub = rsurface.batchskeletalweight4ub + 4*numvertices;
+ for (j = 0;j < surfacenumvertices;j++)
+ ub[j*4] = 255;
+ }
+ }
}
RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
numvertices += surfacenumvertices;
rsurface.batchnumtriangles = batchnumtriangles;
}
+ // apply skeletal animation that would have been done in the vertex shader
+ if (rsurface.batchskeletaltransform3x4)
+ {
+ const unsigned char *si;
+ const unsigned char *sw;
+ const float *t[4];
+ const float *b = rsurface.batchskeletaltransform3x4;
+ float *vp, *vs, *vt, *vn;
+ 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;
+ vs = rsurface.batchsvector3f;
+ vt = rsurface.batchtvector3f;
+ vn = rsurface.batchnormal3f;
+ memset(m[0], 0, sizeof(m));
+ memset(n[0], 0, sizeof(n));
+ for (i = 0;i < batchnumvertices;i++)
+ {
+ t[0] = b + si[0]*12;
+ if (sw[0] == 255)
+ {
+ // common case - only one matrix
+ m[0][0] = t[0][ 0];
+ m[0][1] = t[0][ 1];
+ m[0][2] = t[0][ 2];
+ m[0][3] = t[0][ 3];
+ m[1][0] = t[0][ 4];
+ m[1][1] = t[0][ 5];
+ m[1][2] = t[0][ 6];
+ m[1][3] = t[0][ 7];
+ m[2][0] = t[0][ 8];
+ m[2][1] = t[0][ 9];
+ m[2][2] = t[0][10];
+ m[2][3] = t[0][11];
+ }
+ else if (sw[2] + sw[3])
+ {
+ // blend 4 matrices
+ t[1] = b + si[1]*12;
+ t[2] = b + si[2]*12;
+ t[3] = b + si[3]*12;
+ w[0] = sw[0] * (1.0f / 255.0f);
+ w[1] = sw[1] * (1.0f / 255.0f);
+ w[2] = sw[2] * (1.0f / 255.0f);
+ w[3] = sw[3] * (1.0f / 255.0f);
+ // blend the matrices
+ m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
+ m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
+ m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
+ m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
+ m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
+ m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
+ m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
+ m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
+ m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
+ m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
+ m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
+ m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
+ }
+ else
+ {
+ // blend 2 matrices
+ t[1] = b + si[1]*12;
+ w[0] = sw[0] * (1.0f / 255.0f);
+ w[1] = sw[1] * (1.0f / 255.0f);
+ // blend the matrices
+ m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
+ m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
+ m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
+ m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
+ m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
+ m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
+ m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
+ m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
+ m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
+ m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
+ m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
+ m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
+ }
+ si += 4;
+ sw += 4;
+ // modify the vertex
+ VectorCopy(vp, tp);
+ vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
+ vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
+ vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
+ vp += 3;
+ if (vn)
+ {
+ // the normal transformation matrix is a set of cross products...
+ CrossProduct(m[1], m[2], n[0]);
+ CrossProduct(m[2], m[0], n[1]);
+ CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
+ VectorCopy(vn, tn);
+ vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
+ vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
+ vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
+ VectorNormalize(vn);
+ vn += 3;
+ if (vs)
+ {
+ VectorCopy(vs, ts);
+ vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
+ vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
+ vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
+ VectorNormalize(vs);
+ vs += 3;
+ VectorCopy(vt, tt);
+ vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
+ vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
+ vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
+ VectorNormalize(vt);
+ vt += 3;
+ }
+ }
+ }
+ rsurface.batchskeletaltransform3x4 = NULL;
+ rsurface.batchskeletalnumtransforms = 0;
+ }
+
// q1bsp surfaces rendered in vertex color mode have to have colors
// calculated based on lightstyles
if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
// in place
for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
{
+ float scale;
switch (deform->deform)
{
default:
}
}
- // generate texcoords based on the chosen texcoord source
- switch(rsurface.texture->tcgen.tcgen)
+ if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
{
- default:
- case Q3TCGEN_TEXTURE:
- break;
- case Q3TCGEN_LIGHTMAP:
-// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-// rsurface.batchtexcoordtexture2f_bufferoffset = 0;
- if (rsurface.batchtexcoordlightmap2f)
- memcpy(rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, batchnumvertices * sizeof(float[2]));
- break;
- case Q3TCGEN_VECTOR:
-// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-// rsurface.batchtexcoordtexture2f_bufferoffset = 0;
- for (j = 0;j < batchnumvertices;j++)
- {
- rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms);
- rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3);
- }
- break;
- case Q3TCGEN_ENVIRONMENT:
- // make environment reflections using a spheremap
- rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
- rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
- rsurface.batchtexcoordtexture2f_bufferoffset = 0;
- for (j = 0;j < batchnumvertices;j++)
+ // generate texcoords based on the chosen texcoord source
+ switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
{
- // identical to Q3A's method, but executed in worldspace so
- // carried models can be shiny too
+ default:
+ case Q3TCGEN_TEXTURE:
+ break;
+ case Q3TCGEN_LIGHTMAP:
+ // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+ // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+ // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+ if (rsurface.batchtexcoordlightmap2f)
+ memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
+ break;
+ case Q3TCGEN_VECTOR:
+ // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+ // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+ // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+ for (j = 0;j < batchnumvertices;j++)
+ {
+ rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
+ rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
+ }
+ break;
+ case Q3TCGEN_ENVIRONMENT:
+ // make environment reflections using a spheremap
+ rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+ rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+ rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+ for (j = 0;j < batchnumvertices;j++)
+ {
+ // identical to Q3A's method, but executed in worldspace so
+ // carried models can be shiny too
- float viewer[3], d, reflected[3], worldreflected[3];
+ float viewer[3], d, reflected[3], worldreflected[3];
- VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
- // VectorNormalize(viewer);
+ VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
+ // VectorNormalize(viewer);
- d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
+ d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
- reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
- reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
- reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
- // note: this is proportinal to viewer, so we can normalize later
+ reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
+ reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
+ reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
+ // note: this is proportinal to viewer, so we can normalize later
- Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
- VectorNormalize(worldreflected);
+ Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+ VectorNormalize(worldreflected);
- // note: this sphere map only uses world x and z!
- // so positive and negative y will LOOK THE SAME.
- rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
- rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+ // note: this sphere map only uses world x and z!
+ // so positive and negative y will LOOK THE SAME.
+ rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
+ rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
+ }
+ break;
}
- break;
- }
- // the only tcmod that needs software vertex processing is turbulent, so
- // check for it here and apply the changes if needed
- // and we only support that as the first one
- // (handling a mixture of turbulent and other tcmods would be problematic
- // without punting it entirely to a software path)
- if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
- {
- amplitude = rsurface.texture->tcmods[0].parms[1];
- animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
-// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
-// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
-// rsurface.batchtexcoordtexture2f_bufferoffset = 0;
- for (j = 0;j < batchnumvertices;j++)
- {
- rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
- rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+ // the only tcmod that needs software vertex processing is turbulent, so
+ // check for it here and apply the changes if needed
+ // and we only support that as the first one
+ // (handling a mixture of turbulent and other tcmods would be problematic
+ // without punting it entirely to a software path)
+ if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
+ {
+ amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
+ animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
+ // rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
+ // rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
+ // rsurface.batchtexcoordtexture2f_bufferoffset = 0;
+ for (j = 0;j < batchnumvertices;j++)
+ {
+ rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+ rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
+ }
}
}
{
// convert the modified arrays to vertex structs
// rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
-// rsurface.batchvertexmeshbuffer = NULL;
+// rsurface.batchvertexmesh_vertexbuffer = NULL;
+// rsurface.batchvertexmesh_bufferoffset = 0;
if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
+ if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
+ {
+ for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
+ {
+ Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
+ Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
+ }
+ }
+ }
+
+ // upload buffer data for the dynamic batch
+ if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
+ {
+ if (rsurface.batchvertexmesh)
+ rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
+ else
+ {
+ if (rsurface.batchvertex3f)
+ rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
+ if (rsurface.batchsvector3f)
+ rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
+ if (rsurface.batchtvector3f)
+ rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
+ if (rsurface.batchnormal3f)
+ rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
+ if (rsurface.batchlightmapcolor4f)
+ rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
+ if (rsurface.batchtexcoordtexture2f)
+ rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
+ if (rsurface.batchtexcoordlightmap2f)
+ rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
+ if (rsurface.batchskeletalindex4ub)
+ rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
+ if (rsurface.batchskeletalweight4ub)
+ rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
+ }
+ if (rsurface.batchelement3s)
+ rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
+ else if (rsurface.batchelement3i)
+ rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
}
}
d = 0;
if(!prepared)
{
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
prepared = true;
if(rsurface.batchnumvertices == 0)
break;
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();
}
// in Quake3 maps as it causes problems with q3map2 sky tricks,
// and skymasking also looks very bad when noclipping outside the
// level, so don't use it then either.
- if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
+ if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
{
R_Mesh_ResetTextureState();
if (skyrendermasked)
{
- R_SetupShader_DepthOrShadow(false, false);
+ R_SetupShader_DepthOrShadow(false, false, false);
// depth-only (masking)
GL_ColorMask(0,0,0,0);
// just to make sure that braindead drivers don't draw
// anything despite that colormask...
GL_BlendFunc(GL_ZERO, GL_ONE);
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
- if (rsurface.batchvertex3fbuffer)
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer);
- else
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
+ R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
}
else
{
{
RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
- for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++)
+ for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
{
VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
{
RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
- for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++)
+ for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
{
- unsigned char c = (vi << 3) * (1.0f / 256.0f);
+ unsigned char d = (vi << 3) * (1.0f / 256.0f);
VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
- Vector4Set(batchvertex[vi].color4f, c, c, c, 1);
+ Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
}
R_Mesh_PrepareVertices_Generic_Unlock();
RSurf_DrawBatch();
batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
{
- unsigned char c = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
+ unsigned char d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
- Vector4Set(batchvertex[j*3+0].color4f, c, c, c, 1);
- Vector4Set(batchvertex[j*3+1].color4f, c, c, c, 1);
- Vector4Set(batchvertex[j*3+2].color4f, c, c, c, 1);
+ Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
+ Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
+ Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
}
R_Mesh_PrepareVertices_Generic_Unlock();
R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(true);
// R_Mesh_ResetTextureState();
- R_SetupShader_DepthOrShadow(false, false);
}
RSurf_SetupDepthAndCulling();
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
- if (rsurface.batchvertex3fbuffer)
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer);
- else
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
+ R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
+ R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
RSurf_DrawBatch();
}
if (setup)
if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
return;
RSurf_SetupDepthAndCulling();
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
- if (rsurface.batchvertex3fbuffer)
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3fbuffer);
- else
- R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer);
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
+ R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
+ R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
RSurf_DrawBatch();
}
memset(decalsystem, 0, sizeof(*decalsystem));
}
-static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence)
+static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, unsigned int decalsequence)
{
tridecal_t *decal;
tridecal_t *decals;
extern cvar_t cl_decals_models;
extern cvar_t cl_decals_newsystem_intensitymultiplier;
// baseparms, parms, temps
-static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
+static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
{
int cornerindex;
int index;
for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence);
}
-static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
{
matrix4x4_t projection;
decalsystem_t *decalsystem;
}
// do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
-static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence)
+static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
{
int renderentityindex;
float worldmins[3];
float color[4];
float tcrange[4];
float worldsize;
- int decalsequence;
+ unsigned int decalsequence;
}
r_decalsystem_splatqueue_t;
int i;
decalsystem_t *decalsystem = &ent->decalsystem;
int numdecals;
- int killsequence;
+ unsigned int killsequence;
tridecal_t *decal;
float frametime;
float lifetime;
return;
}
- killsequence = cl.decalsequence - max(1, cl_decals_max.integer);
+ killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
lifetime = cl_decals_time.value + cl_decals_fadetime.value;
if (decalsystem->lastupdatetime)
if (decal->color4f[0][3])
{
decal->lived += frametime;
- if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime)
+ if (killsequence > decal->decalsequence || decal->lived >= lifetime)
{
memset(decal, 0, sizeof(*decal));
if (decalsystem->freedecal > i)
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;
static void R_DrawDebugModel(void)
{
entity_render_t *ent = rsurface.entity;
- int i, j, k, l, flagsmask;
+ int i, j, flagsmask;
const msurface_t *surface;
dp_model_t *model = ent->model;
- vec3_t v;
if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity)
return;
if (r_shownormals.value != 0 && qglBegin)
{
+ int l, k;
+ vec3_t v;
if (r_showdisabledepthtest.integer)
{
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 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
texture.update_lastrenderframe = -1; // regenerate this texture
texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
+ texture.basealpha = 1.0f;
texture.currentskinframe = skinframe;
texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
texture.offsetmapping = OFFSETMAPPING_OFF;