示例#1
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();
}
示例#2
0
	void LoadRGBEToHalfs( const char *name, unsigned short **halfImage, int *width, int *height )
	{
		int            i, j;
		int            w, h;
		float          *hdrImage;
		float          *floatbuf;
		unsigned short *halfbuf;

#if 0
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qtrue, qtrue );

		*width = w;
		*height = h;

		*ldrImage = ri.Malloc( w * h * 4 );
		pixbuf = *ldrImage;

		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				sample[ j ] = *floatbuf++;
			}

			NormalizeColor( sample, sample );

			*pixbuf++ = ( byte )( sample[ 0 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 1 ] * 255 );
			*pixbuf++ = ( byte )( sample[ 2 ] * 255 );
			*pixbuf++ = ( byte ) 255;
		}

#else
		w = h = 0;
		LoadRGBEToFloats( name, &hdrImage, &w, &h, qtrue, qfalse, qtrue );

		*width = w;
		*height = h;

		*halfImage = ( unsigned short * ) Com_Allocate( w * h * 3 * 6 );

		halfbuf = *halfImage;
		floatbuf = hdrImage;

		for ( i = 0; i < ( w * h ); i++ )
		{
			for ( j = 0; j < 3; j++ )
			{
				half sample( *floatbuf++ );
				*halfbuf++ = sample.bits();
			}
		}

#endif

		Com_Dealloc( hdrImage );
	}
示例#3
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();
}
示例#4
0
static JavaVMOption* AllocOption(growList_t * growOptions)
{
	JavaVMOption   *option;

	option = Com_Allocate(sizeof(*option));
	Com_Memset(option, 0, sizeof(*option));

	Com_AddToGrowList(growOptions, option);

	return option;
}
示例#5
0
/**
 * @brief SND_setup
 */
void SND_setup(void)
{
	sndBuffer *p, *q;
	cvar_t    *cv;
	int       scs;

	cv  = Cvar_Get("com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE);
	scs = (cv->integer * 512); // q3 uses a value of 1536 - reverted to genuine ET value

	buffer = Com_Allocate(scs * sizeof(sndBuffer));
	if (!buffer)
	{
		Com_Error(ERR_FATAL, "Sound buffer failed to allocate %1.1f megs", (double)(scs / (1024.f * 1024.f)));
	}

	// allocate the stack based hunk allocator
	sfxScratchBuffer = Com_Allocate(SND_CHUNK_SIZE * sizeof(short) * 4);      //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
	if (!sfxScratchBuffer)
	{
		Com_Error(ERR_FATAL, "Unable to allocate sound scratch buffer");
	}
	sfxScratchPointer = NULL;

	inUse = scs * sizeof(sndBuffer);
	p     = buffer;
	q     = p + scs;
	while (--q > p)
	{
		*(sndBuffer **)q = q - 1;
	}

	*(sndBuffer **)q = NULL;
	freelist         = p + scs - 1;

	Com_Printf("Sound memory manager started\n");
}
示例#6
0
void CL_AllocateDemoPoints(void)
{
	CL_FreeDemoPoints();

	maxRewindBackups = cl_maxRewindBackups->integer;
	if (maxRewindBackups <= 0)
	{
		maxRewindBackups = MAX_REWIND_BACKUPS;
	}

	rewindBackups = (rewindBackups_t *)Com_Allocate(sizeof(rewindBackups_t) * maxRewindBackups);
	if (!rewindBackups)
	{
		Com_FuncError("couldn't allocate %.2f MB for rewind backups\n", MEGABYTES(sizeof(rewindBackups_t) * maxRewindBackups));
		return;
	}
	Com_FuncPrinf("allocated %.2f MB for rewind backups\n", MEGABYTES(sizeof(rewindBackups_t) * maxRewindBackups));
	Com_Memset(rewindBackups, 0, sizeof(rewindBackups_t) * maxRewindBackups);
}
示例#7
0
int Com_AddToGrowList(growList_t *list, void *data)
{
	void **old;

	if (list->currentElements != list->maxElements)
	{
		list->elements[list->currentElements] = data;
		return list->currentElements++;
	}

	// grow, reallocate and move
	old = list->elements;

	if (list->maxElements < 0)
	{
		Ren_Fatal("Com_AddToGrowList: maxElements = %i", list->maxElements);
	}

	if (list->maxElements == 0)
	{
		// initialize the list to hold 100 elements
		Com_InitGrowList(list, 100);
		return Com_AddToGrowList(list, data);
	}

	list->maxElements *= 2;

	//Com_DPrintf("Resizing growlist to %i maxElements\n", list->maxElements);

	list->elements = (void **)Com_Allocate(list->maxElements * sizeof(void *));

	if (!list->elements)
	{
		Ren_Drop("Growlist alloc failed");
	}

	Com_Memcpy(list->elements, old, list->currentElements * sizeof(void *));

	Com_Dealloc(old);

	return Com_AddToGrowList(list, data);
}
示例#8
0
memStream_t *AllocMemStream(byte *buffer, int bufSize)
{
	memStream_t *s;

	if (buffer == NULL || bufSize <= 0)
	{
		return NULL;
	}

	s = Com_Allocate(sizeof(memStream_t));
	if (s == NULL)
	{
		return NULL;
	}

	Com_Memset(s, 0, sizeof(memStream_t));

	s->buffer  = buffer;
	s->curPos  = buffer;
	s->bufSize = bufSize;
	s->flags   = 0;

	return s;
}
示例#9
0
static int OGV_LoadVideoFrame(cinematic_t *cin)
{
	int        r = 0;
	ogg_packet op;

	memset(&op, 0, sizeof(op));

	while (!r && (ogg_stream_packetout(&g_ogm->os_video, &op)))
	{
		ogg_int64_t th_frame;

		theora_decode_packetin(&g_ogm->th_state, &op);

		th_frame = theora_granule_frame(&g_ogm->th_state, g_ogm->th_state.granulepos);

		if ((g_ogm->VFrameCount < th_frame && th_frame >= OGV_NextNeededVFrame(cin)) || !cin->frameBuffer[0])
		{
			if (theora_decode_YUVout(&g_ogm->th_state, &g_ogm->th_yuvbuffer))
			{
				continue;
			}

			if (cin->frameWidth != g_ogm->th_info.width || cin->frameHeight != g_ogm->th_info.height)
			{
				cin->frameWidth  = g_ogm->th_info.width;
				cin->frameHeight = g_ogm->th_info.height;
				Com_DPrintf("Theora new resolution %dx%d\n", cin->frameWidth, cin->frameHeight);
			}

			if (cin->frameBufferSize < g_ogm->th_info.width * g_ogm->th_info.height)
			{

				cin->frameBufferSize = g_ogm->th_info.width * g_ogm->th_info.height;

				/* Free old output buffer */
				if (cin->frameBuffer[0])
				{
					Com_Dealloc(cin->frameBuffer[0]);
					cin->frameBuffer[0] = NULL;
				}

				/* Allocate the new buffer */
				cin->frameBuffer[0] = (unsigned char *)Com_Allocate(cin->frameBufferSize * 4);
				if (cin->frameBuffer[0] == NULL)
				{
					cin->frameBufferSize = 0;
					r                    = -2;
					break;
				}
			}

			if (OGV_yuv_to_rgb24(&g_ogm->th_yuvbuffer, &g_ogm->th_info, (unsigned int *) cin->frameBuffer[0]))
			{
				r                  = 1;
				g_ogm->VFrameCount = th_frame;
			}
			else
			{
				r = -1;
			}
		}
	}

	return r;
}
示例#10
0
qboolean R_LoadPSK(model_t *mod, void *buffer, int bufferSize, const char *modName)
{
	int         i, j, k;
	memStream_t *stream = NULL;

	axChunkHeader_t chunkHeader;

	int       numPoints;
	axPoint_t *point;
	axPoint_t *points = NULL;

	int        numVertexes;
	axVertex_t *vertex;
	axVertex_t *vertexes = NULL;

	//int       numSmoothGroups;
	int          numTriangles;
	axTriangle_t *triangle;
	axTriangle_t *triangles = NULL;

	int          numMaterials;
	axMaterial_t *material;
	axMaterial_t *materials = NULL;

	int               numReferenceBones;
	axReferenceBone_t *refBone;
	axReferenceBone_t *refBones = NULL;

	int            numWeights;
	axBoneWeight_t *axWeight;
	axBoneWeight_t *axWeights = NULL;

	md5Model_t  *md5;
	md5Bone_t   *md5Bone;
	md5Weight_t *weight;

	vec3_t boneOrigin;
	quat_t boneQuat;
	//mat4_t        boneMat;

	int materialIndex, oldMaterialIndex;

	int numRemaining;

	growList_t sortedTriangles;
	growList_t vboVertexes;
	growList_t vboTriangles;
	growList_t vboSurfaces;

	int numBoneReferences;
	int boneReferences[MAX_BONES];

	mat4_t unrealToQuake;

#define DeallocAll() Com_Dealloc(materials); \
	Com_Dealloc(points); \
	Com_Dealloc(vertexes); \
	Com_Dealloc(triangles); \
	Com_Dealloc(refBones); \
	Com_Dealloc(axWeights); \
	FreeMemStream(stream);

	//MatrixSetupScale(unrealToQuake, 1, -1, 1);
	mat4_from_angles(unrealToQuake, 0, 90, 0);

	stream = AllocMemStream(buffer, bufferSize);
	GetChunkHeader(stream, &chunkHeader);

	// check indent again
	if (Q_stricmpn(chunkHeader.ident, "ACTRHEAD", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "ACTRHEAD");
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	mod->type      = MOD_MD5;
	mod->dataSize += sizeof(md5Model_t);
	md5            = mod->md5 = ri.Hunk_Alloc(sizeof(md5Model_t), h_low);

	// read points
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "PNTS0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "PNTS0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axPoint_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axPoint_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numPoints = chunkHeader.numData;
	points    = Com_Allocate(numPoints * sizeof(axPoint_t));

	for (i = 0, point = points; i < numPoints; i++, point++)
	{
		point->point[0] = MemStreamGetFloat(stream);
		point->point[1] = MemStreamGetFloat(stream);
		point->point[2] = MemStreamGetFloat(stream);

#if 0
		// HACK convert from Unreal coordinate system to the Quake one
		MatrixTransformPoint2(unrealToQuake, point->point);
#endif
	}

	// read vertices
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "VTXW0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "VTXW0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axVertex_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axVertex_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numVertexes = chunkHeader.numData;
	vertexes    = Com_Allocate(numVertexes * sizeof(axVertex_t));

	{
		int tmpVertexInt = -1; // tmp vertex member values - MemStreamGet functions return -1 if they fail
		                       // now we print a warning if they do or abort if pointIndex is invalid

		for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
		{
			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0 || tmpVertexInt >= numPoints)
			{
				ri.Printf(PRINT_ERROR, "R_LoadPSK: '%s' has vertex with point index out of range (%i while max %i)\n", modName, tmpVertexInt, numPoints);
				DeallocAll();
				return qfalse;
			}
			vertex->pointIndex = tmpVertexInt;

			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->unknownA)\n");
			}
			vertex->unknownA = tmpVertexInt;

			vertex->st[0] = MemStreamGetFloat(stream);
			if (vertex->st[0] == -1)
			{
				Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[0])\n");
			}

			vertex->st[1] = MemStreamGetFloat(stream);
			if (vertex->st[1] == -1)
			{
				Ren_Warning("R_LoadPSK: MemStream possibly NULL or empty (vertex->st[1])\n");
			}

			tmpVertexInt = MemStreamGetC(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->materialIndex = tmpVertexInt;

			tmpVertexInt = MemStreamGetC(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->reserved = tmpVertexInt;

			tmpVertexInt = MemStreamGetShort(stream);
			if (tmpVertexInt < 0)
			{
				Ren_Warning("R_LoadPSK: MemStream NULL or empty (vertex->materialIndex)\n");
			}
			vertex->unknownB = tmpVertexInt;
#if 0
			Ren_Print("R_LoadPSK: axVertex_t(%i):\n"
			          "axVertex:pointIndex: %i\n"
			          "axVertex:unknownA: %i\n"
			          "axVertex::st: %f %f\n"
			          "axVertex:materialIndex: %i\n"
			          "axVertex:reserved: %d\n"
			          "axVertex:unknownB: %d\n",
			          i,
			          vertex->pointIndex,
			          vertex->unknownA,
			          vertex->st[0], vertex->st[1],
			          vertex->materialIndex,
			          vertex->reserved,
			          vertex->unknownB);
#endif
		}


		// read triangles
		GetChunkHeader(stream, &chunkHeader);

		if (Q_stricmpn(chunkHeader.ident, "FACE0000", 8))
		{
			Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "FACE0000");
			DeallocAll();
			return qfalse;
		}

		if (chunkHeader.dataSize != sizeof(axTriangle_t))
		{
			Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axTriangle_t));
			DeallocAll();
			return qfalse;
		}

		PrintChunkHeader(&chunkHeader);

		numTriangles = chunkHeader.numData;
		triangles    = Com_Allocate(numTriangles * sizeof(axTriangle_t));

		for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
		{
			for (j = 0; j < 3; j++)
			//for(j = 2; j >= 0; j--)
			{
				tmpVertexInt = MemStreamGetShort(stream);

				if (tmpVertexInt < 0)
				{
					Ren_Warning("R_LoadPSK: '%s' MemStream NULL or empty (triangle->indexes[%i])\n", modName, j);
					DeallocAll();
					return qfalse;
				}

				if (tmpVertexInt >= numVertexes)
				{
					Ren_Warning("R_LoadPSK: '%s' has triangle with vertex index out of range (%i while max %i)\n", modName, tmpVertexInt, numVertexes);
					DeallocAll();
					return qfalse;
				}

				triangle->indexes[j] = tmpVertexInt;
			}

			triangle->materialIndex   = MemStreamGetC(stream);
			triangle->materialIndex2  = MemStreamGetC(stream);
			triangle->smoothingGroups = MemStreamGetLong(stream);
		}
	}
	// read materials
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "MATT0000", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "MATT0000");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axMaterial_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axMaterial_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numMaterials = chunkHeader.numData;
	materials    = Com_Allocate(numMaterials * sizeof(axMaterial_t));

	for (i = 0, material = materials; i < numMaterials; i++, material++)
	{
		MemStreamRead(stream, material->name, sizeof(material->name));

		Ren_Print("R_LoadPSK: material name: '%s'\n", material->name);

		material->shaderIndex = MemStreamGetLong(stream);
		material->polyFlags   = MemStreamGetLong(stream);
		material->auxMaterial = MemStreamGetLong(stream);
		material->auxFlags    = MemStreamGetLong(stream);
		material->lodBias     = MemStreamGetLong(stream);
		material->lodStyle    = MemStreamGetLong(stream);
	}

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		if (vertex->materialIndex < 0 || vertex->materialIndex >= numMaterials)
		{
			Ren_Warning("R_LoadPSK: '%s' has vertex with material index out of range (%i while max %i)\n", modName, vertex->materialIndex, numMaterials);
			DeallocAll();
			return qfalse;
		}
	}

	for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
		if (triangle->materialIndex < 0 || triangle->materialIndex >= numMaterials)
		{
			Ren_Warning("R_LoadPSK: '%s' has triangle with material index out of range (%i while max %i)\n", modName, triangle->materialIndex, numMaterials);
			DeallocAll();
			return qfalse;
		}
	}

	// read reference bones
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "REFSKELT", 8))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "REFSKELT");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axReferenceBone_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axReferenceBone_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numReferenceBones = chunkHeader.numData;
	refBones          = Com_Allocate(numReferenceBones * sizeof(axReferenceBone_t));

	for (i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++)
	{
		MemStreamRead(stream, refBone->name, sizeof(refBone->name));

		//Ren_Print("R_LoadPSK: reference bone name: '%s'\n", refBone->name);

		refBone->flags       = MemStreamGetLong(stream);
		refBone->numChildren = MemStreamGetLong(stream);
		refBone->parentIndex = MemStreamGetLong(stream);

		GetBone(stream, &refBone->bone);

#if 0
		Ren_Print("R_LoadPSK: axReferenceBone_t(%i):\n"
		          "axReferenceBone_t::name: '%s'\n"
		          "axReferenceBone_t::flags: %i\n"
		          "axReferenceBone_t::numChildren %i\n"
		          "axReferenceBone_t::parentIndex: %i\n"
		          "axReferenceBone_t::quat: %f %f %f %f\n"
		          "axReferenceBone_t::position: %f %f %f\n"
		          "axReferenceBone_t::length: %f\n"
		          "axReferenceBone_t::xSize: %f\n"
		          "axReferenceBone_t::ySize: %f\n"
		          "axReferenceBone_t::zSize: %f\n",
		          i,
		          refBone->name,
		          refBone->flags,
		          refBone->numChildren,
		          refBone->parentIndex,
		          refBone->bone.quat[0], refBone->bone.quat[1], refBone->bone.quat[2], refBone->bone.quat[3],
		          refBone->bone.position[0], refBone->bone.position[1], refBone->bone.position[2],
		          refBone->bone.length,
		          refBone->bone.xSize,
		          refBone->bone.ySize,
		          refBone->bone.zSize);
#endif
	}

	// read  bone weights
	GetChunkHeader(stream, &chunkHeader);

	if (Q_stricmpn(chunkHeader.ident, "RAWWEIGHTS", 10))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "RAWWEIGHTS");
		DeallocAll();
		return qfalse;
	}

	if (chunkHeader.dataSize != sizeof(axBoneWeight_t))
	{
		Ren_Warning("R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof(axBoneWeight_t));
		DeallocAll();
		return qfalse;
	}

	PrintChunkHeader(&chunkHeader);

	numWeights = chunkHeader.numData;
	axWeights  = Com_Allocate(numWeights * sizeof(axBoneWeight_t));

	for (i = 0, axWeight = axWeights; i < numWeights; i++, axWeight++)
	{
		axWeight->weight     = MemStreamGetFloat(stream);
		axWeight->pointIndex = MemStreamGetLong(stream);
		axWeight->boneIndex  = MemStreamGetLong(stream);

#if 0
		Ren_Print("R_LoadPSK: axBoneWeight_t(%i):\n"
		          "axBoneWeight_t::weight: %f\n"
		          "axBoneWeight_t::pointIndex %i\n"
		          "axBoneWeight_t::boneIndex: %i\n",
		          i,
		          axWeight->weight,
		          axWeight->pointIndex,
		          axWeight->boneIndex);
#endif
	}

	//
	// convert the model to an internal MD5 representation
	//
	md5->numBones = numReferenceBones;

	// calc numMeshes <number>

	/*
	numSmoothGroups = 0;
	for(i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
	        if(triangle->smoothingGroups)
	        {

	        }
	}
	*/

	if (md5->numBones < 1)
	{
		Ren_Warning("R_LoadPSK: '%s' has no bones\n", modName);
		DeallocAll();
		return qfalse;
	}

	if (md5->numBones > MAX_BONES)
	{
		Ren_Warning("R_LoadPSK: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones);
		DeallocAll();
		return qfalse;
	}

	//Ren_Print("R_LoadPSK: '%s' has %i bones\n", modName, md5->numBones);

	// copy all reference bones
	md5->bones = ri.Hunk_Alloc(sizeof(*md5Bone) * md5->numBones, h_low);

	for (i = 0, md5Bone = md5->bones, refBone = refBones; i < md5->numBones; i++, md5Bone++, refBone++)
	{
		Q_strncpyz(md5Bone->name, refBone->name, sizeof(md5Bone->name));

		if (i == 0)
		{
			md5Bone->parentIndex = refBone->parentIndex - 1;
		}
		else
		{
			md5Bone->parentIndex = refBone->parentIndex;
		}

		//Ren_Print("R_LoadPSK: '%s' has bone '%s' with parent index %i\n", modName, md5Bone->name, md5Bone->parentIndex);

		if (md5Bone->parentIndex >= md5->numBones)
		{
			DeallocAll();
			Ren_Drop("R_LoadPSK: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName,
			         md5Bone->name, md5Bone->parentIndex, md5->numBones);
		}

		for (j = 0; j < 3; j++)
		{
			boneOrigin[j] = refBone->bone.position[j];
		}

		// I have really no idea why the .psk format stores the first quaternion with inverted quats.
		// Furthermore only the X and Z components of the first quat are inverted ?!?!
		if (i == 0)
		{
			boneQuat[0] = refBone->bone.quat[0];
			boneQuat[1] = -refBone->bone.quat[1];
			boneQuat[2] = refBone->bone.quat[2];
			boneQuat[3] = refBone->bone.quat[3];
		}
		else
		{
			boneQuat[0] = -refBone->bone.quat[0];
			boneQuat[1] = -refBone->bone.quat[1];
			boneQuat[2] = -refBone->bone.quat[2];
			boneQuat[3] = refBone->bone.quat[3];
		}

		VectorCopy(boneOrigin, md5Bone->origin);
		//MatrixTransformPoint(unrealToQuake, boneOrigin, md5Bone->origin);

		quat_copy(boneQuat, md5Bone->rotation);

		//QuatClear(md5Bone->rotation);

#if 0
		Ren_Print("R_LoadPSK: md5Bone_t(%i):\n"
		          "md5Bone_t::name: '%s'\n"
		          "md5Bone_t::parentIndex: %i\n"
		          "md5Bone_t::quat: %f %f %f %f\n"
		          "md5bone_t::position: %f %f %f\n",
		          i,
		          md5Bone->name,
		          md5Bone->parentIndex,
		          md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3],
		          md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]);
#endif

		if (md5Bone->parentIndex >= 0)
		{
			vec3_t rotated;
			quat_t quat;

			md5Bone_t *parent;

			parent = &md5->bones[md5Bone->parentIndex];

			QuatTransformVector(parent->rotation, md5Bone->origin, rotated);
			//QuatTransformVector(md5Bone->rotation, md5Bone->origin, rotated);

			VectorAdd(parent->origin, rotated, md5Bone->origin);

			QuatMultiply1(parent->rotation, md5Bone->rotation, quat);
			quat_copy(quat, md5Bone->rotation);
		}

		MatrixSetupTransformFromQuat(md5Bone->inverseTransform, md5Bone->rotation, md5Bone->origin);
		mat4_inverse_self(md5Bone->inverseTransform);

#if 0
		Ren_Print("R_LoadPSK: md5Bone_t(%i):\n"
		          "md5Bone_t::name: '%s'\n"
		          "md5Bone_t::parentIndex: %i\n"
		          "md5Bone_t::quat: %f %f %f %f\n"
		          "md5bone_t::position: %f %f %f\n",
		          i,
		          md5Bone->name,
		          md5Bone->parentIndex,
		          md5Bone->rotation[0], md5Bone->rotation[1], md5Bone->rotation[2], md5Bone->rotation[3],
		          md5Bone->origin[0], md5Bone->origin[1], md5Bone->origin[2]);
#endif
	}

	Com_InitGrowList(&vboVertexes, 10000);

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		md5Vertex_t *vboVert = Com_Allocate(sizeof(*vboVert));

		for (j = 0; j < 3; j++)
		{
			vboVert->position[j] = points[vertex->pointIndex].point[j];
		}

		vboVert->texCoords[0] = vertex->st[0];
		vboVert->texCoords[1] = vertex->st[1];

		// find number of associated weights
		vboVert->numWeights = 0;

		for (j = 0, axWeight = axWeights; j < numWeights; j++, axWeight++)
		{
			if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f)
			{
				vboVert->numWeights++;
			}
		}

		if (vboVert->numWeights > MAX_WEIGHTS)
		{
			DeallocAll();
			Ren_Drop("R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'", i, vboVert->numWeights, MAX_WEIGHTS, modName);
			//Ren_Warning( "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'\n", i, vboVert->numWeights, MAX_WEIGHTS, modName);
		}

		vboVert->weights = ri.Hunk_Alloc(sizeof(*vboVert->weights) * vboVert->numWeights, h_low);

		for (j = 0, axWeight = axWeights, k = 0; j < numWeights; j++, axWeight++)
		{
			if (axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f)
			{
				weight = ri.Hunk_Alloc(sizeof(*weight), h_low);

				weight->boneIndex  = axWeight->boneIndex;
				weight->boneWeight = axWeight->weight;

				// FIXME?
				weight->offset[0] = refBones[axWeight->boneIndex].bone.xSize;
				weight->offset[1] = refBones[axWeight->boneIndex].bone.ySize;
				weight->offset[2] = refBones[axWeight->boneIndex].bone.zSize;

				vboVert->weights[k++] = weight;
			}
		}

		Com_AddToGrowList(&vboVertexes, vboVert);
	}

	ClearBounds(md5->bounds[0], md5->bounds[1]);

	for (i = 0, vertex = vertexes; i < numVertexes; i++, vertex++)
	{
		AddPointToBounds(points[vertex->pointIndex].point, md5->bounds[0], md5->bounds[1]);
	}

#if 0
	Ren_Print("R_LoadPSK: AABB (%i %i %i) (%i %i %i)\n",
	          ( int ) md5->bounds[0][0],
	          ( int ) md5->bounds[0][1],
	          ( int ) md5->bounds[0][2],
	          ( int ) md5->bounds[1][0],
	          ( int ) md5->bounds[1][1],
	          ( int ) md5->bounds[1][2]);
#endif

	// sort triangles
	qsort(triangles, numTriangles, sizeof(axTriangle_t), CompareTrianglesByMaterialIndex);

	Com_InitGrowList(&sortedTriangles, 1000);

	for (i = 0, triangle = triangles; i < numTriangles; i++, triangle++)
	{
		skelTriangle_t *sortTri = Com_Allocate(sizeof(*sortTri));

		for (j = 0; j < 3; j++)
		{
			sortTri->indexes[j]  = triangle->indexes[j];
			sortTri->vertexes[j] = Com_GrowListElement(&vboVertexes, triangle->indexes[j]);
		}

		sortTri->referenced = qfalse;

		Com_AddToGrowList(&sortedTriangles, sortTri);
	}

	// calc tangent spaces
#if 1
	{
		md5Vertex_t *v0, *v1, *v2;
		const float *p0, *p1, *p2;
		const float *t0, *t1, *t2;
		vec3_t      tangent = { 0, 0, 0 };
		vec3_t      binormal;
		vec3_t      normal;

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			VectorClear(v0->tangent);
			VectorClear(v0->binormal);
			VectorClear(v0->normal);
		}

		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j);

			v0 = Com_GrowListElement(&vboVertexes, tri->indexes[0]);
			v1 = Com_GrowListElement(&vboVertexes, tri->indexes[1]);
			v2 = Com_GrowListElement(&vboVertexes, tri->indexes[2]);

			p0 = v0->position;
			p1 = v1->position;
			p2 = v2->position;

			t0 = v0->texCoords;
			t1 = v1->texCoords;
			t2 = v2->texCoords;

#if 1
			R_CalcTangentSpace(tangent, binormal, normal, p0, p1, p2, t0, t1, t2);
#else
			R_CalcNormalForTriangle(normal, p0, p1, p2);
			R_CalcTangentsForTriangle(tangent, binormal, p0, p1, p2, t0, t1, t2);
#endif

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

				v0 = Com_GrowListElement(&vboVertexes, tri->indexes[k]);

				v = v0->tangent;
				VectorAdd(v, tangent, v);

				v = v0->binormal;
				VectorAdd(v, binormal, v);

				v = v0->normal;
				VectorAdd(v, normal, v);
			}
		}

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			VectorNormalize(v0->tangent);
			VectorNormalize(v0->binormal);
			VectorNormalize(v0->normal);
		}
	}
#else
	{
		float       bb, s, t;
		vec3_t      bary;
		vec3_t      faceNormal;
		md5Vertex_t *dv[3];

		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			skelTriangle_t *tri = Com_GrowListElement(&sortedTriangles, j);

			dv[0] = Com_GrowListElement(&vboVertexes, tri->indexes[0]);
			dv[1] = Com_GrowListElement(&vboVertexes, tri->indexes[1]);
			dv[2] = Com_GrowListElement(&vboVertexes, tri->indexes[2]);

			R_CalcNormalForTriangle(faceNormal, dv[0]->position, dv[1]->position, dv[2]->position);

			// calculate barycentric basis for the triangle
			bb = (dv[1]->texCoords[0] - dv[0]->texCoords[0]) * (dv[2]->texCoords[1] - dv[0]->texCoords[1]) - (dv[2]->texCoords[0] - dv[0]->texCoords[0]) * (dv[1]->texCoords[1] -
			                                                                                                                                                dv[0]->texCoords[1]);

			if (fabs(bb) < 0.00000001f)
			{
				continue;
			}

			// do each vertex
			for (k = 0; k < 3; k++)
			{
				// calculate s tangent vector
				s       = dv[k]->texCoords[0] + 10.0f;
				t       = dv[k]->texCoords[1];
				bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
				bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
				bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

				dv[k]->tangent[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
				dv[k]->tangent[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
				dv[k]->tangent[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

				VectorSubtract(dv[k]->tangent, dv[k]->position, dv[k]->tangent);
				VectorNormalize(dv[k]->tangent);

				// calculate t tangent vector (binormal)
				s       = dv[k]->texCoords[0];
				t       = dv[k]->texCoords[1] + 10.0f;
				bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
				bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
				bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

				dv[k]->binormal[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
				dv[k]->binormal[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
				dv[k]->binormal[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

				VectorSubtract(dv[k]->binormal, dv[k]->position, dv[k]->binormal);
				VectorNormalize(dv[k]->binormal);

				// calculate the normal as cross product N=TxB
#if 0
				CrossProduct(dv[k]->tangent, dv[k]->binormal, dv[k]->normal);
				VectorNormalize(dv[k]->normal);

				// Gram-Schmidt orthogonalization process for B
				// compute the cross product B=NxT to obtain
				// an orthogonal basis
				CrossProduct(dv[k]->normal, dv[k]->tangent, dv[k]->binormal);

				if (DotProduct(dv[k]->normal, faceNormal) < 0)
				{
					VectorInverse(dv[k]->normal);
					//VectorInverse(dv[k]->tangent);
					//VectorInverse(dv[k]->binormal);
				}

#else
				VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal);
#endif
			}
		}

#if 1

		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			dv[0] = Com_GrowListElement(&vboVertexes, j);
			//VectorNormalize(dv[0]->tangent);
			//VectorNormalize(dv[0]->binormal);
			VectorNormalize(dv[0]->normal);
		}

#endif
	}
#endif

#if 0
	{
		md5Vertex_t *v0, *v1;

		// do another extra smoothing for normals to avoid flat shading
		for (j = 0; j < vboVertexes.currentElements; j++)
		{
			v0 = Com_GrowListElement(&vboVertexes, j);

			for (k = 0; k < vboVertexes.currentElements; k++)
			{
				if (j == k)
				{
					continue;
				}

				v1 = Com_GrowListElement(&vboVertexes, k);

				if (VectorCompare(v0->position, v1->position))
				{
					VectorAdd(v0->position, v1->normal, v0->normal);
				}
			}

			VectorNormalize(v0->normal);
		}
	}
#endif

	// split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones
	Com_InitGrowList(&vboSurfaces, 10);

	materialIndex = oldMaterialIndex = -1;

	for (i = 0; i < numTriangles; i++)
	{
		triangle      = &triangles[i];
		materialIndex = triangle->materialIndex;

		if (materialIndex != oldMaterialIndex)
		{
			oldMaterialIndex = materialIndex;

			numRemaining = sortedTriangles.currentElements - i;

			while (numRemaining)
			{
				numBoneReferences = 0;
				Com_Memset(boneReferences, 0, sizeof(boneReferences));

				Com_InitGrowList(&vboTriangles, 1000);

				for (j = i; j < sortedTriangles.currentElements; j++)
				{
					skelTriangle_t *sortTri;

					triangle      = &triangles[j];
					materialIndex = triangle->materialIndex;

					if (materialIndex != oldMaterialIndex)
					{
						continue;
					}

					sortTri = Com_GrowListElement(&sortedTriangles, j);

					if (sortTri->referenced)
					{
						continue;
					}

					if (AddTriangleToVBOTriangleList(&vboTriangles, sortTri, &numBoneReferences, boneReferences))
					{
						sortTri->referenced = qtrue;
					}
				}

				for (j = 0; j < MAX_BONES; j++)
				{
					if (boneReferences[j] > 0)
					{
						Ren_Print("R_LoadPSK: referenced bone: '%s'\n", (j < numReferenceBones) ? refBones[j].name : NULL);
					}
				}

				if (!vboTriangles.currentElements)
				{
					Ren_Warning("R_LoadPSK: could not add triangles to a remaining VBO surface for model '%s'\n", modName);
					break;
				}

				// FIXME skinIndex
				AddSurfaceToVBOSurfacesList2(&vboSurfaces, &vboTriangles, &vboVertexes, md5, vboSurfaces.currentElements, materials[oldMaterialIndex].name, numBoneReferences, boneReferences);
				numRemaining -= vboTriangles.currentElements;

				Com_DestroyGrowList(&vboTriangles);
			}
		}
	}

	for (j = 0; j < sortedTriangles.currentElements; j++)
	{
		skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j);
		Com_Dealloc(sortTri);
	}

	Com_DestroyGrowList(&sortedTriangles);

	for (j = 0; j < vboVertexes.currentElements; j++)
	{
		md5Vertex_t *v = Com_GrowListElement(&vboVertexes, j);
		Com_Dealloc(v);
	}

	Com_DestroyGrowList(&vboVertexes);

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

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

	Com_DestroyGrowList(&vboSurfaces);

	FreeMemStream(stream);
	Com_Dealloc(points);
	Com_Dealloc(vertexes);
	Com_Dealloc(triangles);
	Com_Dealloc(materials);

	Ren_Developer("%i VBO surfaces created for PSK model '%s'\n", md5->numVBOSurfaces, modName);

	return qtrue;
}
示例#11
0
/*
=================
R_LoadMDM
=================
*/
qboolean R_LoadMDM( model_t *mod, void *buffer, const char *modName )
{
	int                i, j, k;

	mdmHeader_t        *mdm;
//    mdmFrame_t            *frame;
	mdmSurface_t       *mdmSurf;
	mdmTriangle_t      *mdmTri;
	mdmVertex_t        *mdmVertex;
	mdmTag_t           *mdmTag;
	int                version;
//	int             size;
	shader_t           *sh;
	int32_t            *collapseMap, *collapseMapOut, *boneref, *bonerefOut;

	mdmModel_t         *mdmModel;
	mdmTagIntern_t     *tag;
	mdmSurfaceIntern_t *surf;
	srfTriangle_t      *tri;
	md5Vertex_t        *v;

	mdm = ( mdmHeader_t * ) buffer;

	version = LittleLong( mdm->version );

	if ( version != MDM_VERSION )
	{
		ri.Printf( PRINT_WARNING, "R_LoadMDM: %s has wrong version (%i should be %i)\n", modName, version, MDM_VERSION );
		return qfalse;
	}

	mod->type = MOD_MDM;
//	size = LittleLong(mdm->ofsEnd);
	mod->dataSize += sizeof( mdmModel_t );

	//mdm = mod->mdm = ri.Hunk_Alloc(size, h_low);
	//memcpy(mdm, buffer, LittleLong(pinmodel->ofsEnd));

	mdmModel = mod->mdm = ri.Hunk_Alloc( sizeof( mdmModel_t ), h_low );

	LL( mdm->ident );
	LL( mdm->version );
//    LL(mdm->numFrames);
	LL( mdm->numTags );
	LL( mdm->numSurfaces );
//    LL(mdm->ofsFrames);
	LL( mdm->ofsTags );
	LL( mdm->ofsEnd );
	LL( mdm->ofsSurfaces );

	mdmModel->lodBias = LittleFloat( mdm->lodBias );
	mdmModel->lodScale = LittleFloat( mdm->lodScale );

	/*  mdm->skel = RE_RegisterModel(mdm->bonesfile);
	        if ( !mdm->skel ) {
	                ri.Error (ERR_DROP, "R_LoadMDM: %s skeleton not found", mdm->bonesfile );
	        }

	        if ( mdm->numFrames < 1 ) {
	                ri.Printf( PRINT_WARNING, "R_LoadMDM: %s has no frames\n", modName );
	                return qfalse;
	        }*/

	// swap all the frames

	/*frameSize = (int) ( sizeof( mdmFrame_t ) );
	   for ( i = 0 ; i < mdm->numFrames ; i++, frame++) {
	   frame = (mdmFrame_t *) ( (byte *)mdm + mdm->ofsFrames + i * frameSize );
	   frame->radius = LittleFloat( frame->radius );
	   for ( j = 0 ; j < 3 ; j++ ) {
	   frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
	   frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
	   frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
	   frame->parentOffset[j] = LittleFloat( frame->parentOffset[j] );
	   }
	   } */

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

	mdmTag = ( mdmTag_t * )( ( byte * ) mdm + mdm->ofsTags );

	for ( i = 0; i < mdm->numTags; i++, tag++ )
	{
		int ii;

		Q_strncpyz( tag->name, mdmTag->name, sizeof( tag->name ) );

		for ( ii = 0; ii < 3; ii++ )
		{
			tag->axis[ ii ][ 0 ] = LittleFloat( mdmTag->axis[ ii ][ 0 ] );
			tag->axis[ ii ][ 1 ] = LittleFloat( mdmTag->axis[ ii ][ 1 ] );
			tag->axis[ ii ][ 2 ] = LittleFloat( mdmTag->axis[ ii ][ 2 ] );
		}

		tag->boneIndex = LittleLong( mdmTag->boneIndex );
		//tag->torsoWeight = LittleFloat( tag->torsoWeight );
		tag->offset[ 0 ] = LittleFloat( mdmTag->offset[ 0 ] );
		tag->offset[ 1 ] = LittleFloat( mdmTag->offset[ 1 ] );
		tag->offset[ 2 ] = LittleFloat( mdmTag->offset[ 2 ] );

		LL( mdmTag->numBoneReferences );
		LL( mdmTag->ofsBoneReferences );
		LL( mdmTag->ofsEnd );

		tag->numBoneReferences = mdmTag->numBoneReferences;
		tag->boneReferences = ri.Hunk_Alloc( sizeof( *bonerefOut ) * mdmTag->numBoneReferences, h_low );

		// swap the bone references
		boneref = ( int32_t * )( ( byte * ) mdmTag + mdmTag->ofsBoneReferences );

		for ( j = 0, bonerefOut = tag->boneReferences; j < mdmTag->numBoneReferences; j++, boneref++, bonerefOut++ )
		{
			*bonerefOut = LittleLong( *boneref );
		}

		// find the next tag
		mdmTag = ( mdmTag_t * )( ( byte * ) mdmTag + mdmTag->ofsEnd );
	}

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

	mdmSurf = ( mdmSurface_t * )( ( byte * ) mdm + mdm->ofsSurfaces );

	for ( i = 0, surf = mdmModel->surfaces; i < mdm->numSurfaces; i++, surf++ )
	{
		LL( mdmSurf->shaderIndex );
		LL( mdmSurf->ofsHeader );
		LL( mdmSurf->ofsCollapseMap );
		LL( mdmSurf->numTriangles );
		LL( mdmSurf->ofsTriangles );
		LL( mdmSurf->numVerts );
		LL( mdmSurf->ofsVerts );
		LL( mdmSurf->numBoneReferences );
		LL( mdmSurf->ofsBoneReferences );
		LL( mdmSurf->ofsEnd );

		surf->minLod = LittleLong( mdmSurf->minLod );

		// change to surface identifier
		surf->surfaceType = SF_MDM;
		surf->model = mdmModel;

		Q_strncpyz( surf->name, mdmSurf->name, sizeof( surf->name ) );

		if ( mdmSurf->numVerts > SHADER_MAX_VERTEXES )
		{
			ri.Error( ERR_DROP, "R_LoadMDM: %s has more than %i verts on a surface (%i)",
			          modName, SHADER_MAX_VERTEXES, mdmSurf->numVerts );
		}

		if ( mdmSurf->numTriangles > SHADER_MAX_TRIANGLES )
		{
			ri.Error( ERR_DROP, "R_LoadMDM: %s has more than %i triangles on a surface (%i)",
			          modName, SHADER_MAX_TRIANGLES, mdmSurf->numTriangles );
		}

		// register the shaders
		if ( mdmSurf->shader[ 0 ] )
		{
			Q_strncpyz( surf->shader, mdmSurf->shader, sizeof( surf->shader ) );

			sh = R_FindShader( surf->shader, SHADER_3D_DYNAMIC, qtrue );

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

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

		mdmTri = ( mdmTriangle_t * )( ( byte * ) mdmSurf + mdmSurf->ofsTriangles );

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

		// swap all the vertexes
		surf->numVerts = mdmSurf->numVerts;
		surf->verts = ri.Hunk_Alloc( sizeof( *v ) * surf->numVerts, h_low );

		mdmVertex = ( mdmVertex_t * )( ( byte * ) mdmSurf + mdmSurf->ofsVerts );

		for ( j = 0, v = surf->verts; j < mdmSurf->numVerts; j++, v++ )
		{
			v->normal[ 0 ] = LittleFloat( mdmVertex->normal[ 0 ] );
			v->normal[ 1 ] = LittleFloat( mdmVertex->normal[ 1 ] );
			v->normal[ 2 ] = LittleFloat( mdmVertex->normal[ 2 ] );

			v->texCoords[ 0 ] = LittleFloat( mdmVertex->texCoords[ 0 ] );
			v->texCoords[ 1 ] = LittleFloat( mdmVertex->texCoords[ 1 ] );

			v->numWeights = LittleLong( mdmVertex->numWeights );

			if ( v->numWeights > MAX_WEIGHTS )
			{
#if 0
				ri.Error( ERR_DROP, "R_LoadMDM: vertex %i requires %i instead of maximum %i weights on surface (%i) in model '%s'",
				          j, v->numWeights, MAX_WEIGHTS, i, modName );
#else
				ri.Printf( PRINT_WARNING, "WARNING: R_LoadMDM: vertex %i requires %i instead of maximum %i weights on surface (%i) in model '%s'\n",
				           j, v->numWeights, MAX_WEIGHTS, i, modName );
#endif
			}

			v->weights = ri.Hunk_Alloc( sizeof( *v->weights ) * v->numWeights, h_low );

			for ( k = 0; k < v->numWeights; k++ )
			{
				md5Weight_t *weight = ri.Hunk_Alloc( sizeof( *weight ), h_low );

				weight->boneIndex = LittleLong( mdmVertex->weights[ k ].boneIndex );
				weight->boneWeight = LittleFloat( mdmVertex->weights[ k ].boneWeight );
				weight->offset[ 0 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 0 ] );
				weight->offset[ 1 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 1 ] );
				weight->offset[ 2 ] = LittleFloat( mdmVertex->weights[ k ].offset[ 2 ] );

				v->weights[ k ] = weight;
			}

			mdmVertex = ( mdmVertex_t * ) &mdmVertex->weights[ v->numWeights ];
		}

		// swap the collapse map
		surf->collapseMap = ri.Hunk_Alloc( sizeof( *collapseMapOut ) * mdmSurf->numVerts, h_low );

		collapseMap = ( int32_t * )( ( byte * ) mdmSurf + mdmSurf->ofsCollapseMap );

		//ri.Printf(PRINT_ALL, "collapse map for mdm surface '%s': ", surf->name);
		for ( j = 0, collapseMapOut = surf->collapseMap; j < mdmSurf->numVerts; j++, collapseMap++, collapseMapOut++ )
		{
			int32_t value = LittleLong( *collapseMap );
			//surf->collapseMap[j] = value;
			*collapseMapOut = value;

			//ri.Printf(PRINT_ALL, "(%i -> %i) ", j, value);
		}

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

#if 0
		ri.Printf( PRINT_ALL, "collapse map for mdm surface '%s': ", surf->name );

		for ( j = 0, collapseMap = surf->collapseMap; j < mdmSurf->numVerts; j++, collapseMap++ )
		{
			ri.Printf( PRINT_ALL, "(%i -> %i) ", j, *collapseMap );
		}

		ri.Printf( PRINT_ALL, "\n" );
#endif

		// swap the bone references
		surf->numBoneReferences = mdmSurf->numBoneReferences;
		surf->boneReferences = ri.Hunk_Alloc( sizeof( *bonerefOut ) * mdmSurf->numBoneReferences, h_low );

		boneref = ( int32_t * )( ( byte * ) mdmSurf + mdmSurf->ofsBoneReferences );

		for ( j = 0, bonerefOut = surf->boneReferences; j < surf->numBoneReferences; j++, boneref++, bonerefOut++ )
		{
			*bonerefOut = LittleLong( *boneref );
		}

		// find the next surface
		mdmSurf = ( mdmSurface_t * )( ( byte * ) mdmSurf + mdmSurf->ofsEnd );
	}

	// loading is done now calculate the bounding box and tangent spaces
	ClearBounds( mdmModel->bounds[ 0 ], mdmModel->bounds[ 1 ] );

	for ( i = 0, surf = mdmModel->surfaces; i < mdmModel->numSurfaces; i++, surf++ )
	{
		for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
		{
			vec3_t      tmpVert;
			md5Weight_t *w;

			VectorClear( tmpVert );

			for ( k = 0, w = v->weights[ 0 ]; k < v->numWeights; k++, w++ )
			{
				//vec3_t          offsetVec;

				//VectorClear(offsetVec);

				//bone = &md5->bones[w->boneIndex];

				//QuatTransformVector(bone->rotation, w->offset, offsetVec);
				//VectorAdd(bone->origin, offsetVec, offsetVec);

				VectorMA( tmpVert, w->boneWeight, w->offset, tmpVert );
			}

			VectorCopy( tmpVert, v->position );
			AddPointToBounds( tmpVert, mdmModel->bounds[ 0 ], mdmModel->bounds[ 1 ] );
		}

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

			for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
			{
				VectorClear( v->tangent );
				VectorClear( v->binormal );
				VectorClear( v->normal );
			}

			for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ )
			{
				v0 = surf->verts[ tri->indexes[ 0 ] ].position;
				v1 = surf->verts[ tri->indexes[ 1 ] ].position;
				v2 = surf->verts[ tri->indexes[ 2 ] ].position;

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

#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 = surf->verts[ tri->indexes[ k ] ].tangent;
					VectorAdd( v, tangent, v );

					v = surf->verts[ tri->indexes[ k ] ].binormal;
					VectorAdd( v, binormal, v );

					v = surf->verts[ tri->indexes[ k ] ].normal;
					VectorAdd( v, normal, v );
				}
			}

			for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
			{
				VectorNormalize( v->tangent );
				VectorNormalize( v->binormal );
				VectorNormalize( v->normal );
			}
		}
#else
		{
			int         k;
			float       bb, s, t;
			vec3_t      bary;
			vec3_t      faceNormal;
			md5Vertex_t *dv[ 3 ];

			for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ )
			{
				dv[ 0 ] = &surf->verts[ tri->indexes[ 0 ] ];
				dv[ 1 ] = &surf->verts[ tri->indexes[ 1 ] ];
				dv[ 2 ] = &surf->verts[ tri->indexes[ 2 ] ];

				R_CalcNormalForTriangle( faceNormal, dv[ 0 ]->position, dv[ 1 ]->position, dv[ 2 ]->position );

				// calculate barycentric basis for the triangle
				bb = ( dv[ 1 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 2 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ) - ( dv[ 2 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 1 ]->texCoords[ 1 ] -
				     dv[ 0 ]->texCoords[ 1 ] );

				if ( fabs( bb ) < 0.00000001f )
				{
					continue;
				}

				// do each vertex
				for ( k = 0; k < 3; k++ )
				{
					// calculate s tangent vector
					s = dv[ k ]->texCoords[ 0 ] + 10.0f;
					t = dv[ k ]->texCoords[ 1 ];
					bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb;
					bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb;
					bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb;

					dv[ k ]->tangent[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ];
					dv[ k ]->tangent[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ];
					dv[ k ]->tangent[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ];

					VectorSubtract( dv[ k ]->tangent, dv[ k ]->position, dv[ k ]->tangent );
					VectorNormalize( dv[ k ]->tangent );

					// calculate t tangent vector (binormal)
					s = dv[ k ]->texCoords[ 0 ];
					t = dv[ k ]->texCoords[ 1 ] + 10.0f;
					bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb;
					bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb;
					bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb;

					dv[ k ]->binormal[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ];
					dv[ k ]->binormal[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ];
					dv[ k ]->binormal[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ];

					VectorSubtract( dv[ k ]->binormal, dv[ k ]->position, dv[ k ]->binormal );
					VectorNormalize( dv[ k ]->binormal );

					// calculate the normal as cross product N=TxB
#if 0
					CrossProduct( dv[ k ]->tangent, dv[ k ]->binormal, dv[ k ]->normal );
					VectorNormalize( dv[ k ]->normal );

					// Gram-Schmidt orthogonalization process for B
					// compute the cross product B=NxT to obtain
					// an orthogonal basis
					CrossProduct( dv[ k ]->normal, dv[ k ]->tangent, dv[ k ]->binormal );

					if ( DotProduct( dv[ k ]->normal, faceNormal ) < 0 )
					{
						VectorInverse( dv[ k ]->normal );
						//VectorInverse(dv[k]->tangent);
						//VectorInverse(dv[k]->binormal);
					}

#else
					//VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal);
#endif
				}
			}

#if 1

			for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ )
			{
				//VectorNormalize(v->tangent);
				//VectorNormalize(v->binormal);
				//VectorNormalize(v->normal);
			}

#endif
		}
#endif

#if 0

		// do another extra smoothing for normals to avoid flat shading
		for ( j = 0; j < surf->numVerts; j++ )
		{
			for ( k = 0; k < surf->numVerts; k++ )
			{
				if ( j == k )
				{
					continue;
				}

				if ( VectorCompare( surf->verts[ j ].position, surf->verts[ k ].position ) )
				{
					VectorAdd( surf->verts[ j ].normal, surf->verts[ k ].normal, surf->verts[ j ].normal );
				}
			}

			VectorNormalize( surf->verts[ j ].normal );
		}

#endif
	}

	// split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones
	{
		int        numRemaining;
		growList_t sortedTriangles;
		growList_t vboTriangles;
		growList_t vboSurfaces;

		int        numBoneReferences;
		int        boneReferences[ MAX_BONES ];

		Com_InitGrowList( &vboSurfaces, 10 );

		for ( i = 0, surf = mdmModel->surfaces; i < mdmModel->numSurfaces; i++, surf++ )
		{
			// sort triangles
			Com_InitGrowList( &sortedTriangles, 1000 );

			for ( j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++ )
			{
				skelTriangle_t *sortTri = Com_Allocate( sizeof( *sortTri ) );

				for ( k = 0; k < 3; k++ )
				{
					sortTri->indexes[ k ] = tri->indexes[ k ];
					sortTri->vertexes[ k ] = &surf->verts[ tri->indexes[ k ] ];
				}

				sortTri->referenced = qfalse;

				Com_AddToGrowList( &sortedTriangles, sortTri );
			}

			//qsort(sortedTriangles.elements, sortedTriangles.currentElements, sizeof(void *), CompareTrianglesByBoneReferences);

#if 0

			for ( j = 0; j < sortedTriangles.currentElements; j++ )
			{
				int            b[ MAX_WEIGHTS * 3 ];

				skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j );

				for ( k = 0; k < 3; k++ )
				{
					v = sortTri->vertexes[ k ];

					for ( l = 0; l < MAX_WEIGHTS; l++ )
					{
						b[ k * 3 + l ] = ( l < v->numWeights ) ? v->weights[ l ]->boneIndex : 9999;
					}

					qsort( b, MAX_WEIGHTS * 3, sizeof( int ), CompareBoneIndices );
					//ri.Printf(PRINT_ALL, "bone indices: %i %i %i %i\n", b[k * 3 + 0], b[k * 3 + 1], b[k * 3 + 2], b[k * 3 + 3]);
				}
			}

#endif

			numRemaining = sortedTriangles.currentElements;

			while ( numRemaining )
			{
				numBoneReferences = 0;
				Com_Memset( boneReferences, 0, sizeof( boneReferences ) );

				Com_InitGrowList( &vboTriangles, 1000 );

				for ( j = 0; j < sortedTriangles.currentElements; j++ )
				{
					skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j );

					if ( sortTri->referenced )
					{
						continue;
					}

					if ( AddTriangleToVBOTriangleList( &vboTriangles, sortTri, &numBoneReferences, boneReferences ) )
					{
						sortTri->referenced = qtrue;
					}
				}

				if ( !vboTriangles.currentElements )
				{
					ri.Printf( PRINT_WARNING, "R_LoadMDM: could not add triangles to a remaining VBO surface for model '%s'\n", modName );
					break;
				}

				AddSurfaceToVBOSurfacesListMDM( &vboSurfaces, &vboTriangles, mdmModel, surf, i, numBoneReferences, boneReferences );
				numRemaining -= vboTriangles.currentElements;

				Com_DestroyGrowList( &vboTriangles );
			}

			for ( j = 0; j < sortedTriangles.currentElements; j++ )
			{
				skelTriangle_t *sortTri = Com_GrowListElement( &sortedTriangles, j );

				Com_Dealloc( sortTri );
			}

			Com_DestroyGrowList( &sortedTriangles );
		}

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

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

		Com_DestroyGrowList( &vboSurfaces );
	}

	return qtrue;
}
示例#12
0
qboolean R_LoadMD5(model_t *mod, void *buffer, int bufferSize, const char *modName)
{
	int           i, j, k;
	md5Model_t    *md5;
	md5Bone_t     *bone;
	md5Surface_t  *surf;
	srfTriangle_t *tri;
	md5Vertex_t   *v;
	md5Weight_t   *weight;
	int           version;
	shader_t      *sh;
	char          *buf_p = ( char * ) buffer;
	char          *token;
	vec3_t        boneOrigin;
	quat_t        boneQuat;
	matrix_t      boneMat;
	int           numRemaining;
	growList_t    sortedTriangles;
	growList_t    vboTriangles;
	growList_t    vboSurfaces;
	int           numBoneReferences;
	int           boneReferences[MAX_BONES];

	// skip MD5Version indent string
	COM_ParseExt2(&buf_p, qfalse);

	// check version
	token   = COM_ParseExt2(&buf_p, qfalse);
	version = atoi(token);

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

	mod->type      = MOD_MD5;
	mod->dataSize += sizeof(md5Model_t);
	md5            = mod->md5 = ri.Hunk_Alloc(sizeof(md5Model_t), h_low);

	// skip commandline <arguments string>
	token = COM_ParseExt2(&buf_p, qtrue);
	token = COM_ParseExt2(&buf_p, qtrue);
	//  Ren_Print("%s\n", token);

	// parse numJoints <number>
	token = COM_ParseExt2(&buf_p, qtrue);

	if (Q_stricmp(token, "numJoints"))
	{
		Ren_Warning("R_LoadMD5: expected 'numJoints' found '%s' in model '%s'\n", token, modName);
		return qfalse;
	}

	token         = COM_ParseExt2(&buf_p, qfalse);
	md5->numBones = atoi(token);

	// parse numMeshes <number>
	token = COM_ParseExt2(&buf_p, qtrue);

	if (Q_stricmp(token, "numMeshes"))
	{
		Ren_Warning("R_LoadMD5: expected 'numMeshes' found '%s' in model '%s'\n", token, modName);
		return qfalse;
	}

	token            = COM_ParseExt2(&buf_p, qfalse);
	md5->numSurfaces = atoi(token);
	//Ren_Print("R_LoadMD5: '%s' has %i surfaces\n", modName, md5->numSurfaces);

	if (md5->numBones < 1)
	{
		Ren_Warning("R_LoadMD5: '%s' has no bones\n", modName);
		return qfalse;
	}

	if (md5->numBones > MAX_BONES)
	{
		Ren_Warning("R_LoadMD5: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones);
		return qfalse;
	}

	//Ren_Print("R_LoadMD5: '%s' has %i bones\n", modName, md5->numBones);

	// parse all the bones
	md5->bones = ri.Hunk_Alloc(sizeof(*bone) * md5->numBones, h_low);

	// parse joints {
	token = COM_ParseExt2(&buf_p, qtrue);

	if (Q_stricmp(token, "joints"))
	{
		Ren_Warning("R_LoadMD5: expected 'joints' found '%s' in model '%s'\n", token, modName);
		return qfalse;
	}

	token = COM_ParseExt2(&buf_p, qfalse);

	if (Q_stricmp(token, "{"))
	{
		Ren_Warning("R_LoadMD5: expected '{' found '%s' in model '%s'\n", token, modName);
		return qfalse;
	}

	for (i = 0, bone = md5->bones; i < md5->numBones; i++, bone++)
	{
		token = COM_ParseExt2(&buf_p, qtrue);
		Q_strncpyz(bone->name, token, sizeof(bone->name));

		//Ren_Print("R_LoadMD5: '%s' has bone '%s'\n", modName, bone->name);

		token             = COM_ParseExt2(&buf_p, qfalse);
		bone->parentIndex = atoi(token);

		//Ren_Print("R_LoadMD5: '%s' has bone '%s' with parent index %i\n", modName, bone->name, bone->parentIndex);

		if (bone->parentIndex >= md5->numBones)
		{
			Ren_Drop("R_LoadMD5: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName,
			         bone->name, bone->parentIndex, md5->numBones);
		}

		// skip (
		token = COM_ParseExt2(&buf_p, qfalse);

		if (Q_stricmp(token, "("))
		{
			Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		for (j = 0; j < 3; j++)
		{
			token         = COM_ParseExt2(&buf_p, qfalse);
			boneOrigin[j] = atof(token);
		}

		// skip )
		token = COM_ParseExt2(&buf_p, qfalse);

		if (Q_stricmp(token, ")"))
		{
			Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		// skip (
		token = COM_ParseExt2(&buf_p, qfalse);

		if (Q_stricmp(token, "("))
		{
			Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		for (j = 0; j < 3; j++)
		{
			token       = COM_ParseExt2(&buf_p, qfalse);
			boneQuat[j] = atof(token);
		}

		QuatCalcW(boneQuat);
		MatrixFromQuat(boneMat, boneQuat);

		VectorCopy(boneOrigin, bone->origin);
		QuatCopy(boneQuat, bone->rotation);

		MatrixSetupTransformFromQuat(bone->inverseTransform, boneQuat, boneOrigin);
		MatrixInverse(bone->inverseTransform);

		// skip )
		token = COM_ParseExt2(&buf_p, qfalse);

		if (Q_stricmp(token, ")"))
		{
			Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}
	}

	// parse }
	token = COM_ParseExt2(&buf_p, qtrue);

	if (Q_stricmp(token, "}"))
	{
		Ren_Warning("R_LoadMD5: expected '}' found '%s' in model '%s'\n", token, modName);
		return qfalse;
	}

	// parse all the surfaces
	if (md5->numSurfaces < 1)
	{
		Ren_Warning("R_LoadMD5: '%s' has no surfaces\n", modName);
		return qfalse;
	}

	//Ren_Print("R_LoadMD5: '%s' has %i surfaces\n", modName, md5->numSurfaces);

	md5->surfaces = ri.Hunk_Alloc(sizeof(*surf) * md5->numSurfaces, h_low);

	for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++)
	{
		// parse mesh {
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "mesh"))
		{
			Ren_Warning("R_LoadMD5: expected 'mesh' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		token = COM_ParseExt2(&buf_p, qfalse);

		if (Q_stricmp(token, "{"))
		{
			Ren_Warning("R_LoadMD5: expected '{' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

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

		// give pointer to model for Tess_SurfaceMD5
		surf->model = md5;

		// parse shader <name>
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "shader"))
		{
			Ren_Warning("R_LoadMD5: expected 'shader' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		token = COM_ParseExt2(&buf_p, qfalse);
		Q_strncpyz(surf->shader, token, sizeof(surf->shader));

		//Ren_Print("R_LoadMD5: '%s' uses shader '%s'\n", modName, surf->shader);

		// FIXME .md5mesh meshes don't have surface names
		// lowercase the surface name so skin compares are faster
		//Q_strlwr(surf->name);
		//Ren_Print("R_LoadMD5: '%s' has surface '%s'\n", modName, surf->name);

		// register the shaders
		sh = R_FindShader(surf->shader, SHADER_3D_DYNAMIC, qtrue);

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

		// parse numVerts <number>
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "numVerts"))
		{
			Ren_Warning("R_LoadMD5: expected 'numVerts' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		token          = COM_ParseExt2(&buf_p, qfalse);
		surf->numVerts = atoi(token);

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

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

		for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
		{
			// skip vert <number>
			token = COM_ParseExt2(&buf_p, qtrue);

			if (Q_stricmp(token, "vert"))
			{
				Ren_Warning("R_LoadMD5: expected 'vert' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			COM_ParseExt2(&buf_p, qfalse);

			// skip (
			token = COM_ParseExt2(&buf_p, qfalse);

			if (Q_stricmp(token, "("))
			{
				Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			for (k = 0; k < 2; k++)
			{
				token           = COM_ParseExt2(&buf_p, qfalse);
				v->texCoords[k] = atof(token);
			}

			// skip )
			token = COM_ParseExt2(&buf_p, qfalse);

			if (Q_stricmp(token, ")"))
			{
				Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			token          = COM_ParseExt2(&buf_p, qfalse);
			v->firstWeight = atoi(token);

			token         = COM_ParseExt2(&buf_p, qfalse);
			v->numWeights = atoi(token);

			if (v->numWeights > MAX_WEIGHTS)
			{
				Ren_Drop("R_LoadMD5: vertex %i requires more than %i weights on surface (%i) in model '%s'",
				         j, MAX_WEIGHTS, i, modName);
			}
		}

		// parse numTris <number>
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "numTris"))
		{
			Ren_Warning("R_LoadMD5: expected 'numTris' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		token              = COM_ParseExt2(&buf_p, qfalse);
		surf->numTriangles = atoi(token);

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

		surf->triangles = ri.Hunk_Alloc(sizeof(*tri) * surf->numTriangles, h_low);

		for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
		{
			// skip tri <number>
			token = COM_ParseExt2(&buf_p, qtrue);

			if (Q_stricmp(token, "tri"))
			{
				Ren_Warning("R_LoadMD5: expected 'tri' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			COM_ParseExt2(&buf_p, qfalse);

			for (k = 0; k < 3; k++)
			{
				token           = COM_ParseExt2(&buf_p, qfalse);
				tri->indexes[k] = atoi(token);
			}
		}

		// parse numWeights <number>
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "numWeights"))
		{
			Ren_Warning("R_LoadMD5: expected 'numWeights' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		token            = COM_ParseExt2(&buf_p, qfalse);
		surf->numWeights = atoi(token);

		surf->weights = ri.Hunk_Alloc(sizeof(*weight) * surf->numWeights, h_low);

		for (j = 0, weight = surf->weights; j < surf->numWeights; j++, weight++)
		{
			// skip weight <number>
			token = COM_ParseExt2(&buf_p, qtrue);

			if (Q_stricmp(token, "weight"))
			{
				Ren_Warning("R_LoadMD5: expected 'weight' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			COM_ParseExt2(&buf_p, qfalse);

			token             = COM_ParseExt2(&buf_p, qfalse);
			weight->boneIndex = atoi(token);

			token              = COM_ParseExt2(&buf_p, qfalse);
			weight->boneWeight = atof(token);

			// skip (
			token = COM_ParseExt2(&buf_p, qfalse);

			if (Q_stricmp(token, "("))
			{
				Ren_Warning("R_LoadMD5: expected '(' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}

			for (k = 0; k < 3; k++)
			{
				token             = COM_ParseExt2(&buf_p, qfalse);
				weight->offset[k] = atof(token);
			}

			// skip )
			token = COM_ParseExt2(&buf_p, qfalse);

			if (Q_stricmp(token, ")"))
			{
				Ren_Warning("R_LoadMD5: expected ')' found '%s' in model '%s'\n", token, modName);
				return qfalse;
			}
		}

		// parse }
		token = COM_ParseExt2(&buf_p, qtrue);

		if (Q_stricmp(token, "}"))
		{
			Ren_Warning("R_LoadMD5: expected '}' found '%s' in model '%s'\n", token, modName);
			return qfalse;
		}

		// loop trough all vertices and set up the vertex weights
		for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
		{
			v->weights = ri.Hunk_Alloc(sizeof(*v->weights) * v->numWeights, h_low);

			for (k = 0; k < v->numWeights; k++)
			{
				v->weights[k] = surf->weights + (v->firstWeight + k);
			}
		}
	}

	// loading is done now calculate the bounding box and tangent spaces
	ClearBounds(md5->bounds[0], md5->bounds[1]);

	for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++)
	{
		for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
		{
			vec3_t      tmpVert;
			md5Weight_t *w;

			VectorClear(tmpVert);

			for (k = 0, w = v->weights[0]; k < v->numWeights; k++, w++)
			{
				vec3_t offsetVec;

				bone = &md5->bones[w->boneIndex];

				QuatTransformVector(bone->rotation, w->offset, offsetVec);
				VectorAdd(bone->origin, offsetVec, offsetVec);

				VectorMA(tmpVert, w->boneWeight, offsetVec, tmpVert);
			}

			VectorCopy(tmpVert, v->position);
			AddPointToBounds(tmpVert, md5->bounds[0], md5->bounds[1]);
		}

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

			for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
			{
				VectorClear(v->tangent);
				VectorClear(v->binormal);
				VectorClear(v->normal);
			}

			for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
			{
				v0 = surf->verts[tri->indexes[0]].position;
				v1 = surf->verts[tri->indexes[1]].position;
				v2 = surf->verts[tri->indexes[2]].position;

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

#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 = surf->verts[tri->indexes[k]].tangent;
					VectorAdd(v, tangent, v);

					v = surf->verts[tri->indexes[k]].binormal;
					VectorAdd(v, binormal, v);

					v = surf->verts[tri->indexes[k]].normal;
					VectorAdd(v, normal, v);
				}
			}

			for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
			{
				VectorNormalize(v->tangent);
				VectorNormalize(v->binormal);
				VectorNormalize(v->normal);
			}
		}
#else
		{
			int         k;
			float       bb, s, t;
			vec3_t      bary;
			vec3_t      faceNormal;
			md5Vertex_t *dv[3];

			for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
			{
				dv[0] = &surf->verts[tri->indexes[0]];
				dv[1] = &surf->verts[tri->indexes[1]];
				dv[2] = &surf->verts[tri->indexes[2]];

				R_CalcNormalForTriangle(faceNormal, dv[0]->position, dv[1]->position, dv[2]->position);

				// calculate barycentric basis for the triangle
				bb = (dv[1]->texCoords[0] - dv[0]->texCoords[0]) * (dv[2]->texCoords[1] - dv[0]->texCoords[1]) - (dv[2]->texCoords[0] - dv[0]->texCoords[0]) * (dv[1]->texCoords[1] -
				                                                                                                                                                dv[0]->texCoords[1]);

				if (fabs(bb) < 0.00000001f)
				{
					continue;
				}

				// do each vertex
				for (k = 0; k < 3; k++)
				{
					// calculate s tangent vector
					s       = dv[k]->texCoords[0] + 10.0f;
					t       = dv[k]->texCoords[1];
					bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
					bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
					bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

					dv[k]->tangent[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
					dv[k]->tangent[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
					dv[k]->tangent[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

					VectorSubtract(dv[k]->tangent, dv[k]->position, dv[k]->tangent);
					VectorNormalize(dv[k]->tangent);

					// calculate t tangent vector (binormal)
					s       = dv[k]->texCoords[0];
					t       = dv[k]->texCoords[1] + 10.0f;
					bary[0] = ((dv[1]->texCoords[0] - s) * (dv[2]->texCoords[1] - t) - (dv[2]->texCoords[0] - s) * (dv[1]->texCoords[1] - t)) / bb;
					bary[1] = ((dv[2]->texCoords[0] - s) * (dv[0]->texCoords[1] - t) - (dv[0]->texCoords[0] - s) * (dv[2]->texCoords[1] - t)) / bb;
					bary[2] = ((dv[0]->texCoords[0] - s) * (dv[1]->texCoords[1] - t) - (dv[1]->texCoords[0] - s) * (dv[0]->texCoords[1] - t)) / bb;

					dv[k]->binormal[0] = bary[0] * dv[0]->position[0] + bary[1] * dv[1]->position[0] + bary[2] * dv[2]->position[0];
					dv[k]->binormal[1] = bary[0] * dv[0]->position[1] + bary[1] * dv[1]->position[1] + bary[2] * dv[2]->position[1];
					dv[k]->binormal[2] = bary[0] * dv[0]->position[2] + bary[1] * dv[1]->position[2] + bary[2] * dv[2]->position[2];

					VectorSubtract(dv[k]->binormal, dv[k]->position, dv[k]->binormal);
					VectorNormalize(dv[k]->binormal);

					// calculate the normal as cross product N=TxB
#if 0
					CrossProduct(dv[k]->tangent, dv[k]->binormal, dv[k]->normal);
					VectorNormalize(dv[k]->normal);

					// Gram-Schmidt orthogonalization process for B
					// compute the cross product B=NxT to obtain
					// an orthogonal basis
					CrossProduct(dv[k]->normal, dv[k]->tangent, dv[k]->binormal);

					if (DotProduct(dv[k]->normal, faceNormal) < 0)
					{
						VectorInverse(dv[k]->normal);
						//VectorInverse(dv[k]->tangent);
						//VectorInverse(dv[k]->binormal);
					}

#else
					VectorAdd(dv[k]->normal, faceNormal, dv[k]->normal);
#endif
				}
			}

#if 1
			for (j = 0, v = surf->verts; j < surf->numVerts; j++, v++)
			{
				//VectorNormalize(v->tangent);
				//VectorNormalize(v->binormal);
				VectorNormalize(v->normal);
			}
#endif
		}
#endif

#if 0
		// do another extra smoothing for normals to avoid flat shading
		for (j = 0; j < surf->numVerts; j++)
		{
			for (k = 0; k < surf->numVerts; k++)
			{
				if (j == k)
				{
					continue;
				}

				if (VectorCompare(surf->verts[j].position, surf->verts[k].position))
				{
					VectorAdd(surf->verts[j].normal, surf->verts[k].normal, surf->verts[j].normal);
				}
			}

			VectorNormalize(surf->verts[j].normal);
		}
#endif
	}

	// split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones
	Com_InitGrowList(&vboSurfaces, 10);

	for (i = 0, surf = md5->surfaces; i < md5->numSurfaces; i++, surf++)
	{
		// sort triangles
		Com_InitGrowList(&sortedTriangles, 1000);

		for (j = 0, tri = surf->triangles; j < surf->numTriangles; j++, tri++)
		{
			skelTriangle_t *sortTri = Com_Allocate(sizeof(*sortTri));

			for (k = 0; k < 3; k++)
			{
				sortTri->indexes[k]  = tri->indexes[k];
				sortTri->vertexes[k] = &surf->verts[tri->indexes[k]];
			}

			sortTri->referenced = qfalse;

			Com_AddToGrowList(&sortedTriangles, sortTri);
		}

		//qsort(sortedTriangles.elements, sortedTriangles.currentElements, sizeof(void *), CompareTrianglesByBoneReferences);

#if 0
		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			int b[MAX_WEIGHTS * 3];

			skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j);

			for (k = 0; k < 3; k++)
			{
				v = sortTri->vertexes[k];

				for (l = 0; l < MAX_WEIGHTS; l++)
				{
					b[k * 3 + l] = (l < v->numWeights) ? v->weights[l]->boneIndex : 9999;
				}

				qsort(b, MAX_WEIGHTS * 3, sizeof(int), CompareBoneIndices);
				//Ren_Print("bone indices: %i %i %i %i\n", b[k * 3 + 0], b[k * 3 + 1], b[k * 3 + 2], b[k * 3 + 3]);
			}
		}
#endif

		numRemaining = sortedTriangles.currentElements;

		while (numRemaining)
		{
			numBoneReferences = 0;
			Com_Memset(boneReferences, 0, sizeof(boneReferences));

			Com_InitGrowList(&vboTriangles, 1000);

			for (j = 0; j < sortedTriangles.currentElements; j++)
			{
				skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j);

				if (sortTri->referenced)
				{
					continue;
				}

				if (AddTriangleToVBOTriangleList(&vboTriangles, sortTri, &numBoneReferences, boneReferences))
				{
					sortTri->referenced = qtrue;
				}
			}

			if (!vboTriangles.currentElements)
			{
				Ren_Warning("R_LoadMD5: could not add triangles to a remaining VBO surfaces for model '%s'\n", modName);
				Com_DestroyGrowList(&vboTriangles);
				break;
			}

			AddSurfaceToVBOSurfacesList(&vboSurfaces, &vboTriangles, md5, surf, i, numBoneReferences, boneReferences);
			numRemaining -= vboTriangles.currentElements;

			Com_DestroyGrowList(&vboTriangles);
		}

		for (j = 0; j < sortedTriangles.currentElements; j++)
		{
			skelTriangle_t *sortTri = Com_GrowListElement(&sortedTriangles, j);

			Com_Dealloc(sortTri);
		}

		Com_DestroyGrowList(&sortedTriangles);
	}

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

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

	Com_DestroyGrowList(&vboSurfaces);

	return qtrue;
}
示例#13
0
void JVM_Init(void)
{
	int				i;
	jint            nVMs = 0;		// number of VM's active
	JavaVMInitArgs  vm_args;

	growList_t      growOptions;
	JavaVMOption   *option;
	JavaVMOption   *options;

	char            classPath[MAX_QPATH];
	char            policyPath[MAX_OSPATH];

	Com_InitGrowList(&growOptions, 5);

	Com_Printf("------- JVM_Init() -------\n");

	jvm_javaLib = Cvar_Get("jvm_javaLib", DEFAULT_JAVA_LIB, CVAR_ARCHIVE | CVAR_LATCH);
	jvm_useJITCompiler = Cvar_Get("jvm_useJITCompiler", "1", CVAR_INIT);
	jvm_useJAR = Cvar_Get("jvm_useJAR", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_remoteDebugging = Cvar_Get("jvm_remoteDebugging", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_profiling = Cvar_Get("jvm_profiling", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_verboseJNI = Cvar_Get("jvm_verboseJNI", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_verboseClass = Cvar_Get("jvm_verboseClass", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_verboseGC = Cvar_Get("jvm_verboseGC", "0", CVAR_ARCHIVE | CVAR_LATCH);
	jvm_policyFile = Cvar_Get("jvm_policyFile", "", CVAR_ARCHIVE | CVAR_LATCH);

	option = AllocOption(&growOptions);

	if(!jvm_useJITCompiler->integer)
	{
		Com_Printf("Disabling Java JIT support\n");
		option->optionString = "-Djava.compiler=NONE";
	}
	else
	{
		option->optionString = "-Djava.compiler=YES";
	}

	// TODO support sv_pure
	if(jvm_useJAR->integer)
	{
		Com_sprintf(classPath, sizeof(classPath), "-Djava.class.path=%s",
					FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), "game.jar"));
	}
	else
	{
		Com_sprintf(classPath, sizeof(classPath), "-Djava.class.path=%s",
					FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), "classes"));
	}

	option = AllocOption(&growOptions);
	option->optionString = classPath;

	Com_Printf("Set main class path to '%s'\n", classPath);

	if(jvm_remoteDebugging->integer)
	{
		Com_Printf("Enabling remote debugging\n");

		option = AllocOption(&growOptions);
		option->optionString = "-Xdebug";

		option = AllocOption(&growOptions);
		option->optionString = "-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=y";
	}

	if(jvm_verboseJNI->integer)
	{
		Com_Printf("Enabling verbose JNI prints\n");

		option = AllocOption(&growOptions);
		option->optionString = "-verbose:jni";
	}

	if(jvm_verboseClass->integer)
	{
		Com_Printf("Enabling displaying information about each class loaded.\n");

		option = AllocOption(&growOptions);
		option->optionString = "-verbose:class";
	}

	if(jvm_verboseGC->integer)
	{
		Com_Printf("Enabling reports on each garbage collection event.\n");

		option = AllocOption(&growOptions);
		option->optionString = "-verbose:gc";
	}

#if 1
	{
		Com_Printf("Enabling security manager\n");

		option = AllocOption(&growOptions);
		option->optionString = "-Djava.security.manager";
	}
#endif

	if(Q_stricmp(jvm_policyFile->string, "") != 0)
	{
		Com_sprintf(policyPath, sizeof(policyPath), "-Djava.security.policy=file:%s", FS_BuildOSPath(Cvar_VariableString("fs_basepath"), Cvar_VariableString("fs_game"), jvm_policyFile->string));

		option = AllocOption(&growOptions);
		option->optionString = policyPath;

		Com_Printf("Enabling '%s'\n", policyPath);
	}



	// convert growlist to array
	options = Com_Allocate(growOptions.currentElements * sizeof(JavaVMOption));
	for(i = 0; i < growOptions.currentElements; i++)
	{
		options[i] = *(JavaVMOption*) Com_GrowListElement(&growOptions, i);
	}

	vm_args.version = JNI_VERSION_1_4;
	vm_args.options = options;
	vm_args.nOptions = growOptions.currentElements;
	vm_args.ignoreUnrecognized = JNI_TRUE;

#if defined(USE_JAVA_DLOPEN)
	if(!JVM_JNI_Init())
	{
		Com_Error(ERR_FATAL, "JNI initialization failed");
	}
#endif

	Com_Printf("Searching for existing Java VM's ...");

	// look for an existing VM
#if defined(USE_JAVA_DLOPEN)
	if(QJNI_GetCreatedJavaVMs(&javaVM, 1, &nVMs) != JNI_OK)
#else
	if(JNI_GetCreatedJavaVMs(&javaVM, 1, &nVMs) != JNI_OK)
#endif
	{
		Com_Error(ERR_FATAL, "Search for existing VM's failed");
	}

	Com_Printf("found %i\n", nVMs);

#if 1
	if(nVMs > 0)
	{
		Com_Printf("Attaching to existing Java VM...");

		if((*javaVM)->AttachCurrentThread(javaVM, (void **)&javaEnv, NULL))
		{
			Com_Error(ERR_FATAL, "Couldn't attach to existing VM");
		}

		javaVMIsOurs = qfalse;
		//javaVM = jvm;

		Com_Printf("done\n");
	}
	else
#endif
	{
		int res;

		Com_Printf("Creating new Java VM...");

		// Create the Java VM
#if defined(USE_JAVA_DLOPEN)
		res = QJNI_CreateJavaVM(&javaVM, (void **)&javaEnv, &vm_args);
#else
		res = JNI_CreateJavaVM(&javaVM, (void **)&javaEnv, &vm_args);
#endif
		if(res != JNI_OK )
		{
			Com_Error(ERR_FATAL, "Can't create Java VM, JNI returned %i", res);
		}

		//javaVM = jvm;

		Com_Printf("done\n");
	}

	if(!javaVM)
	{
		Com_Error(ERR_FATAL, "JVM_Init failed");
	}

	// finally register the needed core modules
	Misc_javaRegister();
	Engine_javaRegister();
	CVar_javaRegister();
	UserCommand_javaRegister();


	// clean up allocated objects
	for(i = 0; i < growOptions.currentElements; i++)
	{
		option = Com_GrowListElement(&growOptions, i);
		Com_Dealloc(option);
	}
	Com_DestroyGrowList(&growOptions);

	Com_Dealloc(options);
}
示例#14
0
qboolean OGV_StartRead(cinematic_t *cin)
{
	int        status;
	ogg_page   og;
	ogg_packet op;
	int        i;

	cin->data = Com_Allocate(sizeof(cin_ogv_t));
	Com_Memset(cin->data, 0, sizeof(cin_ogv_t));

	ogg_sync_init(&g_ogm->oy);  /* Now we can read pages */

	//FIXME? can serialno be 0 in ogg? (better way to check inited?)
	//TODO: support for more than one audio stream? / detect files with one stream(or without correct ones)
	while (!g_ogm->os_audio.serialno || !g_ogm->os_video.serialno)
	{
		if (ogg_sync_pageout(&g_ogm->oy, &og) == 1)
		{
			if (strstr((char *)(og.body + 1), "vorbis"))
			{
				//FIXME? better way to find audio stream
				if (g_ogm->os_audio.serialno)
				{
					Com_Printf(S_COLOR_YELLOW "WARNING: more than one audio stream, in ogm-file(%s) ... we will stay at the first one\n", cin->name);
				}
				else
				{
					ogg_stream_init(&g_ogm->os_audio, ogg_page_serialno(&og));
					ogg_stream_pagein(&g_ogm->os_audio, &og);
				}
			}
			if (strstr((char *)(og.body + 1), "theora"))
			{
				if (g_ogm->os_video.serialno)
				{
					Com_Printf(S_COLOR_YELLOW "WARNING: more than one video stream, in ogm-file(%s) ... we will stay at the first one\n", cin->name);
				}
				else
				{
					ogg_stream_init(&g_ogm->os_video, ogg_page_serialno(&og));
					ogg_stream_pagein(&g_ogm->os_video, &og);
				}
			}
		}
		else if (OGV_LoadBlockToSync(cin))
		{
			break;
		}
	}

	if (!g_ogm->os_audio.serialno)
	{
		Com_Printf(S_COLOR_YELLOW "WARNING: Haven't found a audio(vorbis) stream in ogm-file (%s)\n", cin->name);
		return qfalse;
	}

	if (!g_ogm->os_video.serialno)
	{
		Com_Printf(S_COLOR_YELLOW "WARNING: Haven't found a video stream in ogm-file (%s)\n", cin->name);
		return qfalse;
	}

	//load vorbis header
	vorbis_info_init(&g_ogm->vi);
	vorbis_comment_init(&g_ogm->vc);
	i = 0;
	while (i < 3)
	{
		status = ogg_stream_packetout(&g_ogm->os_audio, &op);
		if (status < 0)
		{
			Com_Printf(S_COLOR_YELLOW "WARNING: Corrupt ogg packet while loading vorbis-headers, ogm-file(%s)\n", cin->name);
			return qfalse;
		}
		if (status > 0)
		{
			status = vorbis_synthesis_headerin(&g_ogm->vi, &g_ogm->vc, &op);
			if (i == 0 && status < 0)
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: This Ogg bitstream does not contain Vorbis audio data, ogm-file(%s)\n", cin->name);
				return qfalse;
			}
			++i;
		}
		else if (OGV_LoadPagesToStreams(cin))
		{
			if (OGV_LoadBlockToSync(cin))
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: Couldn't find all vorbis headers before end of ogm-file (%s)\n", cin->name);
				return qfalse;
			}
		}
	}

	vorbis_synthesis_init(&g_ogm->vd, &g_ogm->vi);

	// Do init
	{
		theora_info_init(&g_ogm->th_info);
		theora_comment_init(&g_ogm->th_comment);

		i = 0;
		while (i < 3)
		{
			status = ogg_stream_packetout(&g_ogm->os_video, &op);
			if (status < 0)
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: Corrupt ogg packet while loading theora-headers, ogm-file(%s)\n", cin->name);
				return qfalse;
			}
			else if (status > 0)
			{
				status = theora_decode_header(&g_ogm->th_info, &g_ogm->th_comment, &op);
				if (i == 0 && status != 0)
				{
					Com_Printf(S_COLOR_YELLOW "WARNING: This Ogg bitstream does not contain theora data, ogm-file(%s)\n", cin->name);
					return qfalse;
				}
				++i;
			}
			else if (OGV_LoadPagesToStreams(cin))
			{
				if (OGV_LoadBlockToSync(cin))
				{
					Com_Printf(S_COLOR_YELLOW "WARNING: Couldn't find all theora headers before end of ogm-file (%s)\n", cin->name);
					return qfalse;
				}
			}
		}

		theora_decode_init(&g_ogm->th_state, &g_ogm->th_info);

		g_ogm->Vtime_unit = ((ogg_int64_t) g_ogm->th_info.fps_denominator * 1000 * 10000 / g_ogm->th_info.fps_numerator);
	}

	Com_DPrintf("Theora init done (%s)\n", cin->name);
	return qtrue;
}
示例#15
0
void Com_InitGrowList(growList_t *list, int maxElements)
{
	list->maxElements     = maxElements;
	list->currentElements = 0;
	list->elements        = (void **)Com_Allocate(list->maxElements * sizeof(void *));
}
示例#16
0
文件: tr_curve.c 项目: Ododo/etlegacy
static srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
                                              srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
                                              float errorTable[2][MAX_GRID_SIZE],
                                              int numTriangles, srfTriangle_t triangles[SHADER_MAX_TRIANGLES])
{
	int           i, j, size;
	srfVert_t     *vert;
	vec3_t        tmpVec;
	srfGridMesh_t *grid;

	// copy the results out to a grid
	size = sizeof(*grid);

	if (r_stitchCurves->integer)
	{
		grid = /*ri.Hunk_Alloc */ (srfGridMesh_t *)Com_Allocate(size);
		Com_Memset(grid, 0, size);

		grid->widthLodError = /*ri.Hunk_Alloc */ (float *)Com_Allocate(width * 4);
		Com_Memcpy(grid->widthLodError, errorTable[0], width * 4);

		grid->heightLodError = /*ri.Hunk_Alloc */ (float *)Com_Allocate(height * 4);
		Com_Memcpy(grid->heightLodError, errorTable[1], height * 4);

		grid->numTriangles = numTriangles;
		grid->triangles    = (srfTriangle_t *)Com_Allocate(grid->numTriangles * sizeof(srfTriangle_t));
		Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));

		grid->numVerts = (width * height);
		grid->verts    = (srfVert_t *)Com_Allocate(grid->numVerts * sizeof(srfVert_t));
	}
	else
	{
		grid = (srfGridMesh_t *)ri.Hunk_Alloc(size, h_low);
		Com_Memset(grid, 0, size);

		grid->widthLodError = (float *)ri.Hunk_Alloc(width * 4, h_low);
		Com_Memcpy(grid->widthLodError, errorTable[0], width * 4);

		grid->heightLodError = (float *)ri.Hunk_Alloc(height * 4, h_low);
		Com_Memcpy(grid->heightLodError, errorTable[1], height * 4);

		grid->numTriangles = numTriangles;
		grid->triangles    = (srfTriangle_t *)ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low);
		Com_Memcpy(grid->triangles, triangles, numTriangles * sizeof(srfTriangle_t));

		grid->numVerts = (width * height);
		grid->verts    = (srfVert_t *)ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
	}

	grid->width       = width;
	grid->height      = height;
	grid->surfaceType = SF_GRID;
	ClearBounds(grid->bounds[0], grid->bounds[1]);
	for (i = 0; i < width; i++)
	{
		for (j = 0; j < height; j++)
		{
			vert  = &grid->verts[j * width + i];
			*vert = ctrl[j][i];
			AddPointToBounds(vert->xyz, grid->bounds[0], grid->bounds[1]);
		}
	}

	// compute local origin and bounds
	VectorAdd(grid->bounds[0], grid->bounds[1], grid->origin);
	VectorScale(grid->origin, 0.5f, grid->origin);
	VectorSubtract(grid->bounds[0], grid->origin, tmpVec);
	grid->radius = VectorLength(tmpVec);

	VectorCopy(grid->origin, grid->lodOrigin);
	grid->lodRadius = grid->radius;

	return grid;
}
示例#17
0
/*
=======================================================================================================================================
DL_GetString
=======================================================================================================================================
*/
char *DL_GetString(const char *url) {
	CURL *curl = NULL;
	CURLcode status;
	char *data = NULL;
	long code;

	write_result_t write_result = {NULL, 0};

	if (!url) {
		Com_Printf(S_COLOR_RED "DL_GetString: Error - empty download URL\n");
		return NULL;
	}

	DL_InitDownload();

	curl = curl_easy_init();
	data = (char *)Com_Allocate(GET_BUFFER_SIZE);

	if (!data) {
		goto error_get;
	} else {
		write_result.data = data;
	}

	curl_easy_setopt(curl, CURLOPT_USERAGENT, va("%s %s", APP_NAME "/" APP_VERSION, curl_version()));
	curl_easy_setopt(curl, CURLOPT_URL, url);
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DL_write_function);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&write_result);
#ifdef FEATURE_OPENSSL
#if 0
	curl_easy_setopt(dl_request, CURLOPT_CAINFO, "./cert.crt");
#else
	curl_easy_setopt(dl_request, CURLOPT_SSL_VERIFYHOST, 0);
	curl_easy_setopt(dl_request, CURLOPT_SSL_VERIFYPEER, 0);
#endif
#endif
	status = curl_easy_perform(curl);

	if (status != 0) {
		Com_Printf(S_COLOR_RED "DL_GetString: Error - unable to request data from %s\n", url);
		Com_Printf(S_COLOR_RED "DL_GetString: Error - %s\n", curl_easy_strerror(status));
		goto error_get;
	}

	curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);

	if (code != 200) {
		Com_Printf(S_COLOR_RED "DL_GetString: Error - server responded with code %ld\n", code);
		goto error_get;
	}

	curl_easy_cleanup(curl);
	data[write_result.pos] = '\0';

	return data;

error_get:
	if (curl) {
		curl_easy_cleanup(curl);
	}

	if (data) {
		Com_Dealloc(data);
	}

	return NULL;
}