Exemple #1
0
/*
============
R_InitVBOs
============
*/
void R_InitVBOs(void)
{
	int             dataSize;
	int             offset;

	ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n");

	tr.numVBOs = 0;
	tr.numIBOs = 0;

	dataSize  = sizeof(tess.xyz[0]);
	dataSize += sizeof(tess.normal[0]);
#ifdef USE_VERT_TANGENT_SPACE
	dataSize += sizeof(tess.tangent[0]);
	dataSize += sizeof(tess.bitangent[0]);
#endif
	dataSize += sizeof(tess.vertexColors[0]);
	dataSize += sizeof(tess.texCoords[0][0]) * 2;
	dataSize += sizeof(tess.lightdir[0]);
	dataSize *= SHADER_MAX_VERTEXES;

	tess.vbo = R_CreateVBO("tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC);

	offset = 0;

	tess.vbo->ofs_xyz         = offset; offset += sizeof(tess.xyz[0])              * SHADER_MAX_VERTEXES;
	tess.vbo->ofs_normal      = offset; offset += sizeof(tess.normal[0])           * SHADER_MAX_VERTEXES;
#ifdef USE_VERT_TANGENT_SPACE
	tess.vbo->ofs_tangent     = offset; offset += sizeof(tess.tangent[0])          * SHADER_MAX_VERTEXES;
	tess.vbo->ofs_bitangent   = offset; offset += sizeof(tess.bitangent[0])        * SHADER_MAX_VERTEXES;
#endif
	// these next two are actually interleaved
	tess.vbo->ofs_st          = offset; 
	tess.vbo->ofs_lightmap    = offset + sizeof(tess.texCoords[0][0]);
	                                    offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES;

	tess.vbo->ofs_vertexcolor = offset; offset += sizeof(tess.vertexColors[0])     * SHADER_MAX_VERTEXES;
	tess.vbo->ofs_lightdir    = offset;

	tess.vbo->stride_xyz         = sizeof(tess.xyz[0]);
	tess.vbo->stride_normal      = sizeof(tess.normal[0]);
#ifdef USE_VERT_TANGENT_SPACE
	tess.vbo->stride_tangent     = sizeof(tess.tangent[0]);
	tess.vbo->stride_bitangent   = sizeof(tess.bitangent[0]);
#endif
	tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]);
	tess.vbo->stride_st          = sizeof(tess.texCoords[0][0]) * 2;
	tess.vbo->stride_lightmap    = sizeof(tess.texCoords[0][0]) * 2;
	tess.vbo->stride_lightdir    = sizeof(tess.lightdir[0]);

	dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES;

	tess.ibo = R_CreateIBO("tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC);

	R_BindNullVBO();
	R_BindNullIBO();

	GL_CheckErrors();
}
Exemple #2
0
/*
============
R_InitVBOs
============
*/
void R_InitVBOs( void )
{
	int  dataSize;

	ri.Printf( PRINT_DEVELOPER, "------- R_InitVBOs -------\n" );

	Com_InitGrowList( &tr.vbos, 100 );
	Com_InitGrowList( &tr.ibos, 100 );

#if !defined( COMPAT_Q3A ) && !defined( COMPAT_ET )
	dataSize = sizeof( vec4_t ) * SHADER_MAX_VERTEXES * 11;
#else
	dataSize = sizeof( vec4_t ) * SHADER_MAX_VERTEXES * 10;
#endif

	tess.vbo = R_CreateVBO( "tessVertexArray_VBO", NULL, dataSize, VBO_USAGE_DYNAMIC );
	tess.vbo->ofsXYZ = 0;
	tess.vbo->ofsTexCoords = tess.vbo->ofsXYZ + sizeof( tess.xyz );
	tess.vbo->ofsLightCoords = tess.vbo->ofsTexCoords + sizeof( tess.texCoords );
	tess.vbo->ofsTangents = tess.vbo->ofsLightCoords + sizeof( tess.lightCoords );
	tess.vbo->ofsBinormals = tess.vbo->ofsTangents + sizeof( tess.tangents );
	tess.vbo->ofsNormals = tess.vbo->ofsBinormals + sizeof( tess.binormals );
	tess.vbo->ofsColors = tess.vbo->ofsNormals + sizeof( tess.normals );

#if !defined( COMPAT_Q3A ) && !defined( COMPAT_ET )
	tess.vbo->ofsPaintColors = tess.vbo->ofsColors + sizeof( tess.colors );
	tess.vbo->ofsAmbientLight = tess.vbo->ofsPaintColors + sizeof( tess.PaintColors );
#endif
	tess.vbo->ofsAmbientLight = tess.vbo->ofsColors + sizeof( tess.colors );
	tess.vbo->ofsDirectedLight = tess.vbo->ofsAmbientLight + sizeof( tess.ambientLights );
	tess.vbo->ofsLightDirections = tess.vbo->ofsDirectedLight + sizeof( tess.directedLights );

	tess.vbo->sizeXYZ = sizeof( tess.xyz );
	tess.vbo->sizeTangents = sizeof( tess.tangents );
	tess.vbo->sizeBinormals = sizeof( tess.binormals );
	tess.vbo->sizeNormals = sizeof( tess.normals );

	dataSize = sizeof( tess.indexes );

	tess.ibo = R_CreateIBO( "tessVertexArray_IBO", NULL, dataSize, VBO_USAGE_DYNAMIC );

	R_InitUnitCubeVBO();

	// allocate a PBO for color grade map transfers
	glGenBuffers( 1, &tr.colorGradePBO );
	glBindBuffer( GL_PIXEL_PACK_BUFFER, tr.colorGradePBO );
	glBufferData( GL_PIXEL_PACK_BUFFER,
		      REF_COLORGRADEMAP_STORE_SIZE * sizeof(color4ub_t),
		      NULL, GL_STREAM_COPY );
	glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );

	R_BindNullVBO();
	R_BindNullIBO();

	GL_CheckErrors();
}
Exemple #3
0
/*
============
R_InitVBOs
============
*/
void R_InitVBOs( void )
{
	int  dataSize;
	byte *data;

	ri.Printf( PRINT_ALL, "------- R_InitVBOs -------\n" );

	Com_InitGrowList( &tr.vbos, 100 );
	Com_InitGrowList( &tr.ibos, 100 );

	dataSize = sizeof( vec4_t ) * SHADER_MAX_VERTEXES * 11;
	data = Com_Allocate( dataSize );
	memset( data, 0, dataSize );

	tess.vbo = R_CreateVBO( "tessVertexArray_VBO", data, dataSize, VBO_USAGE_DYNAMIC );
	tess.vbo->ofsXYZ = 0;
	tess.vbo->ofsTexCoords = tess.vbo->ofsXYZ + sizeof( tess.xyz );
	tess.vbo->ofsLightCoords = tess.vbo->ofsTexCoords + sizeof( tess.texCoords );
	tess.vbo->ofsTangents = tess.vbo->ofsLightCoords + sizeof( tess.lightCoords );
	tess.vbo->ofsBinormals = tess.vbo->ofsTangents + sizeof( tess.tangents );
	tess.vbo->ofsNormals = tess.vbo->ofsBinormals + sizeof( tess.binormals );
	tess.vbo->ofsColors = tess.vbo->ofsNormals + sizeof( tess.normals );

#if !defined( COMPAT_Q3A ) && !defined( COMPAT_ET )
	tess.vbo->ofsPaintColors = tess.vbo->ofsColors + sizeof( tess.colors );
	tess.vbo->ofsLightDirections = tess.vbo->ofsPaintColors + sizeof( tess.paintColors );
#endif

	tess.vbo->sizeXYZ = sizeof( tess.xyz );
	tess.vbo->sizeTangents = sizeof( tess.tangents );
	tess.vbo->sizeBinormals = sizeof( tess.binormals );
	tess.vbo->sizeNormals = sizeof( tess.normals );

	Com_Dealloc( data );

	dataSize = sizeof( tess.indexes );
	data = Com_Allocate( dataSize );
	memset( data, 0, dataSize );

	tess.ibo = R_CreateIBO( "tessVertexArray_IBO", data, dataSize, VBO_USAGE_DYNAMIC );

	Com_Dealloc( data );

	R_InitUnitCubeVBO();

	R_BindNullVBO();
	R_BindNullIBO();

	GL_CheckErrors();
}
Exemple #4
0
/*
============
R_InitVBOs
============
*/
void R_InitVBOs(void)
{
	int  dataSize;
	byte *data;

	Ren_Print("------- R_InitVBOs -------\n");

	Com_InitGrowList(&tr.vbos, 100);
	Com_InitGrowList(&tr.ibos, 100);

	dataSize = sizeof(vec4_t) * SHADER_MAX_VERTEXES * 11;
	data     = (byte *)Com_Allocate(dataSize);
	memset(data, 0, dataSize);

	tess.vbo                 = R_CreateVBO("tessVertexArray_VBO", data, dataSize, VBO_USAGE_DYNAMIC);
	tess.vbo->ofsXYZ         = 0;
	tess.vbo->ofsTexCoords   = tess.vbo->ofsXYZ + sizeof(tess.xyz);
	tess.vbo->ofsLightCoords = tess.vbo->ofsTexCoords + sizeof(tess.texCoords);
	tess.vbo->ofsTangents    = tess.vbo->ofsLightCoords + sizeof(tess.lightCoords);
	tess.vbo->ofsBinormals   = tess.vbo->ofsTangents + sizeof(tess.tangents);
	tess.vbo->ofsNormals     = tess.vbo->ofsBinormals + sizeof(tess.binormals);
	tess.vbo->ofsColors      = tess.vbo->ofsNormals + sizeof(tess.normals);
	tess.vbo->sizeXYZ        = sizeof(tess.xyz);
	tess.vbo->sizeTangents   = sizeof(tess.tangents);
	tess.vbo->sizeBinormals  = sizeof(tess.binormals);
	tess.vbo->sizeNormals    = sizeof(tess.normals);

	Com_Dealloc(data);

	dataSize = sizeof(tess.indexes);
	data     = (byte *)Com_Allocate(dataSize);
	memset(data, 0, dataSize);

	tess.ibo = R_CreateIBO("tessVertexArray_IBO", data, dataSize, VBO_USAGE_DYNAMIC);

	Com_Dealloc(data);

	R_InitUnitCubeVBO();

	R_BindNullVBO();
	R_BindNullIBO();

	GL_CheckErrors();
}
Exemple #5
0
/*
=================
R_LoadMDC
=================
*/
qboolean R_LoadMDC(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName)
{
	int                i, j, k;
	mdcHeader_t        *mdcModel = ( mdcHeader_t * ) buffer;
	md3Frame_t         *mdcFrame;
	mdcSurface_t       *mdcSurf;
	md3Shader_t        *mdcShader;
	md3Triangle_t      *mdcTri;
	md3St_t            *mdcst;
	md3XyzNormal_t     *mdcxyz;
	mdcXyzCompressed_t *mdcxyzComp;
	mdcTag_t           *mdcTag;
	mdcTagName_t       *mdcTagName;
	mdvModel_t         *mdvModel;
	mdvFrame_t         *frame;
	mdvSurface_t       *surf; //, *surface; //unused
	srfTriangle_t      *tri;
	mdvXyz_t           *v;
	mdvSt_t            *st;
	mdvTag_t           *tag;
	mdvTagName_t       *tagName;
	short              *ps;
	int                version;
	int                size;

	version = LittleLong(mdcModel->version);

	if (version != MDC_VERSION)
	{
		Ren_Warning("R_LoadMD3: %s has wrong version (%i should be %i)\n", modName, version, MDC_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;
	size           = LittleLong(mdcModel->ofsEnd);
	mod->dataSize += size;
	mdvModel       = mod->mdv[lod] = ri.Hunk_Alloc(sizeof(mdvModel_t), h_low);

	LL(mdcModel->ident);
	LL(mdcModel->version);
	LL(mdcModel->numFrames);
	LL(mdcModel->numTags);
	LL(mdcModel->numSurfaces);
	LL(mdcModel->ofsFrames);
	LL(mdcModel->ofsTags);
	LL(mdcModel->ofsSurfaces);
	LL(mdcModel->ofsEnd);
	LL(mdcModel->ofsEnd);
	LL(mdcModel->flags);
	LL(mdcModel->numSkins);

	if (mdcModel->numFrames < 1)
	{
		Ren_Warning("R_LoadMDC: '%s' has no frames\n", modName);
		return qfalse;
	}

	// swap all the frames
	mdvModel->numFrames = mdcModel->numFrames;
	mdvModel->frames    = frame = ri.Hunk_Alloc(sizeof(*frame) * mdcModel->numFrames, h_low);

	mdcFrame = ( md3Frame_t * )(( byte * ) mdcModel + mdcModel->ofsFrames);

	for (i = 0; i < mdcModel->numFrames; i++, frame++, mdcFrame++)
	{
#if 1
		// ET HACK
		if (strstr(mod->name, "sherman") || strstr(mod->name, "mg42"))
		{
			frame->radius = 256;

			for (j = 0; j < 3; j++)
			{
				frame->bounds[0][j]   = 128;
				frame->bounds[1][j]   = -128;
				frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]);
			}
		}
		else
#endif
		{
			frame->radius = LittleFloat(mdcFrame->radius);

			for (j = 0; j < 3; j++)
			{
				frame->bounds[0][j]   = LittleFloat(mdcFrame->bounds[0][j]);
				frame->bounds[1][j]   = LittleFloat(mdcFrame->bounds[1][j]);
				frame->localOrigin[j] = LittleFloat(mdcFrame->localOrigin[j]);
			}
		}
	}

	// swap all the tags
	mdvModel->numTags = mdcModel->numTags;
	mdvModel->tags    = tag = ri.Hunk_Alloc(sizeof(*tag) * (mdcModel->numTags * mdcModel->numFrames), h_low);

	mdcTag = ( mdcTag_t * )(( byte * ) mdcModel + mdcModel->ofsTags);

	for (i = 0; i < mdcModel->numTags * mdcModel->numFrames; i++, tag++, mdcTag++)
	{
		vec3_t angles;

		for (j = 0; j < 3; j++)
		{
			tag->origin[j] = ( float ) LittleShort(mdcTag->xyz[j]) * MD3_XYZ_SCALE;
			angles[j]      = ( float ) LittleShort(mdcTag->angles[j]) * MDC_TAG_ANGLE_SCALE;
		}

		AnglesToAxis(angles, tag->axis);
	}

	mdvModel->tagNames = tagName = ri.Hunk_Alloc(sizeof(*tagName) * (mdcModel->numTags), h_low);

	mdcTagName = ( mdcTagName_t * )(( byte * ) mdcModel + mdcModel->ofsTagNames);

	for (i = 0; i < mdcModel->numTags; i++, tagName++, mdcTagName++)
	{
		Q_strncpyz(tagName->name, mdcTagName->name, sizeof(tagName->name));
	}

	// swap all the surfaces
	mdvModel->numSurfaces = mdcModel->numSurfaces;
	mdvModel->surfaces    = surf = ri.Hunk_Alloc(sizeof(*surf) * mdcModel->numSurfaces, h_low);

	mdcSurf = ( mdcSurface_t * )(( byte * ) mdcModel + mdcModel->ofsSurfaces);

	for (i = 0; i < mdcModel->numSurfaces; i++)
	{
		LL(mdcSurf->ident);
		LL(mdcSurf->flags);
		LL(mdcSurf->numBaseFrames);
		LL(mdcSurf->numCompFrames);
		LL(mdcSurf->numShaders);
		LL(mdcSurf->numTriangles);
		LL(mdcSurf->ofsTriangles);
		LL(mdcSurf->numVerts);
		LL(mdcSurf->ofsShaders);
		LL(mdcSurf->ofsSt);
		LL(mdcSurf->ofsXyzNormals);
		LL(mdcSurf->ofsXyzNormals);
		LL(mdcSurf->ofsXyzCompressed);
		LL(mdcSurf->ofsFrameBaseFrames);
		LL(mdcSurf->ofsFrameCompFrames);
		LL(mdcSurf->ofsEnd);

		if (mdcSurf->numVerts > SHADER_MAX_VERTEXES)
		{
			Ren_Drop("R_LoadMDC: %s has more than %i verts on a surface (%i)",
			         modName, SHADER_MAX_VERTEXES, mdcSurf->numVerts);
		}

		if (mdcSurf->numTriangles > SHADER_MAX_TRIANGLES)
		{
			Ren_Drop("R_LoadMDC: %s has more than %i triangles on a surface (%i)",
			         modName, SHADER_MAX_TRIANGLES, mdcSurf->numTriangles);
		}

		// change to surface identifier
		surf->surfaceType = SF_MDV;

		// give pointer to model for Tess_SurfaceMDX
		surf->model = mdvModel;

		// copy surface name
		Q_strncpyz(surf->name, mdcSurf->name, sizeof(surf->name));

		// lowercase the surface name so skin compares are faster
		Q_strlwr(surf->name);

		// strip off a trailing _1 or _2
		// this is a crutch for q3data being a mess
		j = strlen(surf->name);

		if (j > 2 && surf->name[j - 2] == '_')
		{
			surf->name[j - 2] = 0;
		}

		// register the shaders

		/*
		   surf->numShaders = md3Surf->numShaders;
		   surf->shaders = shader = ri.Hunk_Alloc(sizeof(*shader) * md3Surf->numShaders, h_low);

		   md3Shader = (md3Shader_t *) ((byte *) md3Surf + md3Surf->ofsShaders);
		   for(j = 0; j < md3Surf->numShaders; j++, shader++, md3Shader++)
		   {
		   shader_t       *sh;

		   sh = R_FindShader(md3Shader->name, SHADER_3D_DYNAMIC, RSF_DEFAULT);
		   if(sh->defaultShader)
		   {
		   shader->shaderIndex = 0;
		   }
		   else
		   {
		   shader->shaderIndex = sh->index;
		   }
		   }
		 */

		// only consider the first shader
		mdcShader    = ( md3Shader_t * )(( byte * ) mdcSurf + mdcSurf->ofsShaders);
		surf->shader = R_FindShader(mdcShader->name, SHADER_3D_DYNAMIC, qtrue);

		// swap all the triangles
		surf->numTriangles = mdcSurf->numTriangles;
		surf->triangles    = tri = ri.Hunk_Alloc(sizeof(*tri) * mdcSurf->numTriangles, h_low);

		mdcTri = ( md3Triangle_t * )(( byte * ) mdcSurf + mdcSurf->ofsTriangles);

		for (j = 0; j < mdcSurf->numTriangles; j++, tri++, mdcTri++)
		{
			tri->indexes[0] = LittleLong(mdcTri->indexes[0]);
			tri->indexes[1] = LittleLong(mdcTri->indexes[1]);
			tri->indexes[2] = LittleLong(mdcTri->indexes[2]);
		}

		// swap all the XyzNormals
		mdcxyz = ( md3XyzNormal_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzNormals);

		for (j = 0; j < mdcSurf->numVerts * mdcSurf->numBaseFrames; j++, mdcxyz++)
		{
			mdcxyz->xyz[0] = LittleShort(mdcxyz->xyz[0]);
			mdcxyz->xyz[1] = LittleShort(mdcxyz->xyz[1]);
			mdcxyz->xyz[2] = LittleShort(mdcxyz->xyz[2]);

			mdcxyz->normal = LittleShort(mdcxyz->normal);
		}

		// swap all the XyzCompressed
		mdcxyzComp = ( mdcXyzCompressed_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed);

		for (j = 0; j < mdcSurf->numVerts * mdcSurf->numCompFrames; j++, mdcxyzComp++)
		{
			LL(mdcxyzComp->ofsVec);
		}

		// swap the frameBaseFrames
		ps = ( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames);

		for (j = 0; j < mdcModel->numFrames; j++, ps++)
		{
			*ps = LittleShort(*ps);
		}

		// swap the frameCompFrames
		ps = ( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames);

		for (j = 0; j < mdcModel->numFrames; j++, ps++)
		{
			*ps = LittleShort(*ps);
		}

		surf->numVerts = mdcSurf->numVerts;
		surf->verts    = v = ri.Hunk_Alloc(sizeof(*v) * (mdcSurf->numVerts * mdcModel->numFrames), h_low);

		for (j = 0; j < mdcModel->numFrames; j++)
		{
			int baseFrame;
			int compFrame = 0;

			baseFrame = ( int ) *(( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameBaseFrames) + j);

			mdcxyz = ( md3XyzNormal_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzNormals + baseFrame * mdcSurf->numVerts * sizeof(md3XyzNormal_t));

			if (mdcSurf->numCompFrames > 0)
			{
				compFrame = ( int ) *(( short * )(( byte * ) mdcSurf + mdcSurf->ofsFrameCompFrames) + j);

				if (compFrame >= 0)
				{
					mdcxyzComp = ( mdcXyzCompressed_t * )(( byte * ) mdcSurf + mdcSurf->ofsXyzCompressed + compFrame * mdcSurf->numVerts * sizeof(mdcXyzCompressed_t));
				}
			}

			for (k = 0; k < mdcSurf->numVerts; k++, v++, mdcxyz++)
			{
				v->xyz[0] = LittleShort(mdcxyz->xyz[0]) * MD3_XYZ_SCALE;
				v->xyz[1] = LittleShort(mdcxyz->xyz[1]) * MD3_XYZ_SCALE;
				v->xyz[2] = LittleShort(mdcxyz->xyz[2]) * MD3_XYZ_SCALE;

				if (mdcSurf->numCompFrames > 0 && compFrame >= 0)
				{
					vec3_t ofsVec;

					R_MDC_DecodeXyzCompressed2(LittleShort(mdcxyzComp->ofsVec), ofsVec);
					VectorAdd(v->xyz, ofsVec, v->xyz);

					mdcxyzComp++;
				}
			}
		}

		// swap all the ST
		surf->st = st = ri.Hunk_Alloc(sizeof(*st) * mdcSurf->numVerts, h_low);

		mdcst = ( md3St_t * )(( byte * ) mdcSurf + mdcSurf->ofsSt);

		for (j = 0; j < mdcSurf->numVerts; j++, mdcst++, st++)
		{
			st->st[0] = LittleFloat(mdcst->st[0]);
			st->st[1] = LittleFloat(mdcst->st[1]);
		}

		// find the next surface
		mdcSurf = ( mdcSurface_t * )(( byte * ) mdcSurf + mdcSurf->ofsEnd);
		surf++;
	}

#if 1
	// create VBO surfaces from md3 surfaces
	{
		mdvNormTanBi_t *vertexes;
		mdvNormTanBi_t *vert;

		growList_t      vboSurfaces;
		srfVBOMDVMesh_t *vboSurf;

		byte *data;
		int  dataSize;
		int  dataOfs;

		vec4_t tmp;

		GLuint ofsTexCoords;
		GLuint ofsTangents;
		GLuint ofsBinormals;
		GLuint ofsNormals;

		GLuint sizeXYZ       = 0;
		GLuint sizeTangents  = 0;
		GLuint sizeBinormals = 0;
		GLuint sizeNormals   = 0;

		int vertexesNum;
		int f;

		Com_InitGrowList(&vboSurfaces, 10);

		for (i = 0, surf = mdvModel->surfaces; i < mdvModel->numSurfaces; i++, surf++)
		{
			//allocate temp memory for vertex data
			vertexes = (mdvNormTanBi_t *)ri.Hunk_AllocateTempMemory(sizeof(*vertexes) * surf->numVerts * mdvModel->numFrames);

			// calc tangent spaces
			{
				const float *v0, *v1, *v2;
				const float *t0, *t1, *t2;
				vec3_t      tangent;
				vec3_t      binormal;
				vec3_t      normal;

				for (j = 0, vert = vertexes; j < (surf->numVerts * mdvModel->numFrames); j++, vert++)
				{
					VectorClear(vert->tangent);
					VectorClear(vert->binormal);
					VectorClear(vert->normal);
				}

				for (f = 0; f < mdvModel->numFrames; f++)
				{
					for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
					{
						v0 = surf->verts[surf->numVerts * f + tri->indexes[0]].xyz;
						v1 = surf->verts[surf->numVerts * f + tri->indexes[1]].xyz;
						v2 = surf->verts[surf->numVerts * f + tri->indexes[2]].xyz;

						t0 = surf->st[tri->indexes[0]].st;
						t1 = surf->st[tri->indexes[1]].st;
						t2 = surf->st[tri->indexes[2]].st;

#if 1
						R_CalcTangentSpace(tangent, binormal, normal, v0, v1, v2, t0, t1, t2);
#else
						R_CalcNormalForTriangle(normal, v0, v1, v2);
						R_CalcTangentsForTriangle(tangent, binormal, v0, v1, v2, t0, t1, t2);
#endif

						for (k = 0; k < 3; k++)
						{
							float *v;

							v = vertexes[surf->numVerts * f + tri->indexes[k]].tangent;
							VectorAdd(v, tangent, v);

							v = vertexes[surf->numVerts * f + tri->indexes[k]].binormal;
							VectorAdd(v, binormal, v);

							v = vertexes[surf->numVerts * f + tri->indexes[k]].normal;
							VectorAdd(v, normal, v);
						}
					}
				}

				for (j = 0, vert = vertexes; j < (surf->numVerts * mdvModel->numFrames); j++, vert++)
				{
					VectorNormalize(vert->tangent);
					VectorNormalize(vert->binormal);
					VectorNormalize(vert->normal);
				}
			}

			//Ren_Print("...calculating MDC mesh VBOs ( '%s', %i verts %i tris )\n", surf->name, surf->numVerts, surf->numTriangles);

			// create surface
			vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
			Com_AddToGrowList(&vboSurfaces, vboSurf);

			vboSurf->surfaceType = SF_VBO_MDVMESH;
			vboSurf->mdvModel    = mdvModel;
			vboSurf->mdvSurface  = surf;
			vboSurf->numIndexes  = surf->numTriangles * 3;
			vboSurf->numVerts    = surf->numVerts;

			/*
			vboSurf->vbo = R_CreateVBO2(va("staticWorldMesh_vertices %i", vboSurfaces.currentElements), numVerts, optimizedVerts,
			                                                   ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_TANGENT | ATTR_BINORMAL | ATTR_NORMAL
			                                                   | ATTR_COLOR);
			                                                   */

			vboSurf->ibo = R_CreateIBO2(va("staticMDCMesh_IBO %s", surf->name), surf->numTriangles, surf->triangles, VBO_USAGE_STATIC);

			// create VBO
			vertexesNum = surf->numVerts;

			dataSize = (surf->numVerts * mdvModel->numFrames * sizeof(vec4_t) * 4) +      // xyz, tangent, binormal, normal
			           (surf->numVerts * sizeof(vec4_t));      // texcoords
			data    = ri.Hunk_AllocateTempMemory(dataSize);
			dataOfs = 0;

			// feed vertex XYZ
			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = surf->verts[f * vertexesNum + j].xyz[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeXYZ = dataOfs;
				}
			}

			// feed vertex texcoords
			ofsTexCoords = dataOfs;

			for (j = 0; j < vertexesNum; j++)
			{
				for (k = 0; k < 2; k++)
				{
					tmp[k] = surf->st[j].st[k];
				}

				tmp[2] = 0;
				tmp[3] = 1;
				Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
				dataOfs += sizeof(vec4_t);
			}

			// feed vertex tangents
			ofsTangents = dataOfs;

			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].tangent[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeTangents = dataOfs - ofsTangents;
				}
			}

			// feed vertex binormals
			ofsBinormals = dataOfs;

			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].binormal[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeBinormals = dataOfs - ofsBinormals;
				}
			}

			// feed vertex normals
			ofsNormals = dataOfs;

			for (f = 0; f < mdvModel->numFrames; f++)
			{
				for (j = 0; j < vertexesNum; j++)
				{
					for (k = 0; k < 3; k++)
					{
						tmp[k] = vertexes[f * vertexesNum + j].normal[k];
					}

					tmp[3] = 1;
					Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
					dataOfs += sizeof(vec4_t);
				}

				if (f == 0)
				{
					sizeNormals = dataOfs - ofsNormals;
				}
			}

			vboSurf->vbo                 = R_CreateVBO(va("staticMDCMesh_VBO '%s'", surf->name), data, dataSize, VBO_USAGE_STATIC);
			vboSurf->vbo->ofsXYZ         = 0;
			vboSurf->vbo->ofsTexCoords   = ofsTexCoords;
			vboSurf->vbo->ofsLightCoords = ofsTexCoords;
			vboSurf->vbo->ofsTangents    = ofsTangents;
			vboSurf->vbo->ofsBinormals   = ofsBinormals;
			vboSurf->vbo->ofsNormals     = ofsNormals;

			vboSurf->vbo->sizeXYZ       = sizeXYZ;
			vboSurf->vbo->sizeTangents  = sizeTangents;
			vboSurf->vbo->sizeBinormals = sizeBinormals;
			vboSurf->vbo->sizeNormals   = sizeNormals;

			ri.Hunk_FreeTempMemory(data);
			ri.Hunk_FreeTempMemory(vertexes);
		}

		// move VBO surfaces list to hunk
		mdvModel->numVBOSurfaces = vboSurfaces.currentElements;
		mdvModel->vboSurfaces    = ri.Hunk_Alloc(mdvModel->numVBOSurfaces * sizeof(*mdvModel->vboSurfaces), h_low);

		for (i = 0; i < mdvModel->numVBOSurfaces; i++)
		{
			mdvModel->vboSurfaces[i] = ( srfVBOMDVMesh_t * ) Com_GrowListElement(&vboSurfaces, i);
		}

		Com_DestroyGrowList(&vboSurfaces);
	}
#endif

	return qtrue;
}
Exemple #6
0
void AddSurfaceToVBOSurfacesList2(growList_t *vboSurfaces, growList_t *vboTriangles, growList_t *vboVertexes, md5Model_t *md5, int skinIndex, const char *materialName, int numBoneReferences, int boneReferences[MAX_BONES])
{
	int j, k;

	int  vertexesNum;
	byte *data;
	int  dataSize;
	int  dataOfs;

	GLuint ofsTexCoords;
	GLuint ofsTangents;
	GLuint ofsBinormals;
	GLuint ofsNormals;
	GLuint ofsBoneIndexes;
	GLuint ofsBoneWeights;

	int  indexesNum;
	byte *indexes;
	int  indexesSize;
	int  indexesOfs;

	skelTriangle_t *tri;

	vec4_t tmp;
	int    index;

	srfVBOMD5Mesh_t *vboSurf;
	md5Vertex_t     *v;

	shader_t *shader;
	int      shaderIndex;

	vertexesNum = vboVertexes->currentElements;
	indexesNum  = vboTriangles->currentElements * 3;

	// create surface
	vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
	Com_AddToGrowList(vboSurfaces, vboSurf);

	vboSurf->surfaceType = SF_VBO_MD5MESH;
	vboSurf->md5Model    = md5;

	ri.Printf(PRINT_ALL, "AddSurfaceToVBOSurfacesList2: loading shader '%s'\n", materialName);
	shader = R_FindShader(materialName, SHADER_3D_DYNAMIC, qtrue);

	if (shader->defaultShader)
	{
		shaderIndex = 0;
	}
	else
	{
		shaderIndex = shader->index;
	}

	vboSurf->shader = R_GetShaderByHandle(shaderIndex);

	vboSurf->skinIndex  = skinIndex;
	vboSurf->numIndexes = indexesNum;
	vboSurf->numVerts   = vertexesNum;

	dataSize = vertexesNum * (sizeof(vec4_t) * 8);
	data     = ri.Hunk_AllocateTempMemory(dataSize);
	dataOfs  = 0;

	indexesSize = indexesNum * sizeof(int);
	indexes     = ri.Hunk_AllocateTempMemory(indexesSize);
	indexesOfs  = 0;

	//ri.Printf(PRINT_ALL, "AddSurfaceToVBOSurfacesList( %i verts, %i tris )\n", surf->numVerts, vboTriangles->currentElements);

	vboSurf->numBoneRemap = 0;
	Com_Memset(vboSurf->boneRemap, 0, sizeof(vboSurf->boneRemap));
	Com_Memset(vboSurf->boneRemapInverse, 0, sizeof(vboSurf->boneRemapInverse));

	//ri.Printf(PRINT_ALL, "referenced bones: ");
	for (j = 0; j < MAX_BONES; j++)
	{
		if (boneReferences[j] > 0)
		{
			vboSurf->boneRemap[j]                            = vboSurf->numBoneRemap;
			vboSurf->boneRemapInverse[vboSurf->numBoneRemap] = j;

			vboSurf->numBoneRemap++;

			//ri.Printf(PRINT_ALL, "(%i -> %i) ", j, vboSurf->boneRemap[j]);
		}
	}

	//ri.Printf(PRINT_ALL, "\n");

	//for(j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
	for (j = 0; j < vboTriangles->currentElements; j++)
	{
		tri = Com_GrowListElement(vboTriangles, j);

		for (k = 0; k < 3; k++)
		{
			index = tri->indexes[k];

			Com_Memcpy(indexes + indexesOfs, &index, sizeof(int));
			indexesOfs += sizeof(int);
		}
	}

	// feed vertex XYZ
	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < 3; k++)
		{
			tmp[k] = v->position[k];
		}

		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex texcoords
	ofsTexCoords = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < 2; k++)
		{
			tmp[k] = v->texCoords[k];
		}

		tmp[2] = 0;
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex tangents
	ofsTangents = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < 3; k++)
		{
			tmp[k] = v->tangent[k];
		}

		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex binormals
	ofsBinormals = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < 3; k++)
		{
			tmp[k] = v->binormal[k];
		}

		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex normals
	ofsNormals = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < 3; k++)
		{
			tmp[k] = v->normal[k];
		}

		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed bone indices
	ofsBoneIndexes = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < MAX_WEIGHTS; k++)
		{
			if (k < v->numWeights)
			{
				index = vboSurf->boneRemap[v->weights[k]->boneIndex];
			}
			else
			{
				index = 0;
			}

			Com_Memcpy(data + dataOfs, &index, sizeof(int));
			dataOfs += sizeof(int);
		}
	}

	// feed bone weights
	ofsBoneWeights = dataOfs;

	for (j = 0; j < vertexesNum; j++)
	{
		v = Com_GrowListElement(vboVertexes, j);

		for (k = 0; k < MAX_WEIGHTS; k++)
		{
			if (k < v->numWeights)
			{
				tmp[k] = v->weights[k]->boneWeight;
			}
			else
			{
				tmp[k] = 0;
			}
		}

		Com_Memcpy(data + dataOfs, ( vec_t * ) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	vboSurf->vbo                 = R_CreateVBO(va("staticMD5Mesh_VBO %i", vboSurfaces->currentElements), data, dataSize, VBO_USAGE_STATIC);
	vboSurf->vbo->ofsXYZ         = 0;
	vboSurf->vbo->ofsTexCoords   = ofsTexCoords;
	vboSurf->vbo->ofsLightCoords = ofsTexCoords;
	vboSurf->vbo->ofsTangents    = ofsTangents;
	vboSurf->vbo->ofsBinormals   = ofsBinormals;
	vboSurf->vbo->ofsNormals     = ofsNormals;
	vboSurf->vbo->ofsBoneIndexes = ofsBoneIndexes;
	vboSurf->vbo->ofsBoneWeights = ofsBoneWeights;

	vboSurf->ibo = R_CreateIBO(va("staticMD5Mesh_IBO %i", vboSurfaces->currentElements), indexes, indexesSize, VBO_USAGE_STATIC);

	ri.Hunk_FreeTempMemory(indexes);
	ri.Hunk_FreeTempMemory(data);

	// megs

	/*
	   ri.Printf(PRINT_ALL, "md5 mesh data VBO size: %d.%02d MB\n", dataSize / (1024 * 1024),
	   (dataSize % (1024 * 1024)) * 100 / (1024 * 1024));
	   ri.Printf(PRINT_ALL, "md5 mesh tris VBO size: %d.%02d MB\n", indexesSize / (1024 * 1024),
	   (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
	 */

	ri.Printf(PRINT_ALL, "created VBO surface %i with %i vertices and %i triangles\n", vboSurfaces->currentElements, vboSurf->numVerts, vboSurf->numIndexes / 3);
}
Exemple #7
0
static void AddSurfaceToVBOSurfacesListMDM( growList_t *vboSurfaces, growList_t *vboTriangles, mdmModel_t *mdm, mdmSurfaceIntern_t *surf, int skinIndex, int numBoneReferences, int boneReferences[ MAX_BONES ] )
{
	int             j, k, lod;

	int             vertexesNum;
	byte            *data;
	int             dataSize;
	int             dataOfs;

	GLuint          ofsTexCoords;
	GLuint          ofsTangents;
	GLuint          ofsBinormals;
	GLuint          ofsNormals;
	GLuint          ofsBoneIndexes;
	GLuint          ofsBoneWeights;

	int             indexesNum;
	byte            *indexes;
	int             indexesSize;
	int             indexesOfs;

	skelTriangle_t  *tri;

	vec4_t          tmp;
	int             index;

	srfVBOMDMMesh_t *vboSurf;
	md5Vertex_t     *v;

//	vec4_t          tmpColor = { 1, 1, 1, 1 };

	static int32_t collapse[ MDM_MAX_VERTS ];

	vertexesNum = surf->numVerts;
	indexesNum = vboTriangles->currentElements * 3;

	// create surface
	vboSurf = ri.Hunk_Alloc( sizeof( *vboSurf ), h_low );
	Com_AddToGrowList( vboSurfaces, vboSurf );

	vboSurf->surfaceType = SF_VBO_MDMMESH;
	vboSurf->mdmModel = mdm;
	vboSurf->mdmSurface = surf;
	vboSurf->shader = R_GetShaderByHandle( surf->shaderIndex );
	vboSurf->skinIndex = skinIndex;
	vboSurf->numIndexes = indexesNum;
	vboSurf->numVerts = vertexesNum;

	dataSize = vertexesNum * ( sizeof( vec4_t ) * 7 );
	data = ri.Hunk_AllocateTempMemory( dataSize );
	dataOfs = 0;

	//ri.Printf(PRINT_ALL, "AddSurfaceToVBOSurfacesList( %i verts, %i tris )\n", surf->numVerts, vboTriangles->currentElements);

	vboSurf->numBoneRemap = 0;
	Com_Memset( vboSurf->boneRemap, 0, sizeof( vboSurf->boneRemap ) );
	Com_Memset( vboSurf->boneRemapInverse, 0, sizeof( vboSurf->boneRemapInverse ) );

	//ri.Printf(PRINT_ALL, "original referenced bones: [ ");
	//for(j = 0; j < surf->numBoneReferences; j++)
	//{
	//  ri.Printf(PRINT_ALL, "%i, ", surf->boneReferences[j]);
	//}
	//ri.Printf(PRINT_ALL, "]\n");

	//ri.Printf(PRINT_ALL, "new referenced bones: ");
	for ( j = 0; j < MAX_BONES; j++ )
	{
		if ( boneReferences[ j ] > 0 )
		{
			vboSurf->boneRemap[ j ] = vboSurf->numBoneRemap;
			vboSurf->boneRemapInverse[ vboSurf->numBoneRemap ] = j;

			vboSurf->numBoneRemap++;

			//ri.Printf(PRINT_ALL, "(%i -> %i) ", j, vboSurf->boneRemap[j]);
		}
	}

	//ri.Printf(PRINT_ALL, "\n");

	// feed vertex XYZ
	for ( j = 0; j < vertexesNum; j++ )
	{
		for ( k = 0; k < 3; k++ )
		{
			tmp[ k ] = surf->verts[ j ].position[ k ];
		}

		tmp[ 3 ] = 1;
		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	// feed vertex texcoords
	ofsTexCoords = dataOfs;

	for ( j = 0; j < vertexesNum; j++ )
	{
		for ( k = 0; k < 2; k++ )
		{
			tmp[ k ] = surf->verts[ j ].texCoords[ k ];
		}

		tmp[ 2 ] = 0;
		tmp[ 3 ] = 1;
		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	// feed vertex tangents
	ofsTangents = dataOfs;

	for ( j = 0; j < vertexesNum; j++ )
	{
		for ( k = 0; k < 3; k++ )
		{
			tmp[ k ] = surf->verts[ j ].tangent[ k ];
		}

		tmp[ 3 ] = 1;
		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	// feed vertex binormals
	ofsBinormals = dataOfs;

	for ( j = 0; j < vertexesNum; j++ )
	{
		for ( k = 0; k < 3; k++ )
		{
			tmp[ k ] = surf->verts[ j ].binormal[ k ];
		}

		tmp[ 3 ] = 1;
		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	// feed vertex normals
	ofsNormals = dataOfs;

	for ( j = 0; j < vertexesNum; j++ )
	{
		for ( k = 0; k < 3; k++ )
		{
			tmp[ k ] = surf->verts[ j ].normal[ k ];
		}

		tmp[ 3 ] = 1;
		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	// feed bone indices
	ofsBoneIndexes = dataOfs;

	for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
	{
		for ( k = 0; k < MAX_WEIGHTS; k++ )
		{
			if ( k < v->numWeights )
			{
				index = vboSurf->boneRemap[ v->weights[ k ]->boneIndex ];
			}
			else
			{
				index = 0;
			}

			Com_Memcpy( data + dataOfs, &index, sizeof( int ) );
			dataOfs += sizeof( int );
		}
	}

	// feed bone weights
	ofsBoneWeights = dataOfs;

	for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
	{
		for ( k = 0; k < MAX_WEIGHTS; k++ )
		{
			if ( k < v->numWeights )
			{
				tmp[ k ] = v->weights[ k ]->boneWeight;
			}
			else
			{
				tmp[ k ] = 0;
			}
		}

		Com_Memcpy( data + dataOfs, ( vec_t * ) tmp, sizeof( vec4_t ) );
		dataOfs += sizeof( vec4_t );
	}

	vboSurf->vbo = R_CreateVBO( va( "staticMDMMesh_VBO %i", vboSurfaces->currentElements ), data, dataSize, VBO_USAGE_STATIC );
	vboSurf->vbo->ofsXYZ = 0;
	vboSurf->vbo->ofsTexCoords = ofsTexCoords;
	vboSurf->vbo->ofsLightCoords = ofsTexCoords;
	vboSurf->vbo->ofsTangents = ofsTangents;
	vboSurf->vbo->ofsBinormals = ofsBinormals;
	vboSurf->vbo->ofsNormals = ofsNormals;
	vboSurf->vbo->ofsColors = ofsNormals;
	vboSurf->vbo->ofsLightCoords = 0; // not required anyway
	vboSurf->vbo->ofsLightDirections = 0; // not required anyway
	vboSurf->vbo->ofsBoneIndexes = ofsBoneIndexes;
	vboSurf->vbo->ofsBoneWeights = ofsBoneWeights;

	// calculate LOD IBOs
	lod = 0;

	do
	{
		float flod;
		int   renderCount;

		flod = mdmLODResolutions[ lod ];

		renderCount = MIN( ( int )( ( float ) surf->numVerts * flod ), surf->numVerts );

		if ( renderCount < surf->minLod )
		{
			renderCount = surf->minLod;
			flod = ( float ) renderCount / surf->numVerts;
		}

		if ( renderCount == surf->numVerts )
		{
			indexesNum = vboTriangles->currentElements * 3;
			indexesSize = indexesNum * sizeof( int );
			indexes = ri.Hunk_AllocateTempMemory( indexesSize );
			indexesOfs = 0;

			for ( j = 0; j < vboTriangles->currentElements; j++ )
			{
				tri = Com_GrowListElement( vboTriangles, j );

				for ( k = 0; k < 3; k++ )
				{
					index = tri->indexes[ k ];

					Com_Memcpy( indexes + indexesOfs, &index, sizeof( int ) );
					indexesOfs += sizeof( int );
				}
			}
		}
		else
		{
			int     ci[ 3 ];
			int32_t *pCollapseMap;
			int32_t *pCollapse;

			pCollapse = collapse;

			for ( j = 0; j < renderCount; pCollapse++, j++ )
			{
				*pCollapse = j;
			}

			pCollapseMap = &surf->collapseMap[ renderCount ];

			for ( j = renderCount; j < surf->numVerts; j++, pCollapse++, pCollapseMap++ )
			{
				int32_t collapseValue = *pCollapseMap;
				*pCollapse = collapse[ collapseValue ];
			}

			indexesNum = 0;

			for ( j = 0; j < vboTriangles->currentElements; j++ )
			{
				tri = Com_GrowListElement( vboTriangles, j );

				ci[ 0 ] = collapse[ tri->indexes[ 0 ] ];
				ci[ 1 ] = collapse[ tri->indexes[ 1 ] ];
				ci[ 2 ] = collapse[ tri->indexes[ 2 ] ];

				// FIXME
				// note:  serious optimization opportunity here,
				//  by sorting the triangles the following "continue"
				//  could have been made into a "break" statement.
				if ( ci[ 0 ] == ci[ 1 ] || ci[ 1 ] == ci[ 2 ] || ci[ 2 ] == ci[ 0 ] )
				{
					continue;
				}

				indexesNum += 3;
			}

			indexesSize = indexesNum * sizeof( int );
			indexes = ri.Hunk_AllocateTempMemory( indexesSize );
			indexesOfs = 0;

			for ( j = 0; j < vboTriangles->currentElements; j++ )
			{
				tri = Com_GrowListElement( vboTriangles, j );

				ci[ 0 ] = collapse[ tri->indexes[ 0 ] ];
				ci[ 1 ] = collapse[ tri->indexes[ 1 ] ];
				ci[ 2 ] = collapse[ tri->indexes[ 2 ] ];

				// FIXME
				// note:  serious optimization opportunity here,
				//  by sorting the triangles the following "continue"
				//  could have been made into a "break" statement.
				if ( ci[ 0 ] == ci[ 1 ] || ci[ 1 ] == ci[ 2 ] || ci[ 2 ] == ci[ 0 ] )
				{
					continue;
				}

				for ( k = 0; k < 3; k++ )
				{
					index = ci[ k ];

					Com_Memcpy( indexes + indexesOfs, &index, sizeof( int ) );
					indexesOfs += sizeof( int );
				}
			}
		}

		vboSurf->ibo[ lod ] = R_CreateIBO( va( "staticMDMMesh_IBO_LOD_%f %i", flod, indexesNum / 3 ), indexes, indexesSize, VBO_USAGE_STATIC );
		vboSurf->ibo[ lod ]->indexesNum = indexesNum;

		ri.Hunk_FreeTempMemory( indexes );

		if ( vboTriangles->currentElements != surf->numTriangles )
		{
			ri.Printf( PRINT_WARNING, "Can't calculate LOD IBOs\n" );
			break;
		}

		lod++;
	}
	while ( lod < MD3_MAX_LODS );

	ri.Hunk_FreeTempMemory( data );

	// megs

	/*
	   ri.Printf(PRINT_ALL, "md5 mesh data VBO size: %d.%02d MB\n", dataSize / (1024 * 1024),
	   (dataSize % (1024 * 1024)) * 100 / (1024 * 1024));
	   ri.Printf(PRINT_ALL, "md5 mesh tris VBO size: %d.%02d MB\n", indexesSize / (1024 * 1024),
	   (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
	 */
}
void AddSurfaceToVBOSurfacesList(growList_t * vboSurfaces, growList_t * vboTriangles, md5Model_t * md5, md5Surface_t * surf, int skinIndex, int numBoneReferences, int boneReferences[MAX_BONES])
{
	int				j, k;

	int             vertexesNum;
	byte           *data;
	int             dataSize;
	int             dataOfs;

	GLuint          ofsTexCoords;
	GLuint          ofsTangents;
	GLuint          ofsBinormals;
	GLuint          ofsNormals;
	GLuint          ofsColors;
	GLuint          ofsBoneIndexes;
	GLuint          ofsBoneWeights;

	int             indexesNum;
	byte           *indexes;
	int             indexesSize;
	int             indexesOfs;

	skelTriangle_t  *tri;

	vec4_t          tmp;
	int             index;

	srfVBOMD5Mesh_t *vboSurf;
	md5Vertex_t     *v;

	vec4_t          tmpColor = { 1, 1, 1, 1 };

	vertexesNum = surf->numVerts;
	indexesNum = vboTriangles->currentElements * 3;

	// create surface
	vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
	Com_AddToGrowList(vboSurfaces, vboSurf);

	vboSurf->surfaceType = SF_VBO_MD5MESH;
	vboSurf->md5Model = md5;
	vboSurf->shader = R_GetShaderByHandle(surf->shaderIndex);
	vboSurf->skinIndex = skinIndex;
	vboSurf->numIndexes = indexesNum;
	vboSurf->numVerts = vertexesNum;

	dataSize = vertexesNum * (sizeof(vec4_t) * 8);
	data = ri.Hunk_AllocateTempMemory(dataSize);
	dataOfs = 0;

	indexesSize = indexesNum * sizeof(int);
	indexes = ri.Hunk_AllocateTempMemory(indexesSize);
	indexesOfs = 0;

	//ri.Printf(PRINT_ALL, "AddSurfaceToVBOSurfacesList( %i verts, %i tris )\n", surf->numVerts, vboTriangles->currentElements);

	vboSurf->numBoneRemap = 0;
	Com_Memset(vboSurf->boneRemap, 0, sizeof(vboSurf->boneRemap));
	Com_Memset(vboSurf->boneRemapInverse, 0, sizeof(vboSurf->boneRemapInverse));

	//ri.Printf(PRINT_ALL, "referenced bones: ");
	for(j = 0; j < MAX_BONES; j++)
	{
		if(boneReferences[j] > 0)
		{
			vboSurf->boneRemap[j] = vboSurf->numBoneRemap;
			vboSurf->boneRemapInverse[vboSurf->numBoneRemap] = j;

			vboSurf->numBoneRemap++;

			//ri.Printf(PRINT_ALL, "(%i -> %i) ", j, vboSurf->boneRemap[j]);
		}
	}
	//ri.Printf(PRINT_ALL, "\n");

	//for(j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
	for(j = 0; j < vboTriangles->currentElements; j++)
	{
		tri = Com_GrowListElement(vboTriangles, j);

		for(k = 0; k < 3; k++)
		{
			index = tri->indexes[k];

			Com_Memcpy(indexes + indexesOfs, &index, sizeof(int));
			indexesOfs += sizeof(int);
		}
	}

	// feed vertex XYZ
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].position[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex texcoords
	ofsTexCoords = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 2; k++)
		{
			tmp[k] = surf->verts[j].texCoords[k];
		}
		tmp[2] = 0;
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex tangents
	ofsTangents = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].tangent[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex binormals
	ofsBinormals = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].binormal[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex normals
	ofsNormals = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		for(k = 0; k < 3; k++)
		{
			tmp[k] = surf->verts[j].normal[k];
		}
		tmp[3] = 1;
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed vertex colors
	ofsColors = dataOfs;
	for(j = 0; j < vertexesNum; j++)
	{
		Com_Memcpy(data + dataOfs, tmpColor, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	// feed bone indices
	ofsBoneIndexes = dataOfs;
	for(j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
	{
		for(k = 0; k < MAX_WEIGHTS; k++)
		{
			if(k < v->numWeights)
				index = vboSurf->boneRemap[v->weights[k]->boneIndex];
			else
				index = 0;

			Com_Memcpy(data + dataOfs, &index, sizeof(int));
			dataOfs += sizeof(int);
		}
	}

	// feed bone weights
	ofsBoneWeights = dataOfs;
	for(j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
	{
		for(k = 0; k < MAX_WEIGHTS; k++)
		{
			if(k < v->numWeights)
				tmp[k] = v->weights[k]->boneWeight;
			else
				tmp[k] = 0;
		}
		Com_Memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
		dataOfs += sizeof(vec4_t);
	}

	vboSurf->vbo = R_CreateVBO(va("staticMD5Mesh_VBO %i", vboSurfaces->currentElements), data, dataSize, VBO_USAGE_STATIC);
	vboSurf->vbo->ofsXYZ = 0;
	vboSurf->vbo->ofsTexCoords = ofsTexCoords;
	vboSurf->vbo->ofsLightCoords = ofsTexCoords;
	vboSurf->vbo->ofsTangents = ofsTangents;
	vboSurf->vbo->ofsBinormals = ofsBinormals;
	vboSurf->vbo->ofsNormals = ofsNormals;
	vboSurf->vbo->ofsColors = ofsColors;
	vboSurf->vbo->ofsLightCoords = ofsColors;		// not required anyway
	vboSurf->vbo->ofsLightDirections = ofsColors;	// not required anyway
	vboSurf->vbo->ofsBoneIndexes = ofsBoneIndexes;
	vboSurf->vbo->ofsBoneWeights = ofsBoneWeights;

	vboSurf->ibo = R_CreateIBO(va("staticMD5Mesh_IBO %i", vboSurfaces->currentElements), indexes, indexesSize, VBO_USAGE_STATIC);

	ri.Hunk_FreeTempMemory(indexes);
	ri.Hunk_FreeTempMemory(data);

	// megs
	/*
	   ri.Printf(PRINT_ALL, "md5 mesh data VBO size: %d.%02d MB\n", dataSize / (1024 * 1024),
	   (dataSize % (1024 * 1024)) * 100 / (1024 * 1024));
	   ri.Printf(PRINT_ALL, "md5 mesh tris VBO size: %d.%02d MB\n", indexesSize / (1024 * 1024),
	   (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024));
	 */
}