From c764ddc64a4921c1775423db44a0be36dad906bb Mon Sep 17 00:00:00 2001 From: Ragnvald Maartmann-Moe IV Date: Wed, 19 Dec 2001 04:03:57 +0000 Subject: [PATCH] Just a massive speedup to gl particles. Enjoy. (Thanks to LordHavoc for prodding me to use glDrawElements, and munge all the particle textures into 1. Code mine, suggestions his) --- include/QF/GL/qf_funcs_list.h | 2 +- include/QF/GL/qf_textures.h | 3 + include/r_shared.h | 1 + include/varrays.h | 19 ++- libs/video/renderer/gl/gl_dyn_part.c | 166 +++++++++++++++++++---- libs/video/renderer/gl/gl_dyn_textures.c | 74 ++++++---- libs/video/renderer/gl/gl_rmisc.c | 11 +- libs/video/renderer/r_part.c | 5 +- libs/video/renderer/sw/sw_rmain.c | 1 + libs/video/renderer/sw/sw_rpart.c | 4 + libs/video/renderer/sw32/sw32_rmain.c | 1 + libs/video/renderer/sw32/sw32_rpart.c | 5 + libs/video/targets/vid_common_gl.c | 11 +- 13 files changed, 233 insertions(+), 70 deletions(-) diff --git a/include/QF/GL/qf_funcs_list.h b/include/QF/GL/qf_funcs_list.h index f82e32a34..fbfb3c680 100644 --- a/include/QF/GL/qf_funcs_list.h +++ b/include/QF/GL/qf_funcs_list.h @@ -120,7 +120,7 @@ QFGL_NEED (void, glDisable, (GLenum cap)); QFGL_NEED (void, glDisableClientState, (GLenum cap)); QFGL_NEED (void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)); QFGL_NEED (void, glDrawBuffer, (GLenum mode)); -QFGL_DONT_NEED (void, glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)); +QFGL_NEED (void, glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)); QFGL_DONT_NEED (void, glDrawPixels, (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * pixels)); QFGL_DONT_NEED (void, glDrawRangeElements, (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices)); QFGL_DONT_NEED (void, glEdgeFlag, (GLboolean flag)); diff --git a/include/QF/GL/qf_textures.h b/include/QF/GL/qf_textures.h index a071896bf..ba19bbc1d 100644 --- a/include/QF/GL/qf_textures.h +++ b/include/QF/GL/qf_textures.h @@ -39,9 +39,12 @@ extern int gl_lightmap_format; extern int gl_filter_min; extern int gl_filter_max; +extern int part_tex; +/* extern int part_tex_dot; extern int part_tex_smoke; extern int part_tex_spark; +*/ void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha); void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha); diff --git a/include/r_shared.h b/include/r_shared.h index 10173d6ef..9baa91f45 100644 --- a/include/r_shared.h +++ b/include/r_shared.h @@ -56,6 +56,7 @@ extern void R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1); extern int cachewidth; extern byte *cacheblock; extern int screenwidth; +extern int r_init; extern float pixelAspect; diff --git a/include/varrays.h b/include/varrays.h index fa783d1ae..e220b16ea 100644 --- a/include/varrays.h +++ b/include/varrays.h @@ -39,11 +39,11 @@ #include "QF/GL/types.h" -typedef struct varray_t2f_c4f_v3f_s { +typedef struct varray_t2f_c4ub_v2f_s { GLfloat texcoord[2]; - GLfloat color[4]; - GLfloat vertex[3]; -} varray_t2f_c4f_v3f_t; + GLubyte color[4]; + GLfloat vertex[2]; +} varray_t2f_c4ub_v2f_t; typedef struct varray_t2f_c4ub_v3f_s { GLfloat texcoord[2]; @@ -58,7 +58,14 @@ typedef struct varray_t2f_c4f_n3f_v3f_s { GLfloat vertex[3]; } varray_t2f_c4f_n3f_v3f_t; -#define MAX_VARRAY_VERTS 10000 -extern varray_t2f_c4ub_v3f_t varray[MAX_VARRAY_VERTS]; +//#define MAX_VARRAY_VERTS 10000 + +extern int vaelements; + +extern varray_t2f_c4ub_v3f_t *particleVertexArray; +extern int pVAsize; + +//extern varray_t2f_c4ub_v3f_t *modelVertexArray +//extern varray_t2f_v2f_t *textVertexArray; #endif // __qf_varrays_h diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index cbc5f9bf7..32af95764 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -59,6 +59,14 @@ static const char rcsid[] = int ramp[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 }; +int part_tex_dot = 0; +int part_tex_spark = 1; +int part_tex_smoke = 2; + +int pVAsize; +int *pVAindices; +varray_t2f_c4ub_v3f_t *particleVertexArray; + inline static void particle_new (ptype_t type, int texnum, vec3_t org, float scale, vec3_t vel, @@ -108,6 +116,41 @@ R_ClearParticles (void) numparticles = 0; } +void +R_InitParticles (void) +{ + int i; + + if (r_maxparticles && r_init) { + if (vaelements > 3) + pVAsize = min (vaelements - (vaelements % 4), r_maxparticles * 4); + else + pVAsize = r_maxparticles * 4; + Con_Printf ("%i maximum vertex elements.\n", pVAsize); + + if (particleVertexArray) + free (particleVertexArray); + particleVertexArray = (varray_t2f_c4ub_v3f_t *) + calloc (pVAsize, sizeof (varray_t2f_c4ub_v3f_t)); + qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray); + + if (pVAindices) + free (pVAindices); + pVAindices = (int *) calloc (pVAsize, sizeof (int)); + for (i = 0; i < pVAsize; i++) + pVAindices[i] = i; + } else { + if (particleVertexArray) { + free (particleVertexArray); + particleVertexArray = 0; + } + if (pVAindices) { + free (pVAindices); + pVAindices = 0; + } + } +} + void R_ReadPointFile_f (void) { @@ -694,6 +737,43 @@ R_ParticleExplosion_EE (vec3_t org) 128 + (rand () & 63)); } +void +R_TeleportSplash_EE (vec3_t org) +{ + float vel; + int rnd, i, j, k; + int l = 896; + vec3_t dir, porg, pvel; + + if (numparticles + l >= r_maxparticles) { + return; + } // else if (numparticles + l >= r_maxparticles) { +// l = r_maxparticles - numparticles; +// } + + for (i = -16; i < 16; i += 4) { + dir[1] = i * 8; + for (j = -16; j < 16; j += 4) { + dir[0] = j * 8; + for (k = -24; k < 32; k += 4) { + dir[2] = k * 8; + + rnd = rand (); + porg[0] = org[0] + i + (rnd & 3); + porg[1] = org[1] + j + ((rnd >> 2) & 3); + porg[2] = org[2] + k + ((rnd >> 4) & 3); + + VectorNormalize (dir); + vel = 50 + ((rnd >> 6) & 63); + VectorScale (dir, vel, pvel); + particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel, + (r_realtime + 0.2 + (rand () & 15) * 0.01), + rand () & 255, 255); + } + } + } +} + void R_RocketTrail_EE (entity_t *ent) { @@ -796,6 +876,8 @@ R_DrawParticles (void) fire_alpha, fire_scale, smoke_alpha, smoke_scale, smokecloud_alpha, smokecloud_org, smokecloud_scale; int activeparticles, maxparticle, j, k; + unsigned int vacount; + varray_t2f_c4ub_v3f_t *VA; particle_t *part; vec3_t up_scale, right_scale, up_right_scale, down_right_scale; @@ -804,15 +886,7 @@ R_DrawParticles (void) // LordHavoc: particles should not affect zbuffer qfglDepthMask (GL_FALSE); - - varray[0].texcoord[0] = 0; - varray[0].texcoord[1] = 1; - varray[1].texcoord[0] = 0; - varray[1].texcoord[1] = 0; - varray[2].texcoord[0] = 1; - varray[2].texcoord[1] = 0; - varray[3].texcoord[0] = 1; - varray[3].texcoord[1] = 1; + qfglBindTexture (GL_TEXTURE_2D, part_tex); grav = (fast_grav = r_frametime * 800.0) * 0.05; dvel = bloodcloud_scale = smoke_scale = r_frametime * 4.0; @@ -828,6 +902,8 @@ R_DrawParticles (void) minparticledist = DotProduct (r_refdef.vieworg, vpn) + 32.0; activeparticles = 0; + vacount = 0; + VA = particleVertexArray; maxparticle = -1; j = 0; @@ -836,15 +912,46 @@ R_DrawParticles (void) // Note, we must still do physics and such on them. if (!(DotProduct (part->org, vpn) < minparticledist)) { at = (byte *) & d_8to24table[(byte) part->color]; + VA[0].color[0] = at[0]; + VA[0].color[1] = at[1]; + VA[0].color[2] = at[2]; + VA[0].color[3] = part->alpha; + memcpy (VA[1].color, VA[0].color, sizeof(VA[0].color)); + memcpy (VA[2].color, VA[0].color, sizeof(VA[0].color)); + memcpy (VA[3].color, VA[0].color, sizeof(VA[0].color)); - varray[0].color[0] = at[0]; - varray[0].color[1] = at[1]; - varray[0].color[2] = at[2]; - varray[0].color[3] = part->alpha; - - memcpy (varray[1].color, varray[0].color, sizeof(varray[0].color)); - memcpy (varray[2].color, varray[0].color, sizeof(varray[0].color)); - memcpy (varray[3].color, varray[0].color, sizeof(varray[0].color)); + switch (part->tex) { + case 0: + VA[0].texcoord[0] = 0; + VA[0].texcoord[1] = 0.5; + VA[1].texcoord[0] = 0; + VA[1].texcoord[1] = 0; + VA[2].texcoord[0] = 0.5; + VA[2].texcoord[1] = 0; + VA[3].texcoord[0] = 0.5; + VA[3].texcoord[1] = 0.5; + break; + case 1: + VA[0].texcoord[0] = 0.5; + VA[0].texcoord[1] = 0.5; + VA[1].texcoord[0] = 0.5; + VA[1].texcoord[1] = 0; + VA[2].texcoord[0] = 1; + VA[2].texcoord[1] = 0; + VA[3].texcoord[0] = 1; + VA[3].texcoord[1] = 0.5; + break; + case 2: + VA[0].texcoord[0] = 0; + VA[0].texcoord[1] = 1; + VA[1].texcoord[0] = 0; + VA[1].texcoord[1] = 0.5; + VA[2].texcoord[0] = 0.5; + VA[2].texcoord[1] = 0.5; + VA[3].texcoord[0] = 0.5; + VA[3].texcoord[1] = 1; + break; + } scale = part->scale; @@ -854,13 +961,19 @@ R_DrawParticles (void) VectorAdd (right_scale, up_scale, up_right_scale); VectorSubtract (right_scale, up_scale, down_right_scale); - VectorAdd (part->org, up_right_scale, varray[0].vertex); - VectorAdd (part->org, down_right_scale, varray[1].vertex); - VectorSubtract (part->org, up_right_scale, varray[2].vertex); - VectorSubtract (part->org, down_right_scale, varray[3].vertex); + VectorAdd (part->org, up_right_scale, VA[0].vertex); + VectorAdd (part->org, down_right_scale, VA[1].vertex); + VectorSubtract (part->org, up_right_scale, VA[2].vertex); + VectorSubtract (part->org, down_right_scale, VA[3].vertex); - qfglBindTexture (GL_TEXTURE_2D, part->tex); - qfglDrawArrays (GL_QUADS, 0, 4); + VA += 4; + vacount += 4; + if (vacount + 4 > pVAsize) { + qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT, + pVAindices); + vacount = 0; + VA = particleVertexArray; + } } VectorMA (part->org, r_frametime, part->vel, part->org); @@ -925,10 +1038,13 @@ R_DrawParticles (void) activeparticles++; } } + if (vacount) + qfglDrawElements (GL_QUADS, vacount, GL_UNSIGNED_INT, pVAindices); + k = 0; while (maxparticle >= activeparticles) { *freeparticles[k++] = particles[maxparticle--]; - while (maxparticle >= activeparticles && + while (maxparticle >= activeparticles && particles[maxparticle].die <= r_realtime) maxparticle--; } @@ -944,10 +1060,12 @@ r_easter_eggs_f (cvar_t *var) if (easter_eggs) { if (easter_eggs->int_val) { R_ParticleExplosion = R_ParticleExplosion_EE; + R_TeleportSplash = R_TeleportSplash_EE; R_RocketTrail = R_RocketTrail_EE; R_GrenadeTrail = R_GrenadeTrail_EE; } else { R_ParticleExplosion = R_ParticleExplosion_QF; + R_TeleportSplash = R_TeleportSplash_QF; R_RocketTrail = R_RocketTrail_QF; R_GrenadeTrail = R_GrenadeTrail_QF; } diff --git a/libs/video/renderer/gl/gl_dyn_textures.c b/libs/video/renderer/gl/gl_dyn_textures.c index cc2a4af9f..c3fc1d643 100644 --- a/libs/video/renderer/gl/gl_dyn_textures.c +++ b/libs/video/renderer/gl/gl_dyn_textures.c @@ -30,6 +30,12 @@ static const char rcsid[] = #ifdef HAVE_CONFIG_H # include "config.h" #endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif #include @@ -39,23 +45,42 @@ static const char rcsid[] = #include "QF/GL/qf_noisetextures.h" #include "QF/GL/qf_vid.h" +/* int part_tex_dot; int part_tex_smoke; int part_tex_spark; +*/ +int part_tex; + + +static void +GDT_InitParticleTexture (void) +{ + byte data[64][64][2]; + + memset (data, 0, sizeof (data)); + + part_tex = texture_extension_number++; + qfglBindTexture (GL_TEXTURE_2D, part_tex); + qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qfglTexImage2D (GL_TEXTURE_2D, 0, 2, 64, 64, 0, GL_LUMINANCE_ALPHA, + GL_UNSIGNED_BYTE, data); +} static void GDT_InitDotParticleTexture (void) { - byte data[16][16][2]; + byte data[32][32][2]; int x, y, dx2, dy, d; - for (x = 0; x < 16; x++) { - dx2 = x - 8; + for (x = 0; x < 32; x++) { + dx2 = x - 16; dx2 *= dx2; - for (y = 0; y < 16; y++) { - dy = y - 8; - d = 255 - 4 * (dx2 + (dy * dy)); + for (y = 0; y < 32; y++) { + dy = y - 16; + d = 255 - (dx2 + (dy * dy)); if (d <= 0) { d = 0; data[y][x][0] = 0; @@ -65,26 +90,22 @@ GDT_InitDotParticleTexture (void) data[y][x][1] = (byte) d; } } - part_tex_dot = texture_extension_number++; - qfglBindTexture (GL_TEXTURE_2D, part_tex_dot); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qfglTexImage2D (GL_TEXTURE_2D, 0, 2, 16, 16, 0, GL_LUMINANCE_ALPHA, - GL_UNSIGNED_BYTE, data); + qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 32, 32, GL_LUMINANCE_ALPHA, + GL_UNSIGNED_BYTE, data); } static void GDT_InitSparkParticleTexture (void) { - byte data[16][16][2]; + byte data[32][32][2]; int x, y, dx2, dy, d; - for (x = 0; x < 16; x++) { - dx2 = 8 - abs (x - 8); + for (x = 0; x < 32; x++) { + dx2 = 16 - abs (x - 16); dx2 *= dx2; - for (y = 0; y < 16; y++) { - dy = 8 - abs (y - 8); - d = 3 * (dx2 + dy * dy) - 100; + for (y = 0; y < 32; y++) { + dy = 16 - abs (y - 16); + d = (dx2 + dy * dy) - 200; if (d > 255) d = 255; if (d < 1) { @@ -96,12 +117,8 @@ GDT_InitSparkParticleTexture (void) data[y][x][1] = (byte) d; } } - part_tex_spark = texture_extension_number++; - qfglBindTexture (GL_TEXTURE_2D, part_tex_spark); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qfglTexImage2D (GL_TEXTURE_2D, 0, 2, 16, 16, 0, GL_LUMINANCE_ALPHA, - GL_UNSIGNED_BYTE, data); + qfglTexSubImage2D (GL_TEXTURE_2D, 0, 32, 0, 32, 32, GL_LUMINANCE_ALPHA, + GL_UNSIGNED_BYTE, data); } static void @@ -133,17 +150,14 @@ GDT_InitSmokeParticleTexture (void) } } } - part_tex_smoke = texture_extension_number++; - qfglBindTexture (GL_TEXTURE_2D, part_tex_smoke); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qfglTexImage2D (GL_TEXTURE_2D, 0, 2, 32, 32, 0, GL_LUMINANCE_ALPHA, - GL_UNSIGNED_BYTE, data); + qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, 32, 32, 32, GL_LUMINANCE_ALPHA, + GL_UNSIGNED_BYTE, data); } void GDT_Init (void) { + GDT_InitParticleTexture (); GDT_InitDotParticleTexture (); GDT_InitSparkParticleTexture (); GDT_InitSmokeParticleTexture (); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 104c6b6fa..3e86f0ac7 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -59,7 +59,7 @@ static const char rcsid[] = #include "r_local.h" #include "varrays.h" -varray_t2f_c4ub_v3f_t varray[MAX_VARRAY_VERTS]; +int r_init = 0; qboolean VID_Is8bit (void); void R_InitBubble (void); @@ -159,15 +159,12 @@ R_Init (void) texture_extension_number = Skin_Init_Textures (texture_extension_number); + r_init = 1; + R_InitParticles (); + qfglEnableClientState (GL_COLOR_ARRAY); qfglEnableClientState (GL_VERTEX_ARRAY); qfglEnableClientState (GL_TEXTURE_COORD_ARRAY); - -// qfglInterleavedArrays (GL_T2F_C4UB_N3F_V3F, 0, varray); // Models w/normals -// qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, varray); // Polys w/o normals - qfglTexCoordPointer (2, GL_FLOAT, sizeof(varray[0]), varray[0].texcoord); - qfglColorPointer (4, GL_UNSIGNED_BYTE, sizeof(varray[0]), varray[0].color); - qfglVertexPointer (3, GL_FLOAT, sizeof(varray[0]), varray[0].vertex); } void diff --git a/libs/video/renderer/r_part.c b/libs/video/renderer/r_part.c index 70606c94a..41f247718 100644 --- a/libs/video/renderer/r_part.c +++ b/libs/video/renderer/r_part.c @@ -106,7 +106,10 @@ R_MaxParticlesCheck (cvar_t *r_particles, cvar_t *r_particles_max) sizeof (particle_t *)); } - R_ClearParticles(); + R_ClearParticles (); + + if (r_init) + R_InitParticles (); } void diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 82d6b7813..038e40786 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -66,6 +66,7 @@ int r_pixbytes = 1; float r_aliasuvscale = 1.0; int r_outofsurfaces; int r_outofedges; +int r_init = 0; qboolean r_dowarp, r_dowarpold, r_viewchanged; diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index 7256fb650..61200105b 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -49,6 +49,10 @@ int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 }; int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 }; +void +R_InitParticles (void) +{ +} void R_ClearParticles (void) diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index 422cb2769..fc709e799 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -67,6 +67,7 @@ int r_pixbytes = 1; float r_aliasuvscale = 1.0; int r_outofsurfaces; int r_outofedges; +int r_init = 0; qboolean r_dowarp, r_dowarpold, r_viewchanged; diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index d4564b618..b719a132a 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -49,6 +49,11 @@ int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 }; int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 }; +void +R_InitParticles (void) +{ +} + void R_ClearParticles (void) { diff --git a/libs/video/targets/vid_common_gl.c b/libs/video/targets/vid_common_gl.c index c4edd057e..fd9987026 100644 --- a/libs/video/targets/vid_common_gl.c +++ b/libs/video/targets/vid_common_gl.c @@ -69,6 +69,7 @@ const char *gl_renderer; const char *gl_vendor; const char *gl_version; +int vaelements; int texture_extension_number = 1; int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; int gl_filter_max = GL_LINEAR; @@ -88,7 +89,6 @@ cvar_t *vid_mode; cvar_t *vid_use8bit; - static void gl_multitexture_f (cvar_t *var) { @@ -155,6 +155,13 @@ CheckMultiTextureExtensions (void) } } +void +CheckVertexArraySize (void) +{ + qfglGetIntegerv (GL_MAX_ELEMENTS_VERTICES, &vaelements); +// qfglGetIntegerv (MAX_ELEMENTS_INDICES, *vaindices); +} + void VID_SetPalette (unsigned char *palette) { @@ -280,6 +287,8 @@ GL_Init_Common (void) qfglTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); CheckMultiTextureExtensions (); + CheckVertexArraySize (); + GL_Common_Init_Cvars (); }