[iortcw] 238/497: All: Rend2: Fix corrupt models

Simon McVittie smcv at debian.org
Fri Sep 8 10:36:58 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to annotated tag 1.42d
in repository iortcw.

commit b38bf35b7cbb1f23ef57f62ac7cd0a8469d3a08b
Author: M4N4T4RMS at gmail.com <M4N4T4RMS at gmail.com@e65d2741-a53d-b2dc-ae96-bb75fa5e4c4a>
Date:   Sun Nov 2 13:59:19 2014 +0000

    All: Rend2: Fix corrupt models
---
 MP/code/rend2/tr_glsl.c    |  56 -------------
 MP/code/rend2/tr_init.c    |  14 ++--
 MP/code/rend2/tr_local.h   |   3 +-
 MP/code/rend2/tr_model.c   | 200 ++++++++++++++++++++-------------------------
 MP/code/rend2/tr_shade.c   |   6 --
 MP/code/rend2/tr_surface.c |  61 +++++++++++---
 MP/code/rend2/tr_vbo.c     |  68 ++++++++++-----
 SP/code/rend2/tr_glsl.c    |  56 -------------
 SP/code/rend2/tr_init.c    |  16 ++--
 SP/code/rend2/tr_local.h   |   3 +-
 SP/code/rend2/tr_model.c   | 200 ++++++++++++++++++++-------------------------
 SP/code/rend2/tr_shade.c   |   6 --
 SP/code/rend2/tr_surface.c |  61 +++++++++++---
 SP/code/rend2/tr_vbo.c     |  68 ++++++++++-----
 14 files changed, 387 insertions(+), 431 deletions(-)

diff --git a/MP/code/rend2/tr_glsl.c b/MP/code/rend2/tr_glsl.c
index 5a8cccd..ef2820a 100644
--- a/MP/code/rend2/tr_glsl.c
+++ b/MP/code/rend2/tr_glsl.c
@@ -1497,62 +1497,6 @@ void GLSL_BindNullProgram(void)
 }
 
 
-void GLSL_VertexAttribPointers(uint32_t attribBits)
-{
-	int newFrame, oldFrame;
-	vao_t *vao = glState.currentVao;
-	int attribIndex;
-	uint32_t extraOffsets[ATTR_INDEX_COUNT];
-
-	if(!vao)
-	{
-		ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VAO bound");
-		return;
-	}
-
-	// don't just call LogComment, or we will get a call to va() every frame!
-	if(r_logFile->integer)
-	{
-		GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vao->name));
-	}
-
-	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
-		extraOffsets[attribIndex] = 0;
-
-	// position/normal/tangent are always set in case of animation
-	oldFrame = glState.vertexAttribsOldFrame;
-	newFrame = glState.vertexAttribsNewFrame;
-	if (glState.vertexAnimation)
-	{
-		extraOffsets[ATTR_INDEX_POSITION]  = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_POSITION2] = oldFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_NORMAL]    = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_NORMAL2]   = oldFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_TANGENT]   = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_TANGENT2]  = oldFrame * vao->frameSize;
-	}
-
-	// this may not be bound if we're using VAOs
-	if (glRefConfig.vertexArrayObject)
-	{
-		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
-	}
-
-	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
-	{
-		uint32_t attribBit = 1 << attribIndex;
-		vaoAttrib_t *vAtb;
-
-		if (!(attribBits & attribBit))
-			continue;
-
-		vAtb = &vao->attribs[attribIndex];
-
-		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + extraOffsets[attribIndex]));
-	}
-}
-
-
 shaderProgram_t *GLSL_GetGenericShaderProgram(int stage, glfog_t *glFog)
 {
 	shaderStage_t *pStage = tess.xstages[stage];
diff --git a/MP/code/rend2/tr_init.c b/MP/code/rend2/tr_init.c
index 8da6300..b85963f 100644
--- a/MP/code/rend2/tr_init.c
+++ b/MP/code/rend2/tr_init.c
@@ -1023,9 +1023,13 @@ void GL_SetDefaultState( void ) {
 	glState.currentProgram = 0;
 	qglUseProgramObjectARB(0);
 
+	if (glRefConfig.vertexArrayObject)
+		qglBindVertexArrayARB(0);
+
 	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 	glState.currentVao = NULL;
+	glState.vertexAttribsEnabled = 0;
 
 	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 	qglDepthMask( GL_TRUE );
@@ -1037,6 +1041,11 @@ void GL_SetDefaultState( void ) {
 	if (glRefConfig.seamlessCubeMap)
 		qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 
+	// GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
+	qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
+
+	qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
+
 //----(SA)	added.
 	// ATI pn_triangles
 	if ( qglPNTrianglesiATI ) {
@@ -1064,11 +1073,6 @@ void GL_SetDefaultState( void ) {
 	}
 
 //----(SA)	end
-
-	// GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
-	qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
-
-	qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
 }
 
 /*
diff --git a/MP/code/rend2/tr_local.h b/MP/code/rend2/tr_local.h
index f5cf755..bf97a1d 100644
--- a/MP/code/rend2/tr_local.h
+++ b/MP/code/rend2/tr_local.h
@@ -1493,10 +1493,9 @@ typedef struct {
 	int         faceCullFront;
 	uint32_t    glStateBits;
 	uint32_t    storedGlState;
-	uint32_t        vertexAttribsNewFrame;
-	uint32_t        vertexAttribsOldFrame;
 	float           vertexAttribsInterpolation;
 	qboolean        vertexAnimation;
+	uint32_t        vertexAttribsEnabled;  // global if no VAOs, tess only otherwise
 	shaderProgram_t *currentProgram;
 	FBO_t          *currentFBO;
 	vao_t          *currentVao;
diff --git a/MP/code/rend2/tr_model.c b/MP/code/rend2/tr_model.c
index 0c925d5..dda845d 100644
--- a/MP/code/rend2/tr_model.c
+++ b/MP/code/rend2/tr_model.c
@@ -978,8 +978,8 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 			{
 				st = surf->st;
 				for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
-					dataOfs += sizeof(st->st);
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+					dataOfs += sizeof(vec2_t);
 				}
 
 				v = surf->verts;
@@ -992,8 +992,8 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
-					dataOfs += sizeof(v->xyz);
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+					dataOfs += sizeof(vec3_t);
 
 					// normal
 					p = (uint32_t *)(data + dataOfs);
@@ -1025,11 +1025,11 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
 
 					// st
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
 					dataOfs += sizeof(st->st);
 
 					// normal
@@ -1057,61 +1057,49 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 			vaoSurf->numVerts = surf->numVerts;
 			
 			vaoSurf->minIndex = 0;
-			vaoSurf->maxIndex = surf->numVerts;
+			vaoSurf->maxIndex = surf->numVerts - 1;
 
 			vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
 
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].enabled = 1;
 #ifdef USE_VERT_TANGENT_SPACE
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
 #endif
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].enabled = 1;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].count = 2;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].type = GL_FLOAT;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].normalized = GL_FALSE;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].offset = offset_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].offset = offset_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].offset = offset_tangent;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].stride = stride_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].stride = stride_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].stride = stride_tangent;
-
-			vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].count = 4;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].normalized = GL_TRUE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].offset = offset_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].stride = stride_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
+
+			if (mdvModel->numFrames > 1)
+			{
+				vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
+				vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2  ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ];
+				vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
+
+				vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			}
 
 			Vao_SetVertexPointers(vaoSurf->vao);
 
@@ -1498,8 +1486,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 			{
 				st = surf->st;
 				for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
-					dataOfs += sizeof(st->st);
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+					dataOfs += sizeof(vec2_t);
 				}
 
 				v = surf->verts;
@@ -1512,8 +1500,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
-					dataOfs += sizeof(v->xyz);
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+					dataOfs += sizeof(vec3_t);
 
 					// normal
 					p = (uint32_t *)(data + dataOfs);
@@ -1545,11 +1533,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
 
 					// st
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
 					dataOfs += sizeof(st->st);
 
 					// normal
@@ -1577,61 +1565,49 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 			vaoSurf->numVerts = surf->numVerts;
 			
 			vaoSurf->minIndex = 0;
-			vaoSurf->maxIndex = surf->numVerts;
+			vaoSurf->maxIndex = surf->numVerts - 1;
 
 			vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
 
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].enabled = 1;
 #ifdef USE_VERT_TANGENT_SPACE
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
 #endif
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].enabled = 1;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].count = 2;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].type = GL_FLOAT;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].normalized = GL_FALSE;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].offset = offset_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].offset = offset_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].offset = offset_tangent;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].stride = stride_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].stride = stride_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].stride = stride_tangent;
-
-			vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].count = 4;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].normalized = GL_TRUE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].offset = offset_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].stride = stride_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
+
+			if (mdvModel->numFrames > 1)
+			{
+				vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
+				vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2  ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ];
+				vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
+
+				vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			}
 
 			Vao_SetVertexPointers(vaoSurf->vao);
 
diff --git a/MP/code/rend2/tr_shade.c b/MP/code/rend2/tr_shade.c
index 20f8cac..07d2884 100644
--- a/MP/code/rend2/tr_shade.c
+++ b/MP/code/rend2/tr_shade.c
@@ -1667,12 +1667,6 @@ void RB_StageIteratorGeneric( void )
 	}
 
 	//
-	// Set vertex attribs and pointers
-	//
-	if (glState.vertexAnimation)
-		GLSL_VertexAttribPointers(vertexAttribs & (ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TANGENT | ATTR_TANGENT2));
-
-	//
 	// render depth if in depthfill mode
 	//
 	if (backEnd.depthFill)
diff --git a/MP/code/rend2/tr_surface.c b/MP/code/rend2/tr_surface.c
index fab37a4..df5ae0c 100644
--- a/MP/code/rend2/tr_surface.c
+++ b/MP/code/rend2/tr_surface.c
@@ -1843,8 +1843,8 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface)
 
 	tess.useInternalVao = qfalse;
 
-	tess.numIndexes += surface->numIndexes;
-	tess.numVertexes += surface->numVerts;
+	tess.numIndexes = surface->numIndexes;
+	tess.numVertexes = surface->numVerts;
 	tess.minIndex = surface->minIndex;
 	tess.maxIndex = surface->maxIndex;
 
@@ -1853,20 +1853,57 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface)
 
 	refEnt = &backEnd.currentEntity->e;
 
-	if(refEnt->oldframe == refEnt->frame)
-	{
-		glState.vertexAttribsInterpolation = 0;
-	}
-	else
-	{
-		glState.vertexAttribsInterpolation = refEnt->backlerp;
-	}
+	glState.vertexAttribsInterpolation = (refEnt->oldframe == refEnt->frame) ? 0.0f : refEnt->backlerp;
 
-	glState.vertexAttribsOldFrame = refEnt->oldframe;
-	glState.vertexAttribsNewFrame = refEnt->frame;
 	if (surface->mdvModel->numFrames > 1)
+	{
+		int frameOffset, attribIndex;
+		vaoAttrib_t *vAtb;
+
 		glState.vertexAnimation = qtrue;
 
+		if (glRefConfig.vertexArrayObject)
+		{
+			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, surface->vao->vertexesVBO);
+		}
+
+		frameOffset    = refEnt->frame * surface->vao->frameSize;
+
+		attribIndex = ATTR_INDEX_POSITION;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_NORMAL;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_TANGENT;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		frameOffset = refEnt->oldframe * surface->vao->frameSize;
+
+		attribIndex = ATTR_INDEX_POSITION2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_NORMAL2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_TANGENT2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+
+		if (!glRefConfig.vertexArrayObject)
+		{
+			attribIndex = ATTR_INDEX_TEXCOORD;
+			vAtb = &surface->vao->attribs[attribIndex];
+			qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+		}
+	}
+
 	RB_EndSurface();
 
 	// So we don't lerp surfaces that shouldn't be lerped
diff --git a/MP/code/rend2/tr_vbo.c b/MP/code/rend2/tr_vbo.c
index 5c44b0e..9734c5a 100644
--- a/MP/code/rend2/tr_vbo.c
+++ b/MP/code/rend2/tr_vbo.c
@@ -94,24 +94,32 @@ void R_VaoUnpackNormal(vec3_t v, uint32_t b)
 
 void Vao_SetVertexPointers(vao_t *vao)
 {
-	int i;
+	int attribIndex;
 
 	// set vertex pointers
-	for (i = 0; i < ATTR_INDEX_COUNT; i++)
+	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
 	{
-		if (vao->attribs[i].enabled)
+		uint32_t attribBit = 1 << attribIndex;
+		vaoAttrib_t *vAtb = &vao->attribs[attribIndex];
+
+		if (vAtb->enabled)
 		{
-			qglVertexAttribPointerARB((GLuint)i,
-								  (GLint)vao->attribs[i].count,
-								  (GLenum)vao->attribs[i].type, 
-								  (GLboolean)vao->attribs[i].normalized, 
-								  (GLsizei)vao->attribs[i].stride,
-								  BUFFER_OFFSET(vao->attribs[i].offset));
-			qglEnableVertexAttribArrayARB(i);
+			qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+			if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit))
+				qglEnableVertexAttribArrayARB(attribIndex);
+
+			if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+				glState.vertexAttribsEnabled |= attribBit;
 		}
 		else
 		{
-			qglDisableVertexAttribArrayARB(i);
+			// don't disable vertex attribs when using vertex array objects
+			// Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway
+			if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit))
+				qglDisableVertexAttribArrayARB(attribIndex);
+
+			if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+				glState.vertexAttribsEnabled &= ~attribBit;
 		}
 	}
 }
@@ -386,8 +394,6 @@ void R_BindVao(vao_t * vao)
 		glState.currentVao = vao;
 
 		glState.vertexAttribsInterpolation = 0;
-		glState.vertexAttribsOldFrame = 0;
-		glState.vertexAttribsNewFrame = 0;
 		glState.vertexAnimation = qfalse;
 		backEnd.pc.c_vaoBinds++;
 
@@ -398,13 +404,19 @@ void R_BindVao(vao_t * vao)
 			// why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel?
 			if (1)
 				qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+
+			// tess VAO always has buffers bound
+			if (vao == tess.vao)
+				qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
 		}
 		else
 		{
 			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
 			qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO);
 
-			Vao_SetVertexPointers(vao);
+			// tess VAO doesn't have vertex pointers set until data is uploaded
+			if (vao != tess.vao)
+				Vao_SetVertexPointers(vao);
 		}
 	}
 }
@@ -642,13 +654,6 @@ void RB_UpdateTessVao(unsigned int attribBits)
 
 		R_BindVao(tess.vao);
 
-		// these may not be bound if we're using VAOs
-		if (glRefConfig.vertexArrayObject)
-		{
-			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesVBO);
-			qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesIBO);
-		}
-
 		// orphan old vertex buffer so we don't stall on it
 		qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB);
 
@@ -666,12 +671,31 @@ void RB_UpdateTessVao(unsigned int attribBits)
 
 		for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
 		{
-			if (attribBits & (1 << attribIndex))
+			uint32_t attribBit = 1 << attribIndex;
+
+			if (attribBits & attribBit)
 			{
 				vaoAttrib_t *vAtb = &tess.vao->attribs[attribIndex];
 
 				// note: tess has a VBO where stride == size
 				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]);
+
+				if (!glRefConfig.vertexArrayObject)
+					qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+
+				if (!(glState.vertexAttribsEnabled & attribBit))
+				{
+					qglEnableVertexAttribArrayARB(attribIndex);
+					glState.vertexAttribsEnabled |= attribBit;
+				}
+			}
+			else
+			{
+				if ((glState.vertexAttribsEnabled & attribBit))
+				{
+					qglDisableVertexAttribArrayARB(attribIndex);
+					glState.vertexAttribsEnabled &= ~attribBit;
+				}
 			}
 		}
 
diff --git a/SP/code/rend2/tr_glsl.c b/SP/code/rend2/tr_glsl.c
index 5a8cccd..ef2820a 100644
--- a/SP/code/rend2/tr_glsl.c
+++ b/SP/code/rend2/tr_glsl.c
@@ -1497,62 +1497,6 @@ void GLSL_BindNullProgram(void)
 }
 
 
-void GLSL_VertexAttribPointers(uint32_t attribBits)
-{
-	int newFrame, oldFrame;
-	vao_t *vao = glState.currentVao;
-	int attribIndex;
-	uint32_t extraOffsets[ATTR_INDEX_COUNT];
-
-	if(!vao)
-	{
-		ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VAO bound");
-		return;
-	}
-
-	// don't just call LogComment, or we will get a call to va() every frame!
-	if(r_logFile->integer)
-	{
-		GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", vao->name));
-	}
-
-	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
-		extraOffsets[attribIndex] = 0;
-
-	// position/normal/tangent are always set in case of animation
-	oldFrame = glState.vertexAttribsOldFrame;
-	newFrame = glState.vertexAttribsNewFrame;
-	if (glState.vertexAnimation)
-	{
-		extraOffsets[ATTR_INDEX_POSITION]  = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_POSITION2] = oldFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_NORMAL]    = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_NORMAL2]   = oldFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_TANGENT]   = newFrame * vao->frameSize;
-		extraOffsets[ATTR_INDEX_TANGENT2]  = oldFrame * vao->frameSize;
-	}
-
-	// this may not be bound if we're using VAOs
-	if (glRefConfig.vertexArrayObject)
-	{
-		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
-	}
-
-	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
-	{
-		uint32_t attribBit = 1 << attribIndex;
-		vaoAttrib_t *vAtb;
-
-		if (!(attribBits & attribBit))
-			continue;
-
-		vAtb = &vao->attribs[attribIndex];
-
-		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + extraOffsets[attribIndex]));
-	}
-}
-
-
 shaderProgram_t *GLSL_GetGenericShaderProgram(int stage, glfog_t *glFog)
 {
 	shaderStage_t *pStage = tess.xstages[stage];
diff --git a/SP/code/rend2/tr_init.c b/SP/code/rend2/tr_init.c
index 0f1aa2d..df826b2 100644
--- a/SP/code/rend2/tr_init.c
+++ b/SP/code/rend2/tr_init.c
@@ -1028,9 +1028,13 @@ void GL_SetDefaultState( void ) {
 	glState.currentProgram = 0;
 	qglUseProgramObjectARB(0);
 
+	if (glRefConfig.vertexArrayObject)
+		qglBindVertexArrayARB(0);
+
 	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 	glState.currentVao = NULL;
+	glState.vertexAttribsEnabled = 0;
 
 	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 	qglDepthMask( GL_TRUE );
@@ -1042,6 +1046,12 @@ void GL_SetDefaultState( void ) {
 	if (glRefConfig.seamlessCubeMap)
 		qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 
+	
+	// GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
+	qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
+
+	qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
+
 //----(SA)	added.
 	// ATI pn_triangles
 	if ( qglPNTrianglesiATI ) {
@@ -1067,13 +1077,7 @@ void GL_SetDefaultState( void ) {
 		// set when rendering
 //	   qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glConfig.maxAnisotropy);
 	}
-
 //----(SA)	end
-
-	// GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
-	qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
-
-	qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
 }
 
 /*
diff --git a/SP/code/rend2/tr_local.h b/SP/code/rend2/tr_local.h
index bb7e721..35169aa 100644
--- a/SP/code/rend2/tr_local.h
+++ b/SP/code/rend2/tr_local.h
@@ -1506,10 +1506,9 @@ typedef struct {
 	int         faceCullFront;
 	uint32_t    glStateBits;
 	uint32_t    storedGlState;
-	uint32_t        vertexAttribsNewFrame;
-	uint32_t        vertexAttribsOldFrame;
 	float           vertexAttribsInterpolation;
 	qboolean        vertexAnimation;
+	uint32_t        vertexAttribsEnabled;  // global if no VAOs, tess only otherwise
 	shaderProgram_t *currentProgram;
 	FBO_t          *currentFBO;
 	vao_t          *currentVao;
diff --git a/SP/code/rend2/tr_model.c b/SP/code/rend2/tr_model.c
index ea8bebb..435915b 100644
--- a/SP/code/rend2/tr_model.c
+++ b/SP/code/rend2/tr_model.c
@@ -980,8 +980,8 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 			{
 				st = surf->st;
 				for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
-					dataOfs += sizeof(st->st);
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+					dataOfs += sizeof(vec2_t);
 				}
 
 				v = surf->verts;
@@ -994,8 +994,8 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
-					dataOfs += sizeof(v->xyz);
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+					dataOfs += sizeof(vec3_t);
 
 					// normal
 					p = (uint32_t *)(data + dataOfs);
@@ -1027,11 +1027,11 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
 
 					// st
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
 					dataOfs += sizeof(st->st);
 
 					// normal
@@ -1059,61 +1059,49 @@ static qboolean R_LoadMDC( model_t *mod, int lod, void *buffer, const char *modN
 			vaoSurf->numVerts = surf->numVerts;
 			
 			vaoSurf->minIndex = 0;
-			vaoSurf->maxIndex = surf->numVerts;
+			vaoSurf->maxIndex = surf->numVerts - 1;
 
 			vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
 
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].enabled = 1;
 #ifdef USE_VERT_TANGENT_SPACE
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
 #endif
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].enabled = 1;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].count = 2;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].type = GL_FLOAT;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].normalized = GL_FALSE;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].offset = offset_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].offset = offset_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].offset = offset_tangent;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].stride = stride_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].stride = stride_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].stride = stride_tangent;
-
-			vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].count = 4;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].normalized = GL_TRUE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].offset = offset_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].stride = stride_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
+
+			if (mdvModel->numFrames > 1)
+			{
+				vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
+				vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2  ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ];
+				vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
+
+				vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			}
 
 			Vao_SetVertexPointers(vaoSurf->vao);
 
@@ -1500,8 +1488,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 			{
 				st = surf->st;
 				for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
-					dataOfs += sizeof(st->st);
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
+					dataOfs += sizeof(vec2_t);
 				}
 
 				v = surf->verts;
@@ -1514,8 +1502,8 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
-					dataOfs += sizeof(v->xyz);
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
+					dataOfs += sizeof(vec3_t);
 
 					// normal
 					p = (uint32_t *)(data + dataOfs);
@@ -1547,11 +1535,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 					uint32_t *p;
 
 					// xyz
-					memcpy(data + dataOfs, &v->xyz, sizeof(v->xyz));
+					memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t));
 					dataOfs += sizeof(v->xyz);
 
 					// st
-					memcpy(data + dataOfs, &st->st, sizeof(st->st));
+					memcpy(data + dataOfs, &st->st, sizeof(vec2_t));
 					dataOfs += sizeof(st->st);
 
 					// normal
@@ -1579,61 +1567,49 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, const char *modN
 			vaoSurf->numVerts = surf->numVerts;
 			
 			vaoSurf->minIndex = 0;
-			vaoSurf->maxIndex = surf->numVerts;
+			vaoSurf->maxIndex = surf->numVerts - 1;
 
 			vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC);
 
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].enabled = 1;
 #ifdef USE_VERT_TANGENT_SPACE
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].enabled = 1;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].enabled = 1;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
 #endif
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].enabled = 1;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].count = 3;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].count = 4;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].count = 2;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].type = GL_FLOAT;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].type = glRefConfig.packedNormalDataType;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].type = GL_FLOAT;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].normalized = GL_FALSE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].normalized = GL_TRUE;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].normalized = GL_FALSE;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].offset = offset_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].offset = offset_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].offset = offset_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].offset = offset_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].offset = offset_tangent;
-
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION  ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_POSITION2 ].stride = stride_xyz;
-			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD  ].stride = stride_st;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL    ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2   ].stride = stride_normal;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT   ].stride = stride_tangent;
-			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2  ].stride = stride_tangent;
-
-			vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].count = 4;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].type = glRefConfig.packedNormalDataType;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].normalized = GL_TRUE;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].offset = offset_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
+
+			vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride_xyz;
+			vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride_st;
+			vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ].stride = stride_normal;
+			vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride_tangent;
+
+			if (mdvModel->numFrames > 1)
+			{
+				vaoSurf->vao->attribs[ATTR_INDEX_POSITION2] = vaoSurf->vao->attribs[ATTR_INDEX_POSITION];
+				vaoSurf->vao->attribs[ATTR_INDEX_NORMAL2  ] = vaoSurf->vao->attribs[ATTR_INDEX_NORMAL  ];
+				vaoSurf->vao->attribs[ATTR_INDEX_TANGENT2 ] = vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ];
+
+				vaoSurf->vao->frameSize = stride_xyz    * surf->numVerts;
+			}
 
 			Vao_SetVertexPointers(vaoSurf->vao);
 
diff --git a/SP/code/rend2/tr_shade.c b/SP/code/rend2/tr_shade.c
index 3dcad5b..bb0f78b 100644
--- a/SP/code/rend2/tr_shade.c
+++ b/SP/code/rend2/tr_shade.c
@@ -1668,12 +1668,6 @@ void RB_StageIteratorGeneric( void )
 	}
 
 	//
-	// Set vertex attribs and pointers
-	//
-	if (glState.vertexAnimation)
-		GLSL_VertexAttribPointers(vertexAttribs & (ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TANGENT | ATTR_TANGENT2));
-
-	//
 	// render depth if in depthfill mode
 	//
 	if (backEnd.depthFill)
diff --git a/SP/code/rend2/tr_surface.c b/SP/code/rend2/tr_surface.c
index 429fb89..f3afa01 100644
--- a/SP/code/rend2/tr_surface.c
+++ b/SP/code/rend2/tr_surface.c
@@ -1840,8 +1840,8 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface)
 
 	tess.useInternalVao = qfalse;
 
-	tess.numIndexes += surface->numIndexes;
-	tess.numVertexes += surface->numVerts;
+	tess.numIndexes = surface->numIndexes;
+	tess.numVertexes = surface->numVerts;
 	tess.minIndex = surface->minIndex;
 	tess.maxIndex = surface->maxIndex;
 
@@ -1850,20 +1850,57 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface)
 
 	refEnt = &backEnd.currentEntity->e;
 
-	if(refEnt->oldframe == refEnt->frame)
-	{
-		glState.vertexAttribsInterpolation = 0;
-	}
-	else
-	{
-		glState.vertexAttribsInterpolation = refEnt->backlerp;
-	}
+	glState.vertexAttribsInterpolation = (refEnt->oldframe == refEnt->frame) ? 0.0f : refEnt->backlerp;
 
-	glState.vertexAttribsOldFrame = refEnt->oldframe;
-	glState.vertexAttribsNewFrame = refEnt->frame;
 	if (surface->mdvModel->numFrames > 1)
+	{
+		int frameOffset, attribIndex;
+		vaoAttrib_t *vAtb;
+
 		glState.vertexAnimation = qtrue;
 
+		if (glRefConfig.vertexArrayObject)
+		{
+			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, surface->vao->vertexesVBO);
+		}
+
+		frameOffset    = refEnt->frame * surface->vao->frameSize;
+
+		attribIndex = ATTR_INDEX_POSITION;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_NORMAL;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_TANGENT;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		frameOffset = refEnt->oldframe * surface->vao->frameSize;
+
+		attribIndex = ATTR_INDEX_POSITION2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_NORMAL2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+		attribIndex = ATTR_INDEX_TANGENT2;
+		vAtb = &surface->vao->attribs[attribIndex];
+		qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset));
+
+
+		if (!glRefConfig.vertexArrayObject)
+		{
+			attribIndex = ATTR_INDEX_TEXCOORD;
+			vAtb = &surface->vao->attribs[attribIndex];
+			qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+		}
+	}
+
 	RB_EndSurface();
 
 	// So we don't lerp surfaces that shouldn't be lerped
diff --git a/SP/code/rend2/tr_vbo.c b/SP/code/rend2/tr_vbo.c
index 5c44b0e..9734c5a 100644
--- a/SP/code/rend2/tr_vbo.c
+++ b/SP/code/rend2/tr_vbo.c
@@ -94,24 +94,32 @@ void R_VaoUnpackNormal(vec3_t v, uint32_t b)
 
 void Vao_SetVertexPointers(vao_t *vao)
 {
-	int i;
+	int attribIndex;
 
 	// set vertex pointers
-	for (i = 0; i < ATTR_INDEX_COUNT; i++)
+	for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
 	{
-		if (vao->attribs[i].enabled)
+		uint32_t attribBit = 1 << attribIndex;
+		vaoAttrib_t *vAtb = &vao->attribs[attribIndex];
+
+		if (vAtb->enabled)
 		{
-			qglVertexAttribPointerARB((GLuint)i,
-								  (GLint)vao->attribs[i].count,
-								  (GLenum)vao->attribs[i].type, 
-								  (GLboolean)vao->attribs[i].normalized, 
-								  (GLsizei)vao->attribs[i].stride,
-								  BUFFER_OFFSET(vao->attribs[i].offset));
-			qglEnableVertexAttribArrayARB(i);
+			qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+			if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit))
+				qglEnableVertexAttribArrayARB(attribIndex);
+
+			if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+				glState.vertexAttribsEnabled |= attribBit;
 		}
 		else
 		{
-			qglDisableVertexAttribArrayARB(i);
+			// don't disable vertex attribs when using vertex array objects
+			// Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway
+			if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit))
+				qglDisableVertexAttribArrayARB(attribIndex);
+
+			if (!glRefConfig.vertexArrayObject || vao == tess.vao)
+				glState.vertexAttribsEnabled &= ~attribBit;
 		}
 	}
 }
@@ -386,8 +394,6 @@ void R_BindVao(vao_t * vao)
 		glState.currentVao = vao;
 
 		glState.vertexAttribsInterpolation = 0;
-		glState.vertexAttribsOldFrame = 0;
-		glState.vertexAttribsNewFrame = 0;
 		glState.vertexAnimation = qfalse;
 		backEnd.pc.c_vaoBinds++;
 
@@ -398,13 +404,19 @@ void R_BindVao(vao_t * vao)
 			// why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel?
 			if (1)
 				qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
+
+			// tess VAO always has buffers bound
+			if (vao == tess.vao)
+				qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
 		}
 		else
 		{
 			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO);
 			qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO);
 
-			Vao_SetVertexPointers(vao);
+			// tess VAO doesn't have vertex pointers set until data is uploaded
+			if (vao != tess.vao)
+				Vao_SetVertexPointers(vao);
 		}
 	}
 }
@@ -642,13 +654,6 @@ void RB_UpdateTessVao(unsigned int attribBits)
 
 		R_BindVao(tess.vao);
 
-		// these may not be bound if we're using VAOs
-		if (glRefConfig.vertexArrayObject)
-		{
-			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesVBO);
-			qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesIBO);
-		}
-
 		// orphan old vertex buffer so we don't stall on it
 		qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB);
 
@@ -666,12 +671,31 @@ void RB_UpdateTessVao(unsigned int attribBits)
 
 		for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
 		{
-			if (attribBits & (1 << attribIndex))
+			uint32_t attribBit = 1 << attribIndex;
+
+			if (attribBits & attribBit)
 			{
 				vaoAttrib_t *vAtb = &tess.vao->attribs[attribIndex];
 
 				// note: tess has a VBO where stride == size
 				qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]);
+
+				if (!glRefConfig.vertexArrayObject)
+					qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
+
+				if (!(glState.vertexAttribsEnabled & attribBit))
+				{
+					qglEnableVertexAttribArrayARB(attribIndex);
+					glState.vertexAttribsEnabled |= attribBit;
+				}
+			}
+			else
+			{
+				if ((glState.vertexAttribsEnabled & attribBit))
+				{
+					qglDisableVertexAttribArrayARB(attribIndex);
+					glState.vertexAttribsEnabled &= ~attribBit;
+				}
 			}
 		}
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list