예제 #1
0
파일: skins.cpp 프로젝트: 3ddy/Jedi-Academy
static Skins_ApplyVariant(ModelContainer_t *pContainer, SkinSet_t::iterator itEthnic, ShadersForMaterial_t::iterator itMaterialShaders, string strMaterialName, int iVariant)
{
	if (itMaterialShaders != (*itEthnic).second.end())
	{
		LPCSTR psShaderName	= (*itMaterialShaders).second[iVariant].c_str();	// shader name to load from skinset

		pContainer->MaterialShaders[strMaterialName] = psShaderName;

		LPCSTR psLocalTexturePath = R_FindShader( psShaderName );		// shader->texture name

		if (psLocalTexturePath && strlen(psLocalTexturePath))
		{
			TextureHandle_t hTexture = TextureHandle_ForName( psLocalTexturePath );

			if (hTexture == -1)
			{
				hTexture = Texture_Load(psLocalTexturePath);
			}

			GLuint uiBind = Texture_GetGLBind( hTexture );

			pContainer->MaterialBinds[strMaterialName] = uiBind;
		}
	}
}
예제 #2
0
파일: tr_model.cpp 프로젝트: Avygeil/NewJK
// if return == true, no further action needed by the caller...
//
void *RE_RegisterModels_Malloc(int iSize, void *pvDiskBufferIfJustLoaded, const char *psModelFileName, qboolean *pqbAlreadyFound, memtag_t eTag)
{
	char sModelName[MAX_QPATH];

	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
	Q_strlwr  (sModelName);

	CachedEndianedModelBinary_t &ModelBin = (*CachedModels)[sModelName];

	if (ModelBin.pModelDiskImage == NULL)
	{
		// ... then this entry has only just been created, ie we need to load it fully...
		//
		// new, instead of doing a R_Malloc and assigning that we just morph the disk buffer alloc
		//	then don't thrown it away on return - cuts down on mem overhead
		//
		// ... groan, but not if doing a limb hierarchy creation (some VV stuff?), in which case it's NULL
		//
		if ( pvDiskBufferIfJustLoaded )
		{
			R_MorphMallocTag( pvDiskBufferIfJustLoaded, eTag );
		}
		else
		{
			pvDiskBufferIfJustLoaded =  R_Malloc(iSize,eTag, qfalse );
		}

		ModelBin.pModelDiskImage= pvDiskBufferIfJustLoaded;
		ModelBin.iAllocSize		= iSize;
		*pqbAlreadyFound		= qfalse;
	}
	else
	{
		// if we already had this model entry, then re-register all the shaders it wanted...
		//
		const int iEntries = ModelBin.ShaderRegisterData.size();
		for (int i=0; i<iEntries; i++)
		{
			int iShaderNameOffset	= ModelBin.ShaderRegisterData[i].first;
			int iShaderPokeOffset	= ModelBin.ShaderRegisterData[i].second;

			const char *const psShaderName	 =		   &((char*)ModelBin.pModelDiskImage)[iShaderNameOffset];
				  int  *const piShaderPokePtr= (int *) &((char*)ModelBin.pModelDiskImage)[iShaderPokeOffset];

			shader_t *sh = R_FindShader( psShaderName, lightmapsNone, stylesDefault, qtrue );

			if ( sh->defaultShader )
			{
				*piShaderPokePtr = 0;
			} else {
				*piShaderPokePtr = sh->index;
			}
		}
		*pqbAlreadyFound = qtrue;	// tell caller not to re-Endian or re-Shader this binary
	}

	ModelBin.iLastLevelUsedOn = RE_RegisterMedia_GetLevel();

	return ModelBin.pModelDiskImage;
}
예제 #3
0
// if return == true, no further action needed by the caller...
//
void *RE_RegisterModels_Malloc(int iSize, const char *psModelFileName, qboolean *pqbAlreadyFound, memtag_t eTag)
{
	char sModelName[MAX_QPATH];

	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
	Q_strlwr  (sModelName);

	CachedEndianedModelBinary_t &ModelBin = CachedModels[sModelName];

	if (ModelBin.pModelDiskImage == NULL)
	{
		// ... then this entry has only just been created, ie we need to load it fully...
		//
		void *pMalloc = ri.Malloc(iSize,eTag, qfalse );

		if (!pMalloc)	// not needed anymore, but wtf?
		{
			ri.Error( ERR_FATAL, "RE_RegisterModels_Malloc(): Failed to alloc %d bytes for \"%s\"!", iSize, psModelFileName );
		}

		ModelBin.pModelDiskImage= pMalloc;
		ModelBin.iAllocSize		= iSize;
		*pqbAlreadyFound		= qfalse;
	}
	else
	{
		// if we already had this model entry, then re-register all the shaders it wanted...
		//
		const int iEntries = ModelBin.ShaderRegisterData.size();
		for (int i=0; i<iEntries; i++)
		{
			int iShaderNameOffset	= ModelBin.ShaderRegisterData[i].first;
			int iShaderPokeOffset	= ModelBin.ShaderRegisterData[i].second;

			const char *const psShaderName	 =		   &((char*)ModelBin.pModelDiskImage)[iShaderNameOffset];
				  int  *const piShaderPokePtr= (int *) &((char*)ModelBin.pModelDiskImage)[iShaderPokeOffset];

			shader_t *sh = R_FindShader( psShaderName, lightmapsNone, stylesDefault, qtrue );
	            
			if ( sh->defaultShader ) 
			{
				*piShaderPokePtr = 0;
			} else {
				*piShaderPokePtr = sh->index;
			}
		}
		*pqbAlreadyFound = qtrue;	// tell caller not to re-Endian or re-Shader this binary		
	}

	ModelBin.iLastLevelUsedOn = RE_RegisterMedia_GetLevel();

	return ModelBin.pModelDiskImage;
}
예제 #4
0
static void R_x42LoadDefaultShaders( x42data_t *x42 )
{
	uint i;

	x42->groupMats = (int*)ri.Hunk_Alloc( sizeof( int ) * x42->header.numGroups, h_low );
	for( i = 0; i < x42->header.numGroups; i++ )
	{
		shader_t *shader = R_FindShader( x42->strings + x42->groups[i].material, LIGHTMAP_NONE, qtrue );
		x42->groupMats[i] = shader->defaultShader ? 0 : shader->index;

		Q_strlwr( (char*)x42->strings + x42->groups[i].surfaceName );
	}
}
예제 #5
0
파일: model.cpp 프로젝트: janisl/jlquake
//	loads a model's shadow script
static void R_LoadModelShadow( idRenderModel* mod ) {
	// set default shadow
	mod->q3_shadowShader = 0;

	// build name
	char filename[ 1024 ];
	String::StripExtension2( mod->name, filename, sizeof ( filename ) );
	String::DefaultExtension( filename, 1024, ".shadow" );

	// load file
	char* buf;
	FS_ReadFile( filename, ( void** )&buf );
	if ( !buf ) {
		return;
	}

	char* shadowBits = strchr( buf, ' ' );
	if ( shadowBits != NULL ) {
		*shadowBits = '\0';
		shadowBits++;

		if ( String::Length( buf ) >= MAX_QPATH ) {
			common->Printf( "R_LoadModelShadow: Shader name exceeds MAX_QPATH\n" );
			mod->q3_shadowShader = 0;
		} else {
			shader_t* sh = R_FindShader( buf, LIGHTMAP_NONE, true );

			if ( sh->defaultShader ) {
				mod->q3_shadowShader = 0;
			} else {
				mod->q3_shadowShader = sh->index;
			}
		}
		sscanf( shadowBits, "%f %f %f %f %f %f",
			&mod->q3_shadowParms[ 0 ], &mod->q3_shadowParms[ 1 ], &mod->q3_shadowParms[ 2 ],
			&mod->q3_shadowParms[ 3 ], &mod->q3_shadowParms[ 4 ], &mod->q3_shadowParms[ 5 ] );
	}
	FS_FreeFile( buf );
}
예제 #6
0
/*
===============
ShaderForShaderNum
===============
*/
static shader_t *ShaderForShaderNum( int shaderNum, const int *lightmapNum, const byte *lightmapStyles, const byte *vertexStyles ) {
    shader_t	*shader;
    dshader_t	*dsh;
    const byte	*styles;

    styles = lightmapStyles;

    shaderNum = LittleLong( shaderNum );
    if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {
        ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum );
    }
    dsh = &s_worldData.shaders[ shaderNum ];

    if (lightmapNum[0] == LIGHTMAP_BY_VERTEX)
    {
        styles = vertexStyles;
    }

    if ( r_vertexLight->integer )
    {
        lightmapNum = lightmapsVertex;
        styles = vertexStyles;
    }

    /*	if ( r_fullbright->integer )
    	{
    		lightmapNum = lightmapsFullBright;
    		styles = vertexStyles;
    	}
    */
    shader = R_FindShader( dsh->shader, lightmapNum, styles, qtrue );

    // if the shader had errors, just use default shader
    if ( shader->defaultShader ) {
        return tr.defaultShader;
    }

    return shader;
}
예제 #7
0
/*
=================
R_LoadIQM

Load an IQM model and compute the joint matrices for every frame.
=================
*/
qboolean R_LoadIQM(model_t* mod, void* buffer, int filesize, const char* mod_name) {
    iqmHeader_t*     header;
    iqmVertexArray_t*    vertexarray;
    iqmTriangle_t*       triangle;
    iqmMesh_t*       mesh;
    iqmJoint_t*      joint;
    iqmPose_t*       pose;
    iqmBounds_t*     bounds;
    unsigned short*      framedata;
    char*            str;
    int         i, j;
    float           jointMats[IQM_MAX_JOINTS * 2 * 12];
    float*           mat;
    size_t          size, joint_names;
    iqmData_t*       iqmData;
    srfIQModel_t*        surface;

    if (filesize < sizeof(iqmHeader_t)) {
        return qfalse;
    }

    header = (iqmHeader_t*)buffer;
    if (Q_strncmp(header->magic, IQM_MAGIC, sizeof(header->magic))) {
        return qfalse;
    }

    LL(header->version);
    if (header->version != IQM_VERSION) {
        ri.Printf(PRINT_WARNING, "R_LoadIQM: %s is a unsupported IQM version (%d), only version %d is supported.\n",
                  mod_name, header->version, IQM_VERSION);
        return qfalse;
    }

    LL(header->filesize);
    if (header->filesize > filesize || header->filesize > 16 << 20) {
        return qfalse;
    }

    LL(header->flags);
    LL(header->num_text);
    LL(header->ofs_text);
    LL(header->num_meshes);
    LL(header->ofs_meshes);
    LL(header->num_vertexarrays);
    LL(header->num_vertexes);
    LL(header->ofs_vertexarrays);
    LL(header->num_triangles);
    LL(header->ofs_triangles);
    LL(header->ofs_adjacency);
    LL(header->num_joints);
    LL(header->ofs_joints);
    LL(header->num_poses);
    LL(header->ofs_poses);
    LL(header->num_anims);
    LL(header->ofs_anims);
    LL(header->num_frames);
    LL(header->num_framechannels);
    LL(header->ofs_frames);
    LL(header->ofs_bounds);
    LL(header->num_comment);
    LL(header->ofs_comment);
    LL(header->num_extensions);
    LL(header->ofs_extensions);

    // check ioq3 joint limit
    if (header->num_joints > IQM_MAX_JOINTS) {
        ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %d joints (%d).\n",
                  mod_name, IQM_MAX_JOINTS, header->num_joints);
        return qfalse;
    }

    // check and swap vertex arrays
    if (IQM_CheckRange(header, header->ofs_vertexarrays,
                       header->num_vertexarrays,
                       sizeof(iqmVertexArray_t))) {
        return qfalse;
    }
    vertexarray = (iqmVertexArray_t*)((byte*)header + header->ofs_vertexarrays);
    for (i = 0; i < header->num_vertexarrays; i++, vertexarray++) {
        int j, n, *intPtr;

        if (vertexarray->size <= 0 || vertexarray->size > 4) {
            return qfalse;
        }

        // total number of values
        n = header->num_vertexes * vertexarray->size;

        switch (vertexarray->format) {
            case IQM_BYTE:
            case IQM_UBYTE:
                // 1 byte, no swapping necessary
                if (IQM_CheckRange(header, vertexarray->offset,
                                   n, sizeof(byte))) {
                    return qfalse;
                }
                break;
            case IQM_INT:
            case IQM_UINT:
            case IQM_FLOAT:
                // 4-byte swap
                if (IQM_CheckRange(header, vertexarray->offset,
                                   n, sizeof(float))) {
                    return qfalse;
                }
                intPtr = (int*)((byte*)header + vertexarray->offset);
                for (j = 0; j < n; j++, intPtr++) {
                    LL(*intPtr);
                }
                break;
            default:
                // not supported
                return qfalse;
                break;
        }

        switch (vertexarray->type) {
            case IQM_POSITION:
            case IQM_NORMAL:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 3) {
                    return qfalse;
                }
                break;
            case IQM_TANGENT:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
            case IQM_TEXCOORD:
                if (vertexarray->format != IQM_FLOAT ||
                        vertexarray->size != 2) {
                    return qfalse;
                }
                break;
            case IQM_BLENDINDEXES:
            case IQM_BLENDWEIGHTS:
                if (vertexarray->format != IQM_UBYTE ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
            case IQM_COLOR:
                if (vertexarray->format != IQM_UBYTE ||
                        vertexarray->size != 4) {
                    return qfalse;
                }
                break;
        }
    }

    // check and swap triangles
    if (IQM_CheckRange(header, header->ofs_triangles,
                       header->num_triangles, sizeof(iqmTriangle_t))) {
        return qfalse;
    }
    triangle = (iqmTriangle_t*)((byte*)header + header->ofs_triangles);
    for (i = 0; i < header->num_triangles; i++, triangle++) {
        LL(triangle->vertex[0]);
        LL(triangle->vertex[1]);
        LL(triangle->vertex[2]);

        if (triangle->vertex[0] > header->num_vertexes ||
                triangle->vertex[1] > header->num_vertexes ||
                triangle->vertex[2] > header->num_vertexes) {
            return qfalse;
        }
    }

    // check and swap meshes
    if (IQM_CheckRange(header, header->ofs_meshes,
                       header->num_meshes, sizeof(iqmMesh_t))) {
        return qfalse;
    }
    mesh = (iqmMesh_t*)((byte*)header + header->ofs_meshes);
    for (i = 0; i < header->num_meshes; i++, mesh++) {
        LL(mesh->name);
        LL(mesh->material);
        LL(mesh->first_vertex);
        LL(mesh->num_vertexes);
        LL(mesh->first_triangle);
        LL(mesh->num_triangles);

        // check ioq3 limits
        if (mesh->num_vertexes > SHADER_MAX_VERTEXES) {
            ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on a surface (%i).\n",
                      mod_name, SHADER_MAX_VERTEXES, mesh->num_vertexes);
            return qfalse;
        }
        if (mesh->num_triangles * 3 > SHADER_MAX_INDEXES) {
            ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on a surface (%i).\n",
                      mod_name, SHADER_MAX_INDEXES / 3, mesh->num_triangles);
            return qfalse;
        }

        if (mesh->first_vertex >= header->num_vertexes ||
                mesh->first_vertex + mesh->num_vertexes > header->num_vertexes ||
                mesh->first_triangle >= header->num_triangles ||
                mesh->first_triangle + mesh->num_triangles > header->num_triangles ||
                mesh->name >= header->num_text ||
                mesh->material >= header->num_text) {
            return qfalse;
        }
    }

    // check and swap joints
    if (IQM_CheckRange(header, header->ofs_joints,
                       header->num_joints, sizeof(iqmJoint_t))) {
        return qfalse;
    }
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    joint_names = 0;
    for (i = 0; i < header->num_joints; i++, joint++) {
        LL(joint->name);
        LL(joint->parent);
        LL(joint->translate[0]);
        LL(joint->translate[1]);
        LL(joint->translate[2]);
        LL(joint->rotate[0]);
        LL(joint->rotate[1]);
        LL(joint->rotate[2]);
        LL(joint->rotate[3]);
        LL(joint->scale[0]);
        LL(joint->scale[1]);
        LL(joint->scale[2]);

        if (joint->parent < -1 ||
                joint->parent >= (int)header->num_joints ||
                joint->name >= (int)header->num_text) {
            return qfalse;
        }
        joint_names += strlen((char*)header + header->ofs_text +
                              joint->name) + 1;
    }

    // check and swap poses
    if (header->num_poses != header->num_joints) {
        return qfalse;
    }
    if (IQM_CheckRange(header, header->ofs_poses,
                       header->num_poses, sizeof(iqmPose_t))) {
        return qfalse;
    }
    pose = (iqmPose_t*)((byte*)header + header->ofs_poses);
    for (i = 0; i < header->num_poses; i++, pose++) {
        LL(pose->parent);
        LL(pose->mask);
        LL(pose->channeloffset[0]);
        LL(pose->channeloffset[1]);
        LL(pose->channeloffset[2]);
        LL(pose->channeloffset[3]);
        LL(pose->channeloffset[4]);
        LL(pose->channeloffset[5]);
        LL(pose->channeloffset[6]);
        LL(pose->channeloffset[7]);
        LL(pose->channeloffset[8]);
        LL(pose->channeloffset[9]);
        LL(pose->channelscale[0]);
        LL(pose->channelscale[1]);
        LL(pose->channelscale[2]);
        LL(pose->channelscale[3]);
        LL(pose->channelscale[4]);
        LL(pose->channelscale[5]);
        LL(pose->channelscale[6]);
        LL(pose->channelscale[7]);
        LL(pose->channelscale[8]);
        LL(pose->channelscale[9]);
    }

    if (header->ofs_bounds) {
        // check and swap model bounds
        if (IQM_CheckRange(header, header->ofs_bounds,
                           header->num_frames, sizeof(*bounds))) {
            return qfalse;
        }
        bounds = (iqmBounds_t*)((byte*) header + header->ofs_bounds);
        for (i = 0; i < header->num_frames; i++) {
            LL(bounds->bbmin[0]);
            LL(bounds->bbmin[1]);
            LL(bounds->bbmin[2]);
            LL(bounds->bbmax[0]);
            LL(bounds->bbmax[1]);
            LL(bounds->bbmax[2]);

            bounds++;
        }
    }

    // allocate the model and copy the data
    size = sizeof(iqmData_t);
    size += header->num_meshes * sizeof(srfIQModel_t);
    size += header->num_joints * header->num_frames * 12 * sizeof(float);
    if (header->ofs_bounds)
        size += header->num_frames * 6 * sizeof(float); // model bounds
    size += header->num_vertexes * 3 * sizeof(float);   // positions
    size += header->num_vertexes * 2 * sizeof(float);   // texcoords
    size += header->num_vertexes * 3 * sizeof(float);   // normals
    size += header->num_vertexes * 4 * sizeof(float);   // tangents
    size += header->num_vertexes * 4 * sizeof(byte);    // blendIndexes
    size += header->num_vertexes * 4 * sizeof(byte);    // blendWeights
    size += header->num_vertexes * 4 * sizeof(byte);    // colors
    size += header->num_joints * sizeof(int);       // parents
    size += header->num_triangles * 3 * sizeof(int);    // triangles
    size += joint_names;                    // joint names

    mod->type = MOD_IQM;
    iqmData = (iqmData_t*)ri.Hunk_Alloc(size, h_low);
    mod->modelData = iqmData;

    // fill header
    iqmData->num_vertexes = header->num_vertexes;
    iqmData->num_triangles = header->num_triangles;
    iqmData->num_frames   = header->num_frames;
    iqmData->num_surfaces = header->num_meshes;
    iqmData->num_joints   = header->num_joints;
    iqmData->surfaces     = (srfIQModel_t*)(iqmData + 1);
    iqmData->poseMats     = (float*)(iqmData->surfaces + iqmData->num_surfaces);
    if (header->ofs_bounds) {
        iqmData->bounds       = iqmData->poseMats + 12 * header->num_joints * header->num_frames;
        iqmData->positions    = iqmData->bounds + 6 * header->num_frames;
    } else
        iqmData->positions    = iqmData->poseMats + 12 * header->num_joints * header->num_frames;
    iqmData->texcoords    = iqmData->positions + 3 * header->num_vertexes;
    iqmData->normals      = iqmData->texcoords + 2 * header->num_vertexes;
    iqmData->tangents     = iqmData->normals + 3 * header->num_vertexes;
    iqmData->blendIndexes = (byte*)(iqmData->tangents + 4 * header->num_vertexes);
    iqmData->blendWeights = iqmData->blendIndexes + 4 * header->num_vertexes;
    iqmData->colors       = iqmData->blendWeights + 4 * header->num_vertexes;
    iqmData->jointParents = (int*)(iqmData->colors + 4 * header->num_vertexes);
    iqmData->triangles    = iqmData->jointParents + header->num_joints;
    iqmData->names        = (char*)(iqmData->triangles + 3 * header->num_triangles);

    // calculate joint matrices and their inverses
    // they are needed only until the pose matrices are calculated
    mat = jointMats;
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        float baseFrame[12], invBaseFrame[12];

        JointToMatrix(joint->rotate, joint->scale, joint->translate, baseFrame);
        Matrix34Invert(baseFrame, invBaseFrame);

        if (joint->parent >= 0) {
            Matrix34Multiply(jointMats + 2 * 12 * joint->parent, baseFrame, mat);
            mat += 12;
            Matrix34Multiply(invBaseFrame, jointMats + 2 * 12 * joint->parent + 12, mat);
            mat += 12;
        } else {
            Com_Memcpy(mat, baseFrame,    sizeof(baseFrame));
            mat += 12;
            Com_Memcpy(mat, invBaseFrame, sizeof(invBaseFrame));
            mat += 12;
        }
    }

    // calculate pose matrices
    framedata = (unsigned short*)((byte*)header + header->ofs_frames);
    mat = iqmData->poseMats;
    for (i = 0; i < header->num_frames; i++) {
        pose = (iqmPose_t*)((byte*)header + header->ofs_poses);
        for (j = 0; j < header->num_poses; j++, pose++) {
            vec3_t  translate;
            vec4_t  rotate;
            vec3_t  scale;
            float   mat1[12], mat2[12];

            translate[0] = pose->channeloffset[0];
            if (pose->mask & 0x001)
                translate[0] += *framedata++ * pose->channelscale[0];
            translate[1] = pose->channeloffset[1];
            if (pose->mask & 0x002)
                translate[1] += *framedata++ * pose->channelscale[1];
            translate[2] = pose->channeloffset[2];
            if (pose->mask & 0x004)
                translate[2] += *framedata++ * pose->channelscale[2];

            rotate[0] = pose->channeloffset[3];
            if (pose->mask & 0x008)
                rotate[0] += *framedata++ * pose->channelscale[3];
            rotate[1] = pose->channeloffset[4];
            if (pose->mask & 0x010)
                rotate[1] += *framedata++ * pose->channelscale[4];
            rotate[2] = pose->channeloffset[5];
            if (pose->mask & 0x020)
                rotate[2] += *framedata++ * pose->channelscale[5];
            rotate[3] = pose->channeloffset[6];
            if (pose->mask & 0x040)
                rotate[3] += *framedata++ * pose->channelscale[6];

            scale[0] = pose->channeloffset[7];
            if (pose->mask & 0x080)
                scale[0] += *framedata++ * pose->channelscale[7];
            scale[1] = pose->channeloffset[8];
            if (pose->mask & 0x100)
                scale[1] += *framedata++ * pose->channelscale[8];
            scale[2] = pose->channeloffset[9];
            if (pose->mask & 0x200)
                scale[2] += *framedata++ * pose->channelscale[9];

            // construct transformation matrix
            JointToMatrix(rotate, scale, translate, mat1);

            if (pose->parent >= 0) {
                Matrix34Multiply(jointMats + 12 * 2 * pose->parent,
                                 mat1, mat2);
            } else {
                Com_Memcpy(mat2, mat1, sizeof(mat1));
            }

            Matrix34Multiply(mat2, jointMats + 12 * (2 * j + 1), mat);
            mat += 12;
        }
    }

    // register shaders
    // overwrite the material offset with the shader index
    mesh = (iqmMesh_t*)((byte*)header + header->ofs_meshes);
    surface = iqmData->surfaces;
    str = (char*)header + header->ofs_text;
    for (i = 0; i < header->num_meshes; i++, mesh++, surface++) {
        surface->surfaceType = SF_IQM;
        Q_strncpyz(surface->name, str + mesh->name, sizeof(surface->name));
        Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster
        surface->shader = R_FindShader(str + mesh->material, LIGHTMAP_NONE, qtrue);
        if (surface->shader->defaultShader)
            surface->shader = tr.defaultShader;
        surface->data = iqmData;
        surface->first_vertex = mesh->first_vertex;
        surface->num_vertexes = mesh->num_vertexes;
        surface->first_triangle = mesh->first_triangle;
        surface->num_triangles = mesh->num_triangles;
    }

    // copy vertexarrays and indexes
    vertexarray = (iqmVertexArray_t*)((byte*)header + header->ofs_vertexarrays);
    for (i = 0; i < header->num_vertexarrays; i++, vertexarray++) {
        int n;

        // total number of values
        n = header->num_vertexes * vertexarray->size;

        switch (vertexarray->type) {
            case IQM_POSITION:
                Com_Memcpy(iqmData->positions,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_NORMAL:
                Com_Memcpy(iqmData->normals,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_TANGENT:
                Com_Memcpy(iqmData->tangents,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_TEXCOORD:
                Com_Memcpy(iqmData->texcoords,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(float));
                break;
            case IQM_BLENDINDEXES:
                Com_Memcpy(iqmData->blendIndexes,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
            case IQM_BLENDWEIGHTS:
                Com_Memcpy(iqmData->blendWeights,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
            case IQM_COLOR:
                Com_Memcpy(iqmData->colors,
                           (byte*)header + vertexarray->offset,
                           n * sizeof(byte));
                break;
        }
    }

    // copy joint parents
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        iqmData->jointParents[i] = joint->parent;
    }

    // copy triangles
    triangle = (iqmTriangle_t*)((byte*)header + header->ofs_triangles);
    for (i = 0; i < header->num_triangles; i++, triangle++) {
        iqmData->triangles[3 * i + 0] = triangle->vertex[0];
        iqmData->triangles[3 * i + 1] = triangle->vertex[1];
        iqmData->triangles[3 * i + 2] = triangle->vertex[2];
    }

    // copy joint names
    str = iqmData->names;
    joint = (iqmJoint_t*)((byte*)header + header->ofs_joints);
    for (i = 0; i < header->num_joints; i++, joint++) {
        char* name = (char*)header + header->ofs_text +
                     joint->name;
        int len = strlen(name) + 1;
        Com_Memcpy(str, name, len);
        str += len;
    }

    // copy model bounds
    if (header->ofs_bounds) {
        mat = iqmData->bounds;
        bounds = (iqmBounds_t*)((byte*) header + header->ofs_bounds);
        for (i = 0; i < header->num_frames; i++) {
            mat[0] = bounds->bbmin[0];
            mat[1] = bounds->bbmin[1];
            mat[2] = bounds->bbmin[2];
            mat[3] = bounds->bbmax[0];
            mat[4] = bounds->bbmax[1];
            mat[5] = bounds->bbmax[2];

            mat += 6;
            bounds++;
        }
    }

    return qtrue;
}
예제 #8
0
qboolean R_LoadGLM( model_t *mod, void *buffer, int filesize, const char *mod_name ) {
	int					i, j, lodindex, surfindex;
	glmHeader_t		*header, *glm;
	glmLOD_t			*lod;
	glmLODSurfOffset_t	*lod_surf_ofs;
	glmSurfHierarchy_t	*surfh;
	glmVertexTexCoord_t *vcor;
	glmSurface_t		*surf;
	glmTriangle_t		*tri;
	glmVertex_t		*v;
	int					version;
	int					size;
	shader_t			*sh;
	vec3_t				tempVert;
	vec3_t				tempNorm;
	//int					frameSize;

	float zrots[3][4];
	qboolean do_zrot = qfalse;
	zrots[0][0] = 0.0;
	zrots[0][1] = -1.0;
	zrots[0][2] = 0.0;
	zrots[0][3] = 0.0;
	zrots[1][0] = 1.0;
	zrots[1][1] = 0.0;
	zrots[1][2] = 0.0;
	zrots[1][3] = 0.0;
	zrots[2][0] = 0.0;
	zrots[2][1] = 0.0;
	zrots[2][2] = 1.0;
	zrots[2][3] = 0.0;

	if( filesize < sizeof( glmHeader_t ) ) {
		return qfalse;
	}

	header = (glmHeader_t *)buffer;

	version = LittleLong( header->version );

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

	size = LittleLong( header->ofsEnd );

	if( size > filesize ) {
		ri.Printf( PRINT_WARNING, "R_LoadGLM: Header of %s is broken. Wrong filesize declared!\n", mod_name );
		return qfalse;
	}

	mod->type = MOD_GLM;
	size = LittleLong(header->ofsEnd);
	mod->dataSize += size;
	//ri.Printf( PRINT_WARNING, "R_LoadGLM: %s alloc %d\n", mod_name, size );
	mod->modelData = ri.Hunk_Alloc( size, h_low );
	glm = (glmHeader_t *)mod->modelData;

	Com_Memcpy( glm, buffer, size );

	LL( glm->ident );
	LL( glm->animIndex );
	LL( glm->numBones );
	LL( glm->numLODs );
	LL( glm->ofsLODs );
	LL( glm->numSurfaces );
	LL( glm->ofsSurfHierarchy );

	if ( GLM_CheckRange( glm, glm->ofsSurfHierarchy, glm->numSurfaces, sizeof( glmSurfHierarchy_t ) ) ) {
		return qfalse;
	}

	// swap the surf Hierarchy!
	surfh = (glmSurfHierarchy_t *) ( (byte *)glm + glm->ofsSurfHierarchy );
	for( surfindex = 0; surfindex < glm->numSurfaces; surfindex++ )
	{
		Q_strlwr( surfh->name );
		LL(surfh->flags);
		Q_strlwr( surfh->shader );
		
		//ri.Printf( PRINT_ALL, "surf %d, name '%s' shader '%s'\n", surfindex, surfh->name, surfh->shader );
		
		sh = R_FindShader( surfh->shader, LIGHTMAP_NONE, qtrue );
		if ( sh->defaultShader ) {
			surfh->shaderIndex = 0;
		} else {
			LL(surfh->shaderIndex);
			surfh->shaderIndex = sh->index;
		}
		
		LL(surfh->parentIndex);
		LL(surfh->numChildren);
		for( i = 0; i < surfh->numChildren; i++ ) {
			LL(surfh->childIndexes[i]);
		}
		surfh = (glmSurfHierarchy_t *) ( (byte *)&surfh->childIndexes[surfh->numChildren] );
	}

	if ( GLM_CheckRange( glm, glm->ofsLODs, glm->numLODs, sizeof( glmLOD_t ) ) ) {
		return qfalse;
	}

	// swap all the LOD's
	lod = (glmLOD_t *) ( (byte *)glm + glm->ofsLODs );
	LL( lod->ofsEnd );
	//ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name);
	//ri.Printf (PRINT_WARNING,"lod ofsEnd is 0x%08x\n", lod->ofsEnd );
	for ( lodindex = 0 ; lodindex < glm->numLODs ; lodindex++ )
	{
		lod_surf_ofs = ( glmLODSurfOffset_t *) ((byte *)lod + 4 );
		for( i = 0; i < glm->numSurfaces; i++ )
		{
			LL(lod_surf_ofs->offsets[i]);
			//lod_surf_ofs->offsets[i] += 4;
			//printf( "lod %d surf ofs %d is 0x%08x\n", lodindex, lod_surf_ofs->offsets[i] );
		}
		
		// swap all the surfaces
		for ( i = 0 ; i < glm->numSurfaces ; i++) {
			surf = (glmSurface_t *) ( (byte *)lod_surf_ofs + lod_surf_ofs->offsets[i] );
			LL(surf->ident);
			LL(surf->thisSurfaceIndex);
			LL(surf->ofsHeader);
			LL(surf->numVerts);
			LL(surf->ofsVerts);
			LL(surf->numTriangles);
			LL(surf->ofsTriangles);
			LL(surf->numBoneReferences);
			LL(surf->ofsBoneReferences);
			LL(surf->ofsEnd);
			if(0) ri.Printf( PRINT_ALL, "surf %d, ident %d, index %d, numverts %d, numtris %d, num bone refs %d\n", i, surf->ident, surf->thisSurfaceIndex, surf->numVerts, surf->numTriangles, surf->numBoneReferences );
			
			// change to surface identifier
			surf->ident = SF_GLM;
			
			tri = (glmTriangle_t *) ( (byte *)surf + surf->ofsBoneReferences );
			for( j=0; j<surf->numBoneReferences; j++ )
			{
				LL(tri->indexes[j]);
				if(0) ri.Printf( PRINT_ALL, "j is %d\n", j );
				if(0) ri.Printf( PRINT_ALL, "surf %d, boneref %d is %d\n", i, j, tri->indexes[j] );
			}
			
			if(0) ri.Printf( PRINT_ALL, "swap the triangles!\n" );

			// swap all the triangles
			tri = (glmTriangle_t *) ( (byte *)surf + surf->ofsTriangles );
			for ( j = 0 ; j < surf->numTriangles ; j++ ) {
				LL(tri->indexes[0]);
				LL(tri->indexes[1]);
				LL(tri->indexes[2]);
				tri = (glmTriangle_t *)((byte *)tri + 12 );
			}
			
			
			v = (glmVertex_t *) ( (byte *)surf + surf->ofsVerts);
			for ( j = 0 ; j < surf->numVerts ; j++ )
			{
				v->normal[0] = LittleFloat( v->normal[0] );
				v->normal[1] = LittleFloat( v->normal[1] );
				v->normal[2] = LittleFloat( v->normal[2] );
				v->vertCoords[0] = LittleFloat( v->vertCoords[0] );
				v->vertCoords[1] = LittleFloat( v->vertCoords[1] );
				v->vertCoords[2] = LittleFloat( v->vertCoords[2] );
				
				if( do_zrot )
				{
					VectorCopy( v->normal, tempNorm );
					VectorCopy( v->vertCoords, tempVert );
					Matrix34VectorRotate( zrots, tempVert, v->vertCoords );
					Matrix34VectorRotate( zrots, tempNorm, v->normal );
				}
				
				LL(v->uiNmWeightsAndBoneIndexes);
				//v->texCoords[0] = LittleFloat( v->texCoords[0] );
				//v->texCoords[1] = LittleFloat( v->texCoords[1] );
				/*
				v->numWeights = LittleLong( v->numWeights );

				for ( k = 0 ; k < v->numWeights ; k++ ) {
					v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
					v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
				   v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
				   v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
				   v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
				}
				*/
				v = (glmVertex_t *)( ( byte *)v + 32 );
			}
			vcor = (glmVertexTexCoord_t *)( ( byte *)v );
			for ( j = 0 ; j < surf->numVerts ; j++ )
			{
				vcor->texCoords[0] = LittleFloat( vcor->texCoords[0] );
				vcor->texCoords[1] = LittleFloat( vcor->texCoords[1] );
				vcor = (glmVertexTexCoord_t *)( ( byte *)vcor + 8 );
			}
		}
		lod = (glmLOD_t *)( (byte *)lod + lod->ofsEnd );
	}

	glm->animIndex = 0;
	if(0) ri.Printf( PRINT_DEVELOPER, "glm (%s) animname is '%s'\n", mod_name, glm->animName );
	if( Q_strncmp( glm->animName, sDEFAULT_GLA_NAME, strlen(sDEFAULT_GLA_NAME) ) ) //if there's a difference
	{
		Q_strcat( glm->animName, MAX_QPATH, ".gla" );
		//Com_DPrintf ( "glm: trying to load animfile: '%s'\n", glm->animName );
		//ri.Printf( PRINT_ALL, "glm: trying to load animfile: '%s'\n", glm->animName );
		glm->animIndex = RE_RegisterModel( glm->animName );
	}
	else
	{
		glm->animIndex = 0;
	}

	return qtrue;
}
예제 #9
0
파일: tr_cmds.c 프로젝트: entdark/q3mme
/*
====================
RE_BeginFrame

If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
	drawBufferCommand_t	*cmd;

	if ( !tr.registered ) {
		return;
	}

	glState.finishCalled = qfalse;

	tr.frameCount++;
	tr.frameSceneNum = 0;
	backEnd.traceShader = tr.traceShader;
	backEnd.doneBloom = qfalse;
	backEnd.doneSurfaces = qfalse;
	backEnd.sceneZfar = 2048;
	tr.traceShader = qfalse;

	//
	// do overdraw measurement
	//
	if ( r_measureOverdraw->integer )
	{
		if ( glConfig.stencilBits < 4 )
		{
			ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		}
		else if ( r_shadows->integer == 2 )
		{
			ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		}
		else if ( mme_saveStencil->integer )
		{
			ri.Printf( PRINT_ALL, "Warning: mme stencil masks and overdraw measurement are mutually exclusive\n" );
			ri.Cvar_Set( "r_measureOverdraw", "0" );
			r_measureOverdraw->modified = qfalse;
		}
		else
		{
			R_SyncRenderThread();
			qglEnable( GL_STENCIL_TEST );
			qglStencilMask( ~0U );
			qglClearStencil( 0U );
			qglStencilFunc( GL_ALWAYS, 0U, ~0U );
			qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
		}
		r_measureOverdraw->modified = qfalse;
	}
	else
	{
		// this is only reached if it was on and is now off
		if ( r_measureOverdraw->modified ) {
			R_SyncRenderThread();
			qglDisable( GL_STENCIL_TEST );
		}
		r_measureOverdraw->modified = qfalse;
	}

	if ( mme_saveStencil->integer == 1 ) {
		R_SyncRenderThread();
		qglEnable( GL_STENCIL_TEST );
		qglStencilMask( ~0U );
		qglClearStencil( 0U );
		qglStencilFunc( GL_ALWAYS, 255U, 255U );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
		backEnd.doingStencil = qfalse;
	} else if ( mme_saveStencil->integer == 2 ) {
		R_SyncRenderThread();
		qglEnable( GL_STENCIL_TEST );
		qglStencilMask( ~0U );
		qglClearStencil( 0U );
		qglStencilFunc( GL_ALWAYS, 255U, 255U );
		qglStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
		backEnd.doingStencil = qfalse;
	} else {
		qglDisable( GL_STENCIL_TEST );
	}

	//
	// texturemode stuff
	//
	if ( r_textureMode->modified ) {
		R_SyncRenderThread();
		GL_TextureMode( r_textureMode->string );
		r_textureMode->modified = qfalse;
	}

	if ( r_anisotropy->modified ) {
		R_SyncRenderThread();
		GL_Anisotropy( r_anisotropy->integer );
		r_anisotropy->modified = qfalse;
	}
	//
	// gamma stuff
	//
	if ( r_gamma->modified ) {
		r_gamma->modified = qfalse;

		R_SyncRenderThread();
		R_SetColorMappings();
	}

    // check for errors
    if ( !r_ignoreGLErrors->integer ) {
        int	err;

		R_SyncRenderThread();
        if ( ( err = qglGetError() ) != GL_NO_ERROR ) {
            ri.Error( ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!\n", err );
        }
    }

	if ( mme_worldShader->modified) {
		if (R_FindShaderText( mme_worldShader->string )) {
			tr.mmeWorldShader = R_FindShader( mme_worldShader->string, LIGHTMAP_NONE, qtrue );
		} else {
			tr.mmeWorldShader = 0;
		}
		mme_worldShader->modified = qfalse;
	}

	if ( mme_pip->integer ) {
		tr.mmeWorldShader = R_FindShader( "mme/pip", -1, qtrue );
	}

	//
	// draw buffer stuff
	//
	cmd = R_GetCommandBuffer( RC_DRAW_BUFFER, sizeof( *cmd ) );
	if ( !cmd ) {
		return;
	}

	if ( glConfig.stereoEnabled ) {
		if ( stereoFrame == STEREO_LEFT ) {
			cmd->buffer = (int)GL_BACK_LEFT;
		} else if ( stereoFrame == STEREO_RIGHT ) {
			cmd->buffer = (int)GL_BACK_RIGHT;
		} else {
			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
		}
	} else {
		if ( stereoFrame != STEREO_CENTER ) {
			ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
		}
		if ( !Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) ) {
			cmd->buffer = (int)GL_FRONT;
		} else {
			cmd->buffer = (int)GL_BACK;
		}
	}
}
예제 #10
0
파일: tr_skin.cpp 프로젝트: Razish/CompJA
// given a name, go get the skin we want and return
qhandle_t RE_RegisterIndividualSkin( const char *name , qhandle_t hSkin)
{
    skin_t			*skin;
    skinSurface_t	*surf;
    char			*text, *text_p;
    char			*token;
    char			surfName[MAX_QPATH];

    // load and parse the skin file
    ri->FS_ReadFile( name, (void **)&text );
    if ( !text ) {
#ifndef FINAL_BUILD
        Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) failed to load!\n", name );
#endif
        return 0;
    }

    assert (tr.skins[hSkin]);	//should already be setup, but might be an 3part append

    skin = tr.skins[hSkin];

    text_p = text;
    while ( text_p && *text_p ) {
        // get surface name
        token = CommaParse( &text_p );
        Q_strncpyz( surfName, token, sizeof( surfName ) );

        if ( !token[0] ) {
            break;
        }
        // lowercase the surface name so skin compares are faster
        Q_strlwr( surfName );

        if ( *text_p == ',' ) {
            text_p++;
        }

        if ( !strncmp( token, "tag_", 4 ) ) {	//these aren't in there, but just in case you load an id style one...
            continue;
        }

        // parse the shader name
        token = CommaParse( &text_p );

        if ( !strcmp( &surfName[strlen(surfName)-4], "_off") )
        {
            if ( !strcmp( token ,"*off" ) )
            {
                continue;	//don't need these double offs
            }
            surfName[strlen(surfName)-4] = 0;	//remove the "_off"
        }
        if ( (unsigned)skin->numSurfaces >= ARRAY_LEN( skin->surfaces ) )
        {
            assert( ARRAY_LEN( skin->surfaces ) > (unsigned)skin->numSurfaces );
            Com_Printf( "WARNING: RE_RegisterSkin( '%s' ) more than %d surfaces!\n", name, ARRAY_LEN( skin->surfaces ) );
            break;
        }
        surf = (skinSurface_t *) Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
        skin->surfaces[skin->numSurfaces] = (_skinSurface_t *)surf;

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

        if (gServerSkinHack)	surf->shader = R_FindServerShader( token, lightmapsNone, stylesDefault, qtrue );
        else					surf->shader = R_FindShader( token, lightmapsNone, stylesDefault, qtrue );
        skin->numSurfaces++;
    }

    ri->FS_FreeFile( text );


    // never let a skin have 0 shaders
    if ( skin->numSurfaces == 0 ) {
        return 0;		// use default skin
    }

    return hSkin;
}
예제 #11
0
/*
=================
R_LoadMD5
=================
*/
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;
	md5Triangle_t *tri;
	md5Vertex_t   *v;
	md5Weight_t   *weight;
	int           version;
	shader_t      *sh;
	char          *buf_p;
	char          *token;
	vec3_t        boneOrigin;
	quat_t        boneQuat;
	matrix_t      boneMat;

	buf_p = ( char * ) buffer;

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

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

	if ( version != MD5_VERSION )
	{
		ri.Printf( PRINT_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->model.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 );
//  ri.Printf(PRINT_ALL, "%s\n", token);

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

	if ( Q_stricmp( token, "numJoints" ) )
	{
		ri.Printf( PRINT_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" ) )
	{
		ri.Printf( PRINT_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 );
	//ri.Printf(PRINT_ALL, "R_LoadMD5: '%s' has %i surfaces\n", modName, md5->numSurfaces);

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

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

	//ri.Printf(PRINT_ALL, "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" ) )
	{
		ri.Printf( PRINT_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, "{" ) )
	{
		ri.Printf( PRINT_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 ) );

		//ri.Printf(PRINT_ALL, "R_LoadMD5: '%s' has bone '%s'\n", modName, bone->name);

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

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

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

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

		if ( Q_stricmp( token, "(" ) )
		{
			ri.Printf( PRINT_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, ")" ) )
		{
			ri.Printf( PRINT_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, "(" ) )
		{
			ri.Printf( PRINT_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, ")" ) )
		{
			ri.Printf( PRINT_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, "}" ) )
	{
		ri.Printf( PRINT_WARNING, "R_LoadMD5: expected '}' found '%s' in model '%s'\n", token, modName );
		return qfalse;
	}

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

	//ri.Printf(PRINT_ALL, "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" ) )
		{
			ri.Printf( PRINT_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, "{" ) )
		{
			ri.Printf( PRINT_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" ) )
		{
			Q_strncpyz( surf->shader, "<default>", sizeof( surf->shader ) );
			surf->shaderIndex = 0;
		}
		else
		{
			token = COM_ParseExt2( &buf_p, qfalse );
			Q_strncpyz( surf->shader, token, sizeof( surf->shader ) );

			//ri.Printf(PRINT_ALL, "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);
			//ri.Printf(PRINT_ALL, "R_LoadMD5: '%s' has surface '%s'\n", modName, surf->name);

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

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

			token = COM_ParseExt2( &buf_p, qtrue );
		}

		// parse numVerts <number>
		if ( Q_stricmp( token, "numVerts" ) )
		{
			ri.Printf( PRINT_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 )
		{
			ri.Error( ERR_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" ) )
			{
				ri.Printf( PRINT_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, "(" ) )
			{
				ri.Printf( PRINT_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, ")" ) )
			{
				ri.Printf( PRINT_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 )
			{
				ri.Error( ERR_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" ) )
		{
			ri.Printf( PRINT_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 )
		{
			ri.Error( ERR_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" ) )
			{
				ri.Printf( PRINT_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" ) )
		{
			ri.Printf( PRINT_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" ) )
			{
				ri.Printf( PRINT_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, "(" ) )
			{
				ri.Printf( PRINT_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, ")" ) )
			{
				ri.Printf( PRINT_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, "}" ) )
		{
			ri.Printf( PRINT_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 normals
		{
			const float *v0, *v1, *v2;
			const float *t0, *t1, *t2;
			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;

				R_CalcNormalForTriangle( normal, v0, v1, v2 );

				for ( k = 0; k < 3; k++ )
				{
					float *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->normal );
			}
		}

#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
	}

	return qtrue;
}
예제 #12
0
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean bAlreadyCached ) {
	int					i, j;
	md3Header_t			*pinmodel;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	int					version;
	int					size;

#ifndef _M_IX86
	md3Frame_t			*frame;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
#endif


	pinmodel= (md3Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//
	version = pinmodel->version;
	size	= pinmodel->ofsEnd;

	if (!bAlreadyCached)
	{
		version = LittleLong(version);
		size	= LittleLong(size);
	}
	
	if (version != MD3_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type      = MOD_MESH;	
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	mod->md3[lod] = (md3Header_t *) //ri.Hunk_Alloc( size );
										RE_RegisterModels_Malloc(size, mod_name, &bAlreadyFound, TAG_MODEL_MD3);

	assert(bAlreadyCached == bAlreadyFound);	// I should probably eliminate 'bAlreadyFound', but wtf?

	if (!bAlreadyFound)
	{	
		memcpy (mod->md3[lod], buffer, size );

		LL(mod->md3[lod]->ident);
		LL(mod->md3[lod]->version);
		LL(mod->md3[lod]->numFrames);
		LL(mod->md3[lod]->numTags);
		LL(mod->md3[lod]->numSurfaces);
		LL(mod->md3[lod]->ofsFrames);
		LL(mod->md3[lod]->ofsTags);
		LL(mod->md3[lod]->ofsSurfaces);
		LL(mod->md3[lod]->ofsEnd);
	}

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not pass Go...
	}

#ifndef _M_IX86
	//
	// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
	//

	// swap all the frames
    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
    	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] );
        }
	}

	// swap all the tags
    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
        for ( j = 0 ; j < 3 ; j++ ) {
			tag->origin[j] = LittleFloat( tag->origin[j] );
			tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
			tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
			tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
        }
	}
#endif

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);
		
		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}
	
		// change to surface identifier
		surf->ident = SF_MD3;

		// 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
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, lightmapsNone, stylesDefault, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
			RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex);
        }


#ifndef _M_IX86
//
// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
//

		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
            st->st[0] = LittleFloat( st->st[0] );
            st->st[1] = LittleFloat( st->st[1] );
        }

		// swap all the XyzNormals
        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) 
		{
            xyz->xyz[0] = LittleShort( xyz->xyz[0] );
            xyz->xyz[1] = LittleShort( xyz->xyz[1] );
            xyz->xyz[2] = LittleShort( xyz->xyz[2] );

            xyz->normal = LittleShort( xyz->normal );
        }
#endif

		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}
    
	return qtrue;
}
예제 #13
0
void R_RMGInit(void)
{
	char			newSky[MAX_QPATH];
	char			newFog[MAX_QPATH];
	shader_t		*fog;
	fog_t			*gfog;
	mgrid_t			*grid;
	char			temp[MAX_QPATH];
	int				i;
	unsigned short	*pos;

	ri.Cvar_VariableStringBuffer("RMG_sky", newSky, MAX_QPATH);
	// Get sunlight - this should set up all the sunlight data
	R_FindShader( newSky, lightmapsNone, stylesDefault, qfalse );

	// Remap sky
	R_RemapShader("textures/tools/_sky", newSky, NULL);

	// Fill in the lightgrid with sunlight
	if(tr.world->lightGridData)
	{
		grid = tr.world->lightGridData;
		grid->ambientLight[0][0] = (byte)Com_Clampi(0, 255, tr.sunAmbient[0] * 255.0f);
		grid->ambientLight[0][1] = (byte)Com_Clampi(0, 255, tr.sunAmbient[1] * 255.0f);
		grid->ambientLight[0][2] = (byte)Com_Clampi(0, 255, tr.sunAmbient[2] * 255.0f);
		R_ColorShiftLightingBytes(grid->ambientLight[0], grid->ambientLight[0]);

		grid->directLight[0][0] = (byte)Com_Clampi(0, 255, tr.sunLight[0]);
		grid->directLight[0][1] = (byte)Com_Clampi(0, 255, tr.sunLight[1]);
		grid->directLight[0][2] = (byte)Com_Clampi(0, 255, tr.sunLight[2]);
		R_ColorShiftLightingBytes(grid->directLight[0], grid->directLight[0]);

		NormalToLatLong(tr.sunDirection, grid->latLong);

		pos = tr.world->lightGridArray;
		for(i=0;i<tr.world->numGridArrayElements;i++)
		{
			*pos = 0;
			pos++;
		}
	}

	// Override the global fog with the defined one
	if(tr.world->globalFog != -1)
	{
		ri.Cvar_VariableStringBuffer("RMG_fog", newFog, MAX_QPATH);
		fog = R_FindShader( newFog, lightmapsNone, stylesDefault, qfalse);
		if (fog != tr.defaultShader)
		{
			gfog = tr.world->fogs + tr.world->globalFog;
			gfog->parms = *fog->fogParms;
			if (gfog->parms.depthForOpaque)
			{
				gfog->tcScale = 1.0f / ( gfog->parms.depthForOpaque * 8.0f );
				tr.distanceCull = gfog->parms.depthForOpaque;
				tr.distanceCullSquared = tr.distanceCull * tr.distanceCull;
				ri.Cvar_Set("RMG_distancecull", va("%f", tr.distanceCull));
			}
			else
			{
				gfog->tcScale = 1.0f;
			}
			gfog->colorInt = ColorBytes4 ( gfog->parms.color[0], 
										  gfog->parms.color[1], 
										  gfog->parms.color[2], 1.0f );
		}
	}

	ri.Cvar_VariableStringBuffer("RMG_weather", temp, MAX_QPATH);

	// Set up any weather effects
	switch(atol(temp))
	{
	case 0:
		break;
	case 1:
		RE_WorldEffectCommand("rain init 1000");
		RE_WorldEffectCommand("rain outside");
		break;
	case 2:
		RE_WorldEffectCommand("snow init 1000 outside");
		RE_WorldEffectCommand("snow outside");
		break;
	}
}
예제 #14
0
파일: tr_model.cpp 프로젝트: Avygeil/NewJK
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean &bAlreadyCached ) {
	int					i, j;
	md3Header_t			*pinmodel;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	int					version;
	int					size;

#ifdef Q3_BIG_ENDIAN
	md3Frame_t			*frame;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
#endif


	pinmodel= (md3Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//
	version = pinmodel->version;
	size	= pinmodel->ofsEnd;

	if (!bAlreadyCached)
	{
		version = LittleLong(version);
		size	= LittleLong(size);
	}

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

	mod->type      = MOD_MESH;
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	mod->md3[lod] = (md3Header_t *) RE_RegisterModels_Malloc(size, buffer, mod_name, &bAlreadyFound, TAG_MODEL_MD3);

	assert(bAlreadyCached == bAlreadyFound);

	if (!bAlreadyFound)
	{
		// horrible new hackery, if !bAlreadyFound then we've just done a tag-morph, so we need to set the
		//	bool reference passed into this function to true, to tell the caller NOT to do an FS_Freefile since
		//	we've hijacked that memory block...
		//
		// Aaaargh. Kill me now...
		//
		bAlreadyCached = qtrue;
		assert( mod->md3[lod] == buffer );
//		memcpy( mod->md3[lod], buffer, size );	// and don't do this now, since it's the same thing

		LL(mod->md3[lod]->ident);
		LL(mod->md3[lod]->version);
		LL(mod->md3[lod]->numFrames);
		LL(mod->md3[lod]->numTags);
		LL(mod->md3[lod]->numSurfaces);
		LL(mod->md3[lod]->ofsFrames);
		LL(mod->md3[lod]->ofsTags);
		LL(mod->md3[lod]->ofsSurfaces);
		LL(mod->md3[lod]->ofsEnd);
	}

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not pass Go...
	}

#ifdef Q3_BIG_ENDIAN
	// swap all the frames
	frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
	for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
		LF(frame->radius);
		for ( j = 0 ; j < 3 ; j++ ) {
			LF(frame->bounds[0][j]);
			LF(frame->bounds[1][j]);
			LF(frame->localOrigin[j]);
		}
	}

	// swap all the tags
	tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
	for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
		for ( j = 0 ; j < 3 ; j++ ) {
			LF(tag->origin[j]);
			LF(tag->axis[0][j]);
			LF(tag->axis[1][j]);
			LF(tag->axis[2][j]);
		}
	}
#endif

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);

		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}

		// change to surface identifier
		surf->ident = SF_MD3;

		// 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
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, lightmapsNone, stylesDefault, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
			RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex);
        }


#ifdef Q3_BIG_ENDIAN
		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
		st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
		for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
			LF(st->st[0]);
			LF(st->st[1]);
		}

		// swap all the XyzNormals
		xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
		for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
		{
			LS(xyz->xyz[0]);
			LS(xyz->xyz[1]);
			LS(xyz->xyz[2]);

			LS(xyz->normal);
		}
#endif

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

	return qtrue;
}
예제 #15
0
/*
==============
RE_GetShaderFromModel
        return a shader index for a given model's surface
        'withlightmap' set to '0' will create a new shader that is a copy of the one found
        on the model, without the lighmap stage, if the shader has a lightmap stage

        NOTE: only works for bmodels right now.  Could modify for other models (md3's etc.)
==============
*/
qhandle_t RE_GetShaderFromModel( qhandle_t modelid, int surfnum, int withlightmap )
{
	model_t    *model;
	bmodel_t   *bmodel;
	msurface_t *surf;
	shader_t   *shd;

	if ( surfnum < 0 )
	{
		surfnum = 0;
	}

	model = R_GetModelByHandle( modelid );  // (SA) should be correct now

	if ( model )
	{
		bmodel = model->model.bmodel;

		if ( bmodel && bmodel->firstSurface )
		{
			if ( surfnum >= bmodel->numSurfaces )
			{
				// if it's out of range, return the first surface
				surfnum = 0;
			}

			surf = bmodel->firstSurface + surfnum;

			// RF, check for null shader (can happen on func_explosive entities with botclips attached)
			if ( !surf->shader )
			{
				return 0;
			}

//          if(surf->shader->lightmapIndex != LIGHTMAP_NONE) {
			if ( surf->shader->lightmapIndex > LIGHTMAP_NONE )
			{
				image_t  *image;
				long     hash;
				qboolean mip = qtrue; // mip generation on by default

				// get mipmap info for original texture
				hash = GenerateImageHashValue( surf->shader->name );

				for ( image = r_imageHashTable[ hash ]; image; image = image->next )
				{
					if ( !strcmp( surf->shader->name, image->imgName ) )
					{
						mip = image->mipmap;
						break;
					}
				}

				shd = R_FindShader( surf->shader->name, LIGHTMAP_NONE, mip );
				shd->stages[ 0 ]->rgbGen = CGEN_LIGHTING_DIFFUSE; // (SA) new
			}
			else
			{
				shd = surf->shader;
			}

			return shd->index;
		}
	}

	return 0;
}
예제 #16
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;
}
예제 #17
0
/*
=================
R_LoadIQModel

Load an IQM model and compute the joint matrices for every frame.
=================
*/
bool R_LoadIQModel( model_t *mod, void *buffer, int filesize,
			const char *mod_name ) {
	iqmHeader_t		*header;
	iqmVertexArray_t	*vertexarray;
	iqmTriangle_t		*triangle;
	iqmMesh_t		*mesh;
	iqmJoint_t		*joint;
	iqmPose_t		*pose;
	iqmAnim_t		*anim;
	unsigned short		*framedata;
	char			*str, *name;
	int		len;
	transform_t		*trans, *poses;
	float			*bounds;
	size_t			size, len_names;
	IQModel_t		*IQModel;
	IQAnim_t		*IQAnim;
	srfIQModel_t		*surface;
	vboData_t               vboData;
	float                   *weightbuf;
	int                     *indexbuf;
	i16vec4_t               *qtangentbuf;
	VBO_t                   *vbo;
	IBO_t                   *ibo;
	void                    *ptr;
	u8vec4_t                *weights;

	if( !LoadIQMFile( buffer, filesize, mod_name, &len_names ) ) {
		return false;
	}

	header = (iqmHeader_t *)buffer;

	// compute required space
	size = sizeof(IQModel_t);
	size += header->num_meshes * sizeof( srfIQModel_t );
	size += header->num_anims * sizeof( IQAnim_t );
	size += header->num_joints * sizeof( transform_t );
	size = PAD( size, 16 );
	size += header->num_joints * header->num_frames * sizeof( transform_t );
	if(header->ofs_bounds)
		size += header->num_frames * 6 * sizeof(float);	// model bounds
	size += header->num_vertexes * 3 * sizeof(float);	// positions
	size += header->num_vertexes * 3 * sizeof(float);	// normals
	size += header->num_vertexes * 3 * sizeof(float);	// tangents
	size += header->num_vertexes * 3 * sizeof(float);	// bitangents
	size += header->num_vertexes * 2 * sizeof(int16_t);	// texcoords
	size += header->num_vertexes * 4 * sizeof(byte);	// blendIndexes
	size += header->num_vertexes * 4 * sizeof(byte);	// blendWeights
	size += header->num_vertexes * 4 * sizeof(byte);	// colors
	size += header->num_triangles * 3 * sizeof(int);	// triangles
	size += header->num_joints * sizeof(int);		// parents
	size += len_names;					// joint and anim names

	IQModel = (IQModel_t *)ri.Hunk_Alloc( size, ha_pref::h_low );
	mod->type = modtype_t::MOD_IQM;
	mod->iqm = IQModel;
	ptr = IQModel + 1;

	// fill header and setup pointers
	IQModel->num_vertexes = header->num_vertexes;
	IQModel->num_triangles = header->num_triangles;
	IQModel->num_frames   = header->num_frames;
	IQModel->num_surfaces = header->num_meshes;
	IQModel->num_joints   = header->num_joints;
	IQModel->num_anims    = header->num_anims;

	IQModel->surfaces = (srfIQModel_t *)ptr;
	ptr = IQModel->surfaces + header->num_meshes;

	if( header->ofs_anims ) {
		IQModel->anims = (IQAnim_t *)ptr;
		ptr = IQModel->anims + header->num_anims;
	} else {
		IQModel->anims = nullptr;
	}

	IQModel->joints = (transform_t *)PADP(ptr, 16);
	ptr = IQModel->joints + header->num_joints;

	if( header->ofs_poses ) {
		poses = (transform_t *)ptr;
		ptr = poses + header->num_poses * header->num_frames;
	} else {
		poses = nullptr;
	}

	if( header->ofs_bounds ) {
		bounds = (float *)ptr;
		ptr = bounds + 6 * header->num_frames;
	} else {
		bounds = nullptr;
	}

	IQModel->positions = (float *)ptr;
	ptr = IQModel->positions + 3 * header->num_vertexes;

	IQModel->normals = (float *)ptr;
	ptr = IQModel->normals + 3 * header->num_vertexes;

	IQModel->tangents = (float *)ptr;
	ptr = IQModel->tangents + 3 * header->num_vertexes;

	IQModel->bitangents = (float *)ptr;
	ptr = IQModel->bitangents + 3 * header->num_vertexes;

	IQModel->texcoords = (int16_t *)ptr;
	ptr = IQModel->texcoords + 2 * header->num_vertexes;

	IQModel->blendIndexes = (byte *)ptr;
	ptr = IQModel->blendIndexes + 4 * header->num_vertexes;

	IQModel->blendWeights = (byte *)ptr;
	ptr = IQModel->blendWeights + 4 * header->num_vertexes;

	IQModel->colors = (byte *)ptr;
	ptr = IQModel->colors + 4 * header->num_vertexes;

	IQModel->jointParents = (int *)ptr;
	ptr = IQModel->jointParents + header->num_joints;

	IQModel->triangles = (int *)ptr;
	ptr = IQModel->triangles + 3 * header->num_triangles;

	str                   = (char *)ptr;
	IQModel->jointNames   = str;

	// copy joint names
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++ ) {
		name = ( char* )IQMPtr( header, header->ofs_text + joint->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// setup animations
	IQAnim = IQModel->anims;
	anim = ( iqmAnim_t* )IQMPtr( header, header->ofs_anims );
	for(int i = 0; i < IQModel->num_anims; i++, IQAnim++, anim++ ) {
		IQAnim->num_frames   = anim->num_frames;
		IQAnim->framerate    = anim->framerate;
		IQAnim->num_joints   = header->num_joints;
		IQAnim->flags        = anim->flags;
		IQAnim->jointParents = IQModel->jointParents;
		if( poses ) {
			IQAnim->poses    = poses + anim->first_frame * header->num_poses;
		} else {
			IQAnim->poses    = nullptr;
		}
		if( bounds ) {
			IQAnim->bounds   = bounds + anim->first_frame * 6;
		} else {
			IQAnim->bounds    = nullptr;
		}
		IQAnim->name         = str;
		IQAnim->jointNames   = IQModel->jointNames;

		name = ( char* )IQMPtr( header, header->ofs_text + anim->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// calculate joint transforms
	trans = IQModel->joints;
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++, trans++ ) {
		if( joint->parent >= (int) i ) {
			Log::Warn("R_LoadIQModel: file %s contains an invalid parent joint number.",
				  mod_name );
			return false;
		}

		TransInitRotationQuat( joint->rotate, trans );
		TransAddScale( joint->scale[0], trans );
		TransAddTranslation( joint->translate, trans );

		if( joint->parent >= 0 ) {
			TransCombine( trans, &IQModel->joints[ joint->parent ],
				      trans );
		}

		IQModel->jointParents[i] = joint->parent;
	}

	// calculate pose transforms
	framedata = ( short unsigned int* )IQMPtr( header, header->ofs_frames );
	trans = poses;
	for(unsigned i = 0; i < header->num_frames; i++ ) {
		pose = ( iqmPose_t* )IQMPtr( header, header->ofs_poses );
		for(unsigned j = 0; j < header->num_poses; j++, pose++, trans++ ) {
			vec3_t	translate;
			quat_t	rotate;
			vec3_t	scale;

			translate[0] = pose->channeloffset[0];
			if( pose->mask & 0x001)
				translate[0] += *framedata++ * pose->channelscale[0];
			translate[1] = pose->channeloffset[1];
			if( pose->mask & 0x002)
				translate[1] += *framedata++ * pose->channelscale[1];
			translate[2] = pose->channeloffset[2];
			if( pose->mask & 0x004)
				translate[2] += *framedata++ * pose->channelscale[2];
			rotate[0] = pose->channeloffset[3];
			if( pose->mask & 0x008)
				rotate[0] += *framedata++ * pose->channelscale[3];
			rotate[1] = pose->channeloffset[4];
			if( pose->mask & 0x010)
				rotate[1] += *framedata++ * pose->channelscale[4];
			rotate[2] = pose->channeloffset[5];
			if( pose->mask & 0x020)
				rotate[2] += *framedata++ * pose->channelscale[5];
			rotate[3] = pose->channeloffset[6];
			if( pose->mask & 0x040)
				rotate[3] += *framedata++ * pose->channelscale[6];
			scale[0] = pose->channeloffset[7];
			if( pose->mask & 0x080)
				scale[0] += *framedata++ * pose->channelscale[7];
			scale[1] = pose->channeloffset[8];
			if( pose->mask & 0x100)
				scale[1] += *framedata++ * pose->channelscale[8];
			scale[2] = pose->channeloffset[9];
			if( pose->mask & 0x200)
				scale[2] += *framedata++ * pose->channelscale[9];

			if( scale[0] < 0.0f ||
			    (int)( scale[0] - scale[1] ) ||
			    (int)( scale[1] - scale[2] ) ) {
				Log::Warn("R_LoadIQM: file %s contains an invalid scale.", mod_name );
				return false;
			    }

			// construct transformation
			TransInitRotationQuat( rotate, trans );
			TransAddScale( scale[0], trans );
			TransAddTranslation( translate, trans );
		}
	}

	// copy vertexarrays and indexes
	vertexarray = ( iqmVertexArray_t* )IQMPtr( header, header->ofs_vertexarrays );
	for(unsigned i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
		int	n;

		// total number of values
		n = header->num_vertexes * vertexarray->size;

		switch( vertexarray->type ) {
		case IQM_POSITION:
			ClearBounds( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			Com_Memcpy( IQModel->positions,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			for( int j = 0; j < n; j += vertexarray->size ) {
				AddPointToBounds( &IQModel->positions[ j ],
						  IQModel->bounds[ 0 ],
						  IQModel->bounds[ 1 ] );
			}
			IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			if( IQModel->internalScale > 0.0f ) {
				float inverseScale = 1.0f / IQModel->internalScale;
				for( int j = 0; j < n; j += vertexarray->size ) {
					VectorScale( &IQModel->positions[ j ],
						     inverseScale,
						     &IQModel->positions[ j ] );
				}
			}

			break;
		case IQM_NORMAL:
			Com_Memcpy( IQModel->normals,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			break;
		case IQM_TANGENT:
			BuildTangents( header->num_vertexes,
				       ( float* )IQMPtr( header, vertexarray->offset ),
				       IQModel->normals, IQModel->tangents,
				       IQModel->bitangents );
			break;
		case IQM_TEXCOORD:
			for( int j = 0; j < n; j++ ) {
				IQModel->texcoords[ j ] = floatToHalf( ((float *)IQMPtr( header, vertexarray->offset ))[ j ] );
			}
			break;
		case IQM_BLENDINDEXES:
			Com_Memcpy( IQModel->blendIndexes,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		case IQM_BLENDWEIGHTS:
			weights = (u8vec4_t *)IQMPtr( header, vertexarray->offset );
			for(unsigned j = 0; j < header->num_vertexes; j++ ) {
				IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ];
				IQModel->blendWeights[ 4 * j + 1 ] = weights[ j ][ 1 ];
				IQModel->blendWeights[ 4 * j + 2 ] = weights[ j ][ 2 ];
				IQModel->blendWeights[ 4 * j + 3 ] = weights[ j ][ 3 ];
			}
			break;
		case IQM_COLOR:
			Com_Memcpy( IQModel->colors,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		}
	}

	// copy triangles
	triangle = ( iqmTriangle_t* )IQMPtr( header, header->ofs_triangles );
	for(unsigned i = 0; i < header->num_triangles; i++, triangle++ ) {
		IQModel->triangles[3*i+0] = triangle->vertex[0];
		IQModel->triangles[3*i+1] = triangle->vertex[1];
		IQModel->triangles[3*i+2] = triangle->vertex[2];
	}

	// convert data where necessary and create VBO
	if( r_vboModels->integer && glConfig2.vboVertexSkinningAvailable
	    && IQModel->num_joints <= glConfig2.maxVertexSkinningBones ) {

		if( IQModel->blendIndexes ) {
			indexbuf = (int *)ri.Hunk_AllocateTempMemory( sizeof(int[4]) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				indexbuf[ 4 * i + 0 ] = IQModel->blendIndexes[ 4 * i + 0 ];
				indexbuf[ 4 * i + 1 ] = IQModel->blendIndexes[ 4 * i + 1 ];
				indexbuf[ 4 * i + 2 ] = IQModel->blendIndexes[ 4 * i + 2 ];
				indexbuf[ 4 * i + 3 ] = IQModel->blendIndexes[ 4 * i + 3 ];
			}
		} else {
			indexbuf = nullptr;
		}
		if( IQModel->blendWeights ) {
			const float weightscale = 1.0f / 255.0f;

			weightbuf = (float *)ri.Hunk_AllocateTempMemory( sizeof(vec4_t) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				if( IQModel->blendWeights[ 4 * i + 0 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 1 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 2 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 3 ] == 0 )
					IQModel->blendWeights[ 4 * i + 0 ] = 255;

				weightbuf[ 4 * i + 0 ] = weightscale * IQModel->blendWeights[ 4 * i + 0 ];
				weightbuf[ 4 * i + 1 ] = weightscale * IQModel->blendWeights[ 4 * i + 1 ];
				weightbuf[ 4 * i + 2 ] = weightscale * IQModel->blendWeights[ 4 * i + 2 ];
				weightbuf[ 4 * i + 3 ] = weightscale * IQModel->blendWeights[ 4 * i + 3 ];
			}
		} else {
			weightbuf = nullptr;
		}

		qtangentbuf = (i16vec4_t *)ri.Hunk_AllocateTempMemory( sizeof( i16vec4_t ) * IQModel->num_vertexes );

		for(int i = 0; i < IQModel->num_vertexes; i++ ) {
			R_TBNtoQtangents( &IQModel->tangents[ 3 * i ],
					  &IQModel->bitangents[ 3 * i ],
					  &IQModel->normals[ 3 * i ],
					  qtangentbuf[ i ] );
		}

		vboData.xyz = (vec3_t *)IQModel->positions;
		vboData.qtangent = qtangentbuf;
		vboData.numFrames = 0;
		vboData.color = (u8vec4_t *)IQModel->colors;
		vboData.st = (i16vec2_t *)IQModel->texcoords;
		vboData.noLightCoords = true;
		vboData.boneIndexes = (int (*)[4])indexbuf;
		vboData.boneWeights = (vec4_t *)weightbuf;
		vboData.numVerts = IQModel->num_vertexes;


		vbo = R_CreateStaticVBO( "IQM surface VBO", vboData,
					 vboLayout_t::VBO_LAYOUT_SKELETAL );

		if( qtangentbuf ) {
			ri.Hunk_FreeTempMemory( qtangentbuf );
		}
		if( weightbuf ) {
			ri.Hunk_FreeTempMemory( weightbuf );
		}
		if( indexbuf ) {
			ri.Hunk_FreeTempMemory( indexbuf );
		}

		// create IBO
		ibo = R_CreateStaticIBO( "IQM surface IBO", ( glIndex_t* )IQModel->triangles, IQModel->num_triangles * 3 );
	} else {
		vbo = nullptr;
		ibo = nullptr;
	}

	// register shaders
	// overwrite the material offset with the shader index
	mesh = ( iqmMesh_t* )IQMPtr( header, header->ofs_meshes );
	surface = IQModel->surfaces;
	for(unsigned i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
		surface->surfaceType = surfaceType_t::SF_IQM;

		if( mesh->name ) {
			surface->name = str;
			name = ( char* )IQMPtr( header, header->ofs_text + mesh->name );
			len = strlen( name ) + 1;
			Com_Memcpy( str, name, len );
			str += len;
		} else {
			surface->name = nullptr;
		}

		surface->shader = R_FindShader( ( char* )IQMPtr(header, header->ofs_text + mesh->material),
						shaderType_t::SHADER_3D_DYNAMIC, RSF_DEFAULT );
		if( surface->shader->defaultShader )
			surface->shader = tr.defaultShader;
		surface->data = IQModel;
		surface->first_vertex = mesh->first_vertex;
		surface->num_vertexes = mesh->num_vertexes;
		surface->first_triangle = mesh->first_triangle;
		surface->num_triangles = mesh->num_triangles;
		surface->vbo = vbo;
		surface->ibo = ibo;
	}

	// copy model bounds
	if(header->ofs_bounds)
	{
		iqmBounds_t *ptr = ( iqmBounds_t* )IQMPtr( header, header->ofs_bounds );
		for(unsigned i = 0; i < header->num_frames; i++)
		{
			VectorCopy( ptr->bbmin, bounds );
			bounds += 3;
			VectorCopy( ptr->bbmax, bounds );
			bounds += 3;

			ptr++;
		}
	}

	// register animations
	IQAnim = IQModel->anims;
	if( header->num_anims == 1 ) {
		RE_RegisterAnimationIQM( mod_name, IQAnim );
	}
	for(unsigned i = 0; i < header->num_anims; i++, IQAnim++ ) {
		char name[ MAX_QPATH ];

		Com_sprintf( name, MAX_QPATH, "%s:%s", mod_name, IQAnim->name );
		RE_RegisterAnimationIQM( name, IQAnim );
	}

	// build VBO

	return true;
}
예제 #18
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;
	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;

	mdcModel = ( mdcHeader_t * ) buffer;

	version = LittleLong( mdcModel->version );

	if ( version != MDC_VERSION )
	{
		ri.Printf( PRINT_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 ] = (mdvModel_t*) 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 )
	{
		ri.Printf( PRINT_WARNING, "R_LoadMDC: '%s' has no frames\n", modName );
		return qfalse;
	}

	// swap all the frames
	mdvModel->numFrames = mdcModel->numFrames;
	mdvModel->frames = frame = (mdvFrame_t*) 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

		// RB: 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 = (mdvTag_t*) 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 = (mdvTagName_t*) 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 = (mdvSurface_t*) 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 )
		{
			ri.Error( ERR_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 )
		{
			ri.Error( ERR_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_SurfaceMDV
		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, RSF_DEFAULT );

		// swap all the triangles
		surf->numTriangles = mdcSurf->numTriangles;
		surf->triangles = tri = (srfTriangle_t*) 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 = (mdvXyz_t*) 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;
					//vec3_t    normal;

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

					mdcxyzComp++;
				}
			}
		}

		// swap all the ST
		surf->st = st = (mdvSt_t*) 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
	{
		growList_t      vboSurfaces;
		srfVBOMDVMesh_t *vboSurf;
		vboData_t       data;

		int             f;

		Com_InitGrowList( &vboSurfaces, 10 );

		for ( i = 0, surf = mdvModel->surfaces; i < mdvModel->numSurfaces; i++, surf++ )
		{
			//allocate temp memory for vertex data
			memset( &data, 0, sizeof( data ) );
			data.xyz = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.xyz ) * mdvModel->numFrames * surf->numVerts );
			data.normal = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.normal ) * mdvModel->numFrames * surf->numVerts );
			data.tangent = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.tangent ) * mdvModel->numFrames * surf->numVerts );
			data.binormal = ( vec3_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.binormal ) * mdvModel->numFrames * surf->numVerts );
			data.numFrames = mdvModel->numFrames;
			data.st = ( vec2_t * ) ri.Hunk_AllocateTempMemory( sizeof( *data.st ) * surf->numVerts );
			data.numVerts = surf->numVerts;

			// feed vertex XYZ
			for ( f = 0; f < mdvModel->numFrames; f++ )
			{
				for ( j = 0; j < surf->numVerts; j++ )
				{
					VectorCopy( surf->verts[ f * surf->numVerts + j ].xyz, data.xyz[ f * surf->numVerts + j ] );
				}
			}

			// feed vertex texcoords
			for ( j = 0; j < surf->numVerts; j++ )
			{
				data.st[ j ][ 0 ] = surf->st[ j ].st[ 0 ];
				data.st[ j ][ 1 ] = surf->st[ j ].st[ 1 ];
			}

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

				for ( j = 0; j < ( surf->numVerts * mdvModel->numFrames ); j++ )
				{
					VectorClear( data.tangent[ j ] );
					VectorClear( data.binormal[ j ] );
					VectorClear( data.normal[ j ] );
				}

				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 = data.tangent[ surf->numVerts * f + tri->indexes[ k ] ];
							VectorAdd( v, tangent, v );

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

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

				for ( j = 0; j < ( surf->numVerts * mdvModel->numFrames ); j++ )
				{
					VectorNormalize( data.tangent[ j ] );
					VectorNormalize( data.binormal[ j ] );
					VectorNormalize( data.normal[ j ] );
				}
			}

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

			// create surface
			vboSurf = (srfVBOMDVMesh_t*) 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->ibo = R_CreateStaticIBO2( va( "staticMD3Mesh_IBO %s", surf->name ), surf->numTriangles, surf->triangles );

			vboSurf->vbo = R_CreateStaticVBO( va( "staticMD3Mesh_VBO '%s'", surf->name ), data, VBO_LAYOUT_VERTEX_ANIMATION );
			
			ri.Hunk_FreeTempMemory( data.st );
			ri.Hunk_FreeTempMemory( data.binormal );
			ri.Hunk_FreeTempMemory( data.tangent );
			ri.Hunk_FreeTempMemory( data.normal );
			ri.Hunk_FreeTempMemory( data.xyz );
		}

		// move VBO surfaces list to hunk
		mdvModel->numVBOSurfaces = vboSurfaces.currentElements;
		mdvModel->vboSurfaces = (srfVBOMDVMesh_t**) 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;
}
예제 #19
0
bool idRenderModelMD4::Load( idList<byte>& buffer, idSkinTranslation* skinTranslation ) {
	md4Header_t* pinmodel = ( md4Header_t* )buffer.Ptr();

	int version = LittleLong( pinmodel->version );
	if ( version != MD4_VERSION ) {
		common->Printf( S_COLOR_YELLOW "R_LoadMD4: %s has wrong version (%i should be %i)\n",
			name, version, MD4_VERSION );
		return false;
	}

	type = MOD_MD4;
	int size = LittleLong( pinmodel->ofsEnd );
	q3_dataSize += size;
	md4Header_t* md4 = q3_md4 = ( md4Header_t* )Mem_Alloc( size );

	Com_Memcpy( md4, buffer.Ptr(), LittleLong( pinmodel->ofsEnd ) );

	LL( md4->ident );
	LL( md4->version );
	LL( md4->numFrames );
	LL( md4->numBones );
	LL( md4->numLODs );
	LL( md4->ofsFrames );
	LL( md4->ofsLODs );
	LL( md4->ofsEnd );

	if ( md4->numFrames < 1 ) {
		common->Printf( S_COLOR_YELLOW "R_LoadMD4: %s has no frames\n", name );
		return false;
	}

	// we don't need to swap tags in the renderer, they aren't used

	// swap all the frames
	int frameSize = ( qintptr )( &( ( md4Frame_t* )0 )->bones[ md4->numBones ] );
	for ( int i = 0; i < md4->numFrames; i++ ) {
		md4Frame_t* frame = ( md4Frame_t* )( ( byte* )md4 + md4->ofsFrames + i * frameSize );
		frame->radius = LittleFloat( frame->radius );
		for ( int 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 ] );
		}
		for ( int j = 0; j < md4->numBones * ( int )sizeof ( md4Bone_t ) / 4; j++ ) {
			( ( float* )frame->bones )[ j ] = LittleFloat( ( ( float* )frame->bones )[ j ] );
		}
	}

	// swap all the LOD's
	q3_md4Lods = new mmd4Lod_t[ md4->numLODs ];
	md4LOD_t* lod = ( md4LOD_t* )( ( byte* )md4 + md4->ofsLODs );
	for ( int lodindex = 0; lodindex < md4->numLODs; lodindex++ ) {
		// swap all the surfaces
		q3_md4Lods[ lodindex ].numSurfaces = lod->numSurfaces;
		q3_md4Lods[ lodindex ].surfaces = new idSurfaceMD4[ lod->numSurfaces ];
		md4Surface_t* surf = ( md4Surface_t* )( ( byte* )lod + lod->ofsSurfaces );
		for ( int i = 0; i < lod->numSurfaces; i++ ) {
			q3_md4Lods[ lodindex ].surfaces[ i ].SetMd4Data( surf );
			LL( surf->ident );
			LL( surf->numTriangles );
			LL( surf->ofsTriangles );
			LL( surf->numVerts );
			LL( surf->ofsVerts );
			LL( surf->ofsEnd );

			if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
				common->Error( "R_LoadMD3: %s has more than %i verts on a surface (%i)",
					name, SHADER_MAX_VERTEXES, surf->numVerts );
			}
			if ( surf->numTriangles * 3 > SHADER_MAX_INDEXES ) {
				common->Error( "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
					name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
			}

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

			// register the shaders
			shader_t* sh = R_FindShader( surf->shader, LIGHTMAP_NONE, true );
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}

			// swap all the triangles
			md4Triangle_t* tri = ( md4Triangle_t* )( ( byte* )surf + surf->ofsTriangles );
			for ( int j = 0; j < surf->numTriangles; j++, tri++ ) {
				LL( tri->indexes[ 0 ] );
				LL( tri->indexes[ 1 ] );
				LL( tri->indexes[ 2 ] );
			}

			// swap all the vertexes
			// FIXME
			// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
			// in for reference.
			//v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
			md4Vertex_t* v = ( md4Vertex_t* )( ( byte* )surf + surf->ofsVerts );
			for ( int j = 0; j < surf->numVerts; j++ ) {
				v->normal[ 0 ] = LittleFloat( v->normal[ 0 ] );
				v->normal[ 1 ] = LittleFloat( v->normal[ 1 ] );
				v->normal[ 2 ] = LittleFloat( v->normal[ 2 ] );

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

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

				for ( int k = 0; k < v->numWeights; k++ ) {
					v->weights[ k ].boneIndex = LittleLong( v->weights[ k ].boneIndex );
					v->weights[ k ].boneWeight = LittleFloat( v->weights[ k ].boneWeight );
					v->weights[ k ].offset[ 0 ] = LittleFloat( v->weights[ k ].offset[ 0 ] );
					v->weights[ k ].offset[ 1 ] = LittleFloat( v->weights[ k ].offset[ 1 ] );
					v->weights[ k ].offset[ 2 ] = LittleFloat( v->weights[ k ].offset[ 2 ] );
				}
				// FIXME
				// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
				// in for reference.
				//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
				v = ( md4Vertex_t* )( ( byte* )&v->weights[ v->numWeights ] );
			}

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

		// find the next LOD
		lod = ( md4LOD_t* )( ( byte* )lod + lod->ofsEnd );
	}

	return true;
}
예제 #20
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;
}
예제 #21
0
파일: tr_bsp.cpp 프로젝트: Avygeil/NewJK
/*
=================
R_LoadFogs

=================
*/
static	void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump, world_t &worldData, int index ) {
	int			i;
	fog_t		*out;
	dfog_t		*fogs;
	dbrush_t 	*brushes, *brush;
	dbrushside_t	*sides;
	int			count, brushesCount, sidesCount;
	int			sideNum;
	int			planeNum;
	shader_t	*shader;
	float		d;
	int			firstSide=0;
	int			lightmaps[MAXLIGHTMAPS] = { LIGHTMAP_NONE } ;

	fogs = (dfog_t *)(fileBase + l->fileofs);
	if (l->filelen % sizeof(*fogs)) {
		Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name);
	}
	count = l->filelen / sizeof(*fogs);

	// create fog strucutres for them
	worldData.numfogs = count + 1;
	worldData.fogs = (fog_t *)R_Hunk_Alloc ( (worldData.numfogs+1)*sizeof(*out), qtrue);
	worldData.globalFog = -1;
	out = worldData.fogs + 1;

	// Copy the global fog from the main world into the bsp instance
	if(index)
	{
		if(tr.world && (tr.world->globalFog != -1))
		{
			// Use the nightvision fog slot
			worldData.fogs[worldData.numfogs] = tr.world->fogs[tr.world->globalFog];
			worldData.globalFog = worldData.numfogs;
			worldData.numfogs++;
		}
	}

	if ( !count ) {
		return;
	}

	brushes = (dbrush_t *)(fileBase + brushesLump->fileofs);
	if (brushesLump->filelen % sizeof(*brushes)) {
		Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name);
	}
	brushesCount = brushesLump->filelen / sizeof(*brushes);

	sides = (dbrushside_t *)(fileBase + sidesLump->fileofs);
	if (sidesLump->filelen % sizeof(*sides)) {
		Com_Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData.name);
	}
	sidesCount = sidesLump->filelen / sizeof(*sides);

	for ( i=0 ; i<count ; i++, fogs++) {
		out->originalBrushNumber = LittleLong( fogs->brushNum );
		if (out->originalBrushNumber == -1)
		{
			if(index)
			{
				Com_Error (ERR_DROP, "LoadMap: global fog not allowed in bsp instances - %s", worldData.name);
			}
			VectorSet(out->bounds[0], MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD);
			VectorSet(out->bounds[1], MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD);
			worldData.globalFog = i + 1;
		}
		else
		{
			if ( (unsigned)out->originalBrushNumber >= (unsigned)brushesCount ) {
				Com_Error( ERR_DROP, "fog brushNumber out of range" );
			}
			brush = brushes + out->originalBrushNumber;

			firstSide = LittleLong( brush->firstSide );

				if ( (unsigned)firstSide > (unsigned)(sidesCount - 6) ) {
				Com_Error( ERR_DROP, "fog brush sideNumber out of range" );
			}

			// brushes are always sorted with the axial sides first
			sideNum = firstSide + 0;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[0][0] = -worldData.planes[ planeNum ].dist;

			sideNum = firstSide + 1;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[1][0] = worldData.planes[ planeNum ].dist;

			sideNum = firstSide + 2;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[0][1] = -worldData.planes[ planeNum ].dist;

			sideNum = firstSide + 3;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[1][1] = worldData.planes[ planeNum ].dist;

			sideNum = firstSide + 4;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[0][2] = -worldData.planes[ planeNum ].dist;

			sideNum = firstSide + 5;
			planeNum = LittleLong( sides[ sideNum ].planeNum );
			out->bounds[1][2] = worldData.planes[ planeNum ].dist;
		}

		// get information from the shader for fog parameters
		shader = R_FindShader( fogs->shader, lightmaps, stylesDefault, qtrue );

		assert(shader->fogParms);
		if (!shader->fogParms)
		{//bad shader!!
			out->parms.color[0] = 1.0f;
			out->parms.color[1] = 0.0f;
			out->parms.color[2] = 0.0f;
			out->parms.depthForOpaque = 250.0f;
		}
		else
		{
			out->parms = *shader->fogParms;
		}
		out->colorInt = ColorBytes4 ( out->parms.color[0],
			out->parms.color[1],
			out->parms.color[2], 1.0 );

		d = out->parms.depthForOpaque < 1 ? 1 : out->parms.depthForOpaque;
		out->tcScale = 1.0f / ( d * 8 );

		// set the gradient vector
		sideNum = LittleLong( fogs->visibleSide );

		if ( sideNum == -1 ) {
			out->hasSurface = qfalse;
		} else {
			out->hasSurface = qtrue;
			planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
			VectorSubtract( vec3_origin, worldData.planes[ planeNum ].normal, out->surface );
			out->surface[3] = -worldData.planes[ planeNum ].dist;
		}

		out++;
	}

	if (!index)
	{
		// Initialise the last fog so we can use it with the LA Goggles
		// NOTE: We are might appear to be off the end of the array, but we allocated an extra memory slot above but [purposely] didn't
		//	increment the total world numFogs to match our array size
		VectorSet(out->bounds[0], MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD);
		VectorSet(out->bounds[1], MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD);
		out->originalBrushNumber = -1;
		out->parms.color[0] = 0.0f;
		out->parms.color[1] = 0.0f;
		out->parms.color[2] = 0.0f;
		out->parms.depthForOpaque = 0.0f;
		out->colorInt = 0x00000000;
		out->tcScale = 0.0f;
		out->hasSurface = qfalse;
	}
}
예제 #22
0
파일: tr_model.c 프로젝트: luaman/zq
static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) 
{
	int					i, j, k, l;
	mdrHeader_t			*pinmodel, *mdr;
        mdrFrame_t			*frame;
	mdrLOD_t			*lod, *curlod;
	mdrSurface_t			*surf, *cursurf;
	mdrTriangle_t			*tri, *curtri;
	mdrVertex_t			*v, *curv;
	mdrWeight_t			*weight, *curweight;
	mdrTag_t			*tag, *curtag;
	int					size;
	shader_t			*sh;

	pinmodel = (mdrHeader_t *)buffer;

	pinmodel->version = LittleLong(pinmodel->version);
	if (pinmodel->version != MDR_VERSION) 
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
		return qfalse;
	}

	size = LittleLong(pinmodel->ofsEnd);
	
	if(size > filesize)
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
		return qfalse;
	}
	
	mod->type = MOD_MDR;

	pinmodel->numFrames = LittleLong(pinmodel->numFrames);
	pinmodel->numBones = LittleLong(pinmodel->numBones);
	pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames);
	
	// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
	// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
	if(pinmodel->ofsFrames < 0)
	{
		// mdrFrame_t is larger than mdrCompFrame_t:
		size += pinmodel->numFrames * sizeof(frame->name);
		// now add enough space for the uncompressed bones.
		size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
	}
	
	mod->dataSize += size;
	mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );

	// Copy all the values over from the file and fix endian issues in the process, if necessary.
	
	mdr->ident = LittleLong(pinmodel->ident);
	mdr->version = pinmodel->version;	// Don't need to swap byte order on this one, we already did above.
	strlcpy(mdr->name, pinmodel->name, sizeof(mdr->name));
	mdr->numFrames = pinmodel->numFrames;
	mdr->numBones = pinmodel->numBones;
	mdr->numLODs = LittleLong(pinmodel->numLODs);
	mdr->numTags = LittleLong(pinmodel->numTags);
	// We don't care about offset values, we'll generate them ourselves while loading.
	
	mod->numLods = mdr->numLODs;

	if ( mdr->numFrames < 1 ) 
	{
		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
		return qfalse;
	}

	/* The first frame will be put into the first free space after the header */
	frame = (mdrFrame_t *)(mdr + 1);
	mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
		
	if (pinmodel->ofsFrames < 0)
	{
		mdrCompFrame_t *cframe;
				
		// compressed model...				
		cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);

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

			frame->radius = LittleFloat(cframe->radius);
			frame->name[0] = '\0';	// No name supplied in the compressed version.
			
			for(j = 0; j < mdr->numBones; j++)
			{
				for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
				{
					// Do swapping for the uncompressing functions. They seem to use shorts
					// values only, so I assume this will work. Never tested it on other
					// platforms, though.
					
					((unsigned short *)(cframe->bones[j].Comp))[k] =
						LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
				}
				
				/* Now do the actual uncompressing */
				MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
			}
			
			// Next Frame...
			cframe = (mdrCompFrame_t *) &cframe->bones[j];
			frame = (mdrFrame_t *) &frame->bones[j];
		}
	}
	else
	{
		mdrFrame_t *curframe;
		
		// uncompressed model...
		//
    
		curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
		
		// swap all the frames
		for ( i = 0 ; i < mdr->numFrames ; i++) 
		{
			for(j = 0; j < 3; j++)
			{
				frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
				frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
				frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
			}
			
			frame->radius = LittleFloat(curframe->radius);
			strlcpy(frame->name, curframe->name, sizeof(frame->name));
			
			for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) 
			{
				((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
			}
			
			curframe++;
			frame++;
		}
	}
	
	// frame should now point to the first free address after all frames.
	lod = (mdrLOD_t *) frame;
	mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
	
	curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
		
	// swap all the LOD's
	for ( l = 0 ; l < mdr->numLODs ; l++)
	{
		lod->numSurfaces = LittleLong(curlod->numSurfaces);
		
		// swap all the surfaces
		surf = (mdrSurface_t *) (lod + 1);
		lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
		cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
		
		for ( i = 0 ; i < lod->numSurfaces ; i++) {
			// first do some copying stuff
			
			surf->ident = SF_MDR;
			strlcpy(surf->name, cursurf->name, sizeof(surf->name));
			strlcpy(surf->shader, cursurf->shader, sizeof(surf->shader));
			
			surf->ofsHeader = (byte *) mdr - (byte *) surf;
			
			surf->numVerts = LittleLong(cursurf->numVerts);
			surf->numTriangles = LittleLong(cursurf->numTriangles);
			// numBoneReferences and BoneReferences generally seem to be unused
			
			// now do the checks that may fail.
			if ( surf->numVerts > SHADER_MAX_VERTEXES ) 
			{
				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)",
					  mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
				return qfalse;
			}
			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) 
			{
				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)",
					  mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
				return qfalse;
			}
			// lowercase the surface name so skin compares are faster
			Q_strlwr( surf->name );

			// register the shaders
			sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}
			
			// now copy the vertexes.
			v = (mdrVertex_t *) (surf + 1);
			surf->ofsVerts = (int)((byte *) v - (byte *) surf);
			curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
			
			for(j = 0; j < surf->numVerts; j++)
			{
				v->normal[0] = LittleFloat(curv->normal[0]);
				v->normal[1] = LittleFloat(curv->normal[1]);
				v->normal[2] = LittleFloat(curv->normal[2]);
				
				v->texCoords[0] = LittleFloat(curv->texCoords[0]);
				v->texCoords[1] = LittleFloat(curv->texCoords[1]);
				
				v->numWeights = LittleLong(curv->numWeights);
				weight = &v->weights[0];
				curweight = &curv->weights[0];
				
				// Now copy all the weights
				for(k = 0; k < v->numWeights; k++)
				{
					weight->boneIndex = LittleLong(curweight->boneIndex);
					weight->boneWeight = LittleFloat(curweight->boneWeight);
					
					weight->offset[0] = LittleFloat(curweight->offset[0]);
					weight->offset[1] = LittleFloat(curweight->offset[1]);
					weight->offset[2] = LittleFloat(curweight->offset[2]);
					
					weight++;
					curweight++;
				}
				
				v = (mdrVertex_t *) weight;
				curv = (mdrVertex_t *) curweight;
			}
						
			// we know the offset to the triangles now:
			tri = (mdrTriangle_t *) v;
			surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
			curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
			
			for(j = 0; j < surf->numTriangles; j++)
			{
				tri->indexes[0] = LittleLong(curtri->indexes[0]);
				tri->indexes[1] = LittleLong(curtri->indexes[1]);
				tri->indexes[2] = LittleLong(curtri->indexes[2]);
				
				tri++;
				curtri++;
			}
			
			// tri now points to the end of the surface.
			surf->ofsEnd = (byte *) tri - (byte *) surf;
			surf = (mdrSurface_t *) tri;

			// find the next surface.
			cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
		}

		// surf points to the next lod now.
		lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
		lod = (mdrLOD_t *) surf;

		// find the next LOD.
		curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
	}
	
	// lod points to the first tag now, so update the offset too.
	tag = (mdrTag_t *) lod;
	mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
	curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
	
	for (i = 0 ; i < mdr->numTags ; i++)
	{
		tag->boneIndex = LittleLong(curtag->boneIndex);
		strlcpy(tag->name, curtag->name, sizeof(tag->name));
		
		tag++;
		curtag++;
	}
	
	// And finally we know the offset to the end.
	mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);

	// phew! we're done.
	
	return qtrue;
}
예제 #23
0
/*
===============
RE_RegisterSkin

===============
*/
qhandle_t RE_RegisterSkin(const char *name)
{
	qhandle_t       hSkin;
	skin_t         *skin;
	skinSurface_t  *surf;
	skinModel_t    *model;		//----(SA) added
	char           *text, *text_p;
	char           *token;
	char            surfName[MAX_QPATH];

	if(!name || !name[0])
	{
		Com_Printf("Empty name passed to RE_RegisterSkin\n");
		return 0;
	}

	if(strlen(name) >= MAX_QPATH)
	{
		Com_Printf("Skin name exceeds MAX_QPATH\n");
		return 0;
	}


	// see if the skin is already loaded
	for(hSkin = 1; hSkin < tr.numSkins; hSkin++)
	{
		skin = tr.skins[hSkin];
		if(!Q_stricmp(skin->name, name))
		{
			if(skin->numSurfaces == 0)
			{
				return 0;		// default skin
			}
			return hSkin;
		}
	}

	// allocate a new skin
	if(tr.numSkins == MAX_SKINS)
	{
		ri.Printf(PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name);
		return 0;
	}

//----(SA)  moved things around slightly to fix the problem where you restart
//          a map that has ai characters who had invalid skin names entered
//          in thier "skin" or "head" field

	// make sure the render thread is stopped
	R_SyncRenderThread();

#if 0
	// If not a .skin file, load as a single shader
	if(strcmp(name + strlen(name) - 5, ".skin"))
	{
		skin->numSurfaces = 1;
		skin->surfaces[0] = ri.Hunk_Alloc(sizeof(skin->surfaces[0]), h_low);
		skin->surfaces[0]->shader = R_FindShader(name, SHADER_3D_DYNAMIC, true);
		return hSkin;
	}
#endif

	// load and parse the skin file
	ri.FS_ReadFile(name, (void **)&text);
	if(!text)
	{
		return 0;
	}

	tr.numSkins++;
	skin = (skin_t*)ri.Hunk_Alloc(sizeof(skin_t), h_low);
	tr.skins[hSkin] = skin;
	Q_strncpyz(skin->name, name, sizeof(skin->name));
	skin->numSurfaces = 0;
	skin->numModels = 0;		//----(SA) added

//----(SA)  end

	text_p = text;
	while(text_p && *text_p)
	{
		// get surface name
		token = CommaParse(&text_p);
		Q_strncpyz(surfName, token, sizeof(surfName));

		if(!token[0])
		{
			break;
		}
		// lowercase the surface name so skin compares are faster
		Q_strlwr(surfName);

		if(*text_p == ',')
		{
			text_p++;
		}

		if(!Q_stricmpn(token, "tag_", 4))
		{
			continue;
		}

		if(!Q_stricmpn(token, "md3_", 4))
		{
			// this is specifying a model
			model = skin->models[skin->numModels] = (skinModel_t*)ri.Hunk_Alloc(sizeof(*skin->models[0]), h_low);
			Q_strncpyz(model->type, token, sizeof(model->type));
			model->hash = Com_HashKey(model->type, sizeof(model->type));

			// get the model name
			token = CommaParse(&text_p);

			Q_strncpyz(model->model, token, sizeof(model->model));

			skin->numModels++;
			continue;
		}

		// parse the shader name
		token = CommaParse(&text_p);

		surf = skin->surfaces[skin->numSurfaces] = (skinSurface_t*)ri.Hunk_Alloc(sizeof(*skin->surfaces[0]), h_low);
		Q_strncpyz(surf->name, surfName, sizeof(surf->name));

		// RB: bspSurface not not have ::hash yet
//		surf->hash = Com_HashKey(surf->name, sizeof(surf->name));
		surf->shader = R_FindShader(token, SHADER_3D_DYNAMIC, true);
		skin->numSurfaces++;
	}

	ri.FS_FreeFile(text);

	// never let a skin have 0 shaders
	if(skin->numSurfaces == 0)
	{
		return 0;				// use default skin
	}

	return hSkin;
}
예제 #24
0
/*
=================
R_LoadMD4
=================
*/
static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qboolean bAlreadyCached ) {
	int					i,l;
	md4Header_t			*pinmodel, *md4;
	md4LOD_t			*lod;
	md4Surface_t		*surf;
	int					version;
	int					size;
	shader_t			*sh;

#ifndef _M_IX86
	int					j, k;
	int					frameSize;
	md4Tag_t			*tag;
	md4Triangle_t		*tri;
	md4Vertex_t			*v;
	md4Frame_t			*frame;
	md4CompFrame_t		*cframe;
#endif 

	pinmodel = (md4Header_t *)buffer;
	//
	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
	//	
	version = (pinmodel->version);
	size	= (pinmodel->ofsEnd);

	if (!bAlreadyCached)
	{
		version = LittleLong(version);
		size	= LittleLong(size);
	}

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

	mod->type	   = MOD_MD4;	
	mod->dataSize += size;

	qboolean bAlreadyFound = qfalse;
	md4 = mod->md4 = (md4Header_t*) //ri.Hunk_Alloc( size );
									RE_RegisterModels_Malloc(size, mod_name, &bAlreadyFound, TAG_MODEL_MD4);

	assert(bAlreadyCached == bAlreadyFound);	// I should probably eliminate 'bAlreadyFound', but wtf?

	if (!bAlreadyFound)
	{
		memcpy( md4, buffer, size );

		LL(md4->ident);
		LL(md4->version);
		LL(md4->numFrames);
		LL(md4->numBones);
		LL(md4->numLODs);
		LL(md4->ofsFrames);
		LL(md4->ofsLODs);
		LL(md4->numTags);
		LL(md4->ofsTags);
		LL(md4->ofsEnd);
	}

	mod->numLods = md4->numLODs -1 ;	//copy this up to the model for ease of use - it wil get inced after this.

	if ( md4->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
		return qfalse;
	}

	if (bAlreadyFound)
	{
		return qtrue;	// All done. Stop, go no further, do not LittleLong(), do not pass Go...
	}


#ifndef _M_IX86
	//
	// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
	//
	if (md4->ofsFrames<0) // Compressed .
	{
		// swap all the frames
		frameSize = (int)( &((md4CompFrame_t *)0)->bones[ md4->numBones ] );
		for ( i = 0 ; i < md4->numFrames ; i++) {
			cframe = (md4CompFrame_t *) ( (byte *)md4 - md4->ofsFrames + i * frameSize );
    		cframe->radius = LittleFloat( cframe->radius );
			for ( j = 0 ; j < 3 ; j++ ) {
				cframe->bounds[0][j] = LittleFloat( cframe->bounds[0][j] );
				cframe->bounds[1][j] = LittleFloat( cframe->bounds[1][j] );
	    		cframe->localOrigin[j] = LittleFloat( cframe->localOrigin[j] );
			}
			for ( j = 0 ; j < md4->numBones * sizeof( md4CompBone_t ) / 2 ; j++ ) {
				((short *)cframe->bones)[j] = LittleShort( ((short *)cframe->bones)[j] );
			}
		}
	}
	else
	{
		// swap all the frames
		frameSize = (int)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
		for ( i = 0 ; i < md4->numFrames ; i++) {
			frame = (md4Frame_t *) ( (byte *)md4 + md4->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] );
			}
			for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
				((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
			}
		}
	}
#endif


	// swap all the LOD's	(we need to do the middle part of this even for intel, because of shader reg and err-check)
	lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
	for ( l = 0 ; l < md4->numLODs ; l++) {
		LL(lod->ofsSurfaces);
		LL(lod->numSurfaces);
		LL(lod->ofsEnd);
		// swap all the surfaces
		surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
		for ( i = 0 ; i < lod->numSurfaces ; i++) {
			LL(surf->numTriangles);
			LL(surf->ofsTriangles);
			LL(surf->numVerts);
			LL(surf->ofsVerts);
			LL(surf->ofsEnd);
			LL(surf->ofsHeader);
			
			if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD4: %s has more than %i verts on a surface (%i)",
					mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
			}
			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD4: %s has more than %i triangles on a surface (%i)",
					mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
			}
		
			// change to surface identifier
			surf->ident = SF_MD4;

			// register the shaders
			sh = R_FindShader( surf->shader, lightmapsNone, stylesDefault, qtrue );
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}
			RE_RegisterModels_StoreShaderRequest(mod_name, &surf->shader[0], &surf->shaderIndex);

#ifndef _M_IX86
//
// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
//

			// swap all the triangles
			tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
			for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
				LL(tri->indexes[0]);
				LL(tri->indexes[1]);
				LL(tri->indexes[2]);
			}

			// swap all the vertexes
			v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts );
			for ( j = 0 ; j < surf->numVerts ; j++ ) {
				v->normal[0] = LittleFloat( v->normal[0] );
				v->normal[1] = LittleFloat( v->normal[1] );
				v->normal[2] = LittleFloat( v->normal[2] );

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

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

				for ( k = 0 ; k < v->numWeights ; k++ ) {
					v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
					v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
				   v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
				   v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
				   v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
				}
				v = (md4Vertex_t *)&v->weights[v->numWeights];
			}
#endif

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

		// find the next LOD
		lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
	}

#ifndef _M_IX86
//
// optimisation, we don't bother doing this for standard intel case since our data's already in that format...
//
	tag = (md4Tag_t *) ( (byte *)md4 + md4->ofsTags );
	for ( i = 0 ; i < md4->numTags ; i++) {
		LL(tag->boneIndex);
		tag++;
	}
#endif

	return qtrue;
}
예제 #25
0
파일: tr_model.c 프로젝트: luaman/zq
/*
=================
R_LoadMD3
=================
*/
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name ) {
	int					i, j;
	md3Header_t			*pinmodel;
    md3Frame_t			*frame;
	md3Surface_t		*surf;
	md3Shader_t			*shader;
	md3Triangle_t		*tri;
	md3St_t				*st;
	md3XyzNormal_t		*xyz;
	md3Tag_t			*tag;
	int					version;
	int					size;

	pinmodel = (md3Header_t *)buffer;

	version = LittleLong (pinmodel->version);
	if (version != MD3_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD3_VERSION);
		return qfalse;
	}

	mod->type = MOD_MESH;
	size = LittleLong(pinmodel->ofsEnd);
	mod->dataSize += size;
	mod->md3[lod] = ri.Hunk_Alloc( size, h_low );

	memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );

    LL(mod->md3[lod]->ident);
    LL(mod->md3[lod]->version);
    LL(mod->md3[lod]->numFrames);
    LL(mod->md3[lod]->numTags);
    LL(mod->md3[lod]->numSurfaces);
    LL(mod->md3[lod]->ofsFrames);
    LL(mod->md3[lod]->ofsTags);
    LL(mod->md3[lod]->ofsSurfaces);
    LL(mod->md3[lod]->ofsEnd);

	if ( mod->md3[lod]->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
		return qfalse;
	}
    
	// swap all the frames
    frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
    for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
    	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] );
        }
	}

	// swap all the tags
    tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
    for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
        for ( j = 0 ; j < 3 ; j++ ) {
			tag->origin[j] = LittleFloat( tag->origin[j] );
			tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
			tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
			tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
        }
	}

	// swap all the surfaces
	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {

        LL(surf->ident);
        LL(surf->flags);
        LL(surf->numFrames);
        LL(surf->numShaders);
        LL(surf->numTriangles);
        LL(surf->ofsTriangles);
        LL(surf->numVerts);
        LL(surf->ofsShaders);
        LL(surf->ofsSt);
        LL(surf->ofsXyzNormals);
        LL(surf->ofsEnd);
		
		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
		}
		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
			ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
		}
	
		// change to surface identifier
		surf->ident = SF_MD3;

		// 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
        shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
        for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
            shader_t	*sh;

            sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
			if ( sh->defaultShader ) {
				shader->shaderIndex = 0;
			} else {
				shader->shaderIndex = sh->index;
			}
        }

		// swap all the triangles
		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
			LL(tri->indexes[0]);
			LL(tri->indexes[1]);
			LL(tri->indexes[2]);
		}

		// swap all the ST
        st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
        for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
            st->st[0] = LittleFloat( st->st[0] );
            st->st[1] = LittleFloat( st->st[1] );
        }

		// swap all the XyzNormals
        xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
        for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ ) 
		{
            xyz->xyz[0] = LittleShort( xyz->xyz[0] );
            xyz->xyz[1] = LittleShort( xyz->xyz[1] );
            xyz->xyz[2] = LittleShort( xyz->xyz[2] );

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


		// find the next surface
		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
	}
    
	return qtrue;
}
예제 #26
0
static bool R_LoadMd3Lod( idRenderModel* mod, int lod, const void* buffer, const char* mod_name ) {
    md3Header_t* pinmodel = ( md3Header_t* )buffer;

    int version = LittleLong( pinmodel->version );
    if ( version != MD3_VERSION ) {
        common->Printf( S_COLOR_YELLOW "R_LoadMD3: %s has wrong version (%i should be %i)\n",
                        mod_name, version, MD3_VERSION );
        return false;
    }

    mod->type = MOD_MESH3;
    int size = LittleLong( pinmodel->ofsEnd );
    mod->q3_dataSize += size;
    mod->q3_md3[ lod ].header = ( md3Header_t* )Mem_Alloc( size );

    Com_Memcpy( mod->q3_md3[ lod ].header, buffer, LittleLong( pinmodel->ofsEnd ) );

    LL( mod->q3_md3[ lod ].header->ident );
    LL( mod->q3_md3[ lod ].header->version );
    LL( mod->q3_md3[ lod ].header->numFrames );
    LL( mod->q3_md3[ lod ].header->numTags );
    LL( mod->q3_md3[ lod ].header->numSurfaces );
    LL( mod->q3_md3[ lod ].header->ofsFrames );
    LL( mod->q3_md3[ lod ].header->ofsTags );
    LL( mod->q3_md3[ lod ].header->ofsSurfaces );
    LL( mod->q3_md3[ lod ].header->ofsEnd );

    if ( mod->q3_md3[ lod ].header->numFrames < 1 ) {
        common->Printf( S_COLOR_YELLOW "R_LoadMD3: %s has no frames\n", mod_name );
        return false;
    }

    bool fixRadius = false;
    if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) &&
            ( strstr( mod->name,"sherman" ) || strstr( mod->name, "mg42" ) ) ) {
        fixRadius = true;
    }

    // swap all the frames
    md3Frame_t* frame = ( md3Frame_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsFrames );
    for ( int i = 0; i < mod->q3_md3[ lod ].header->numFrames; i++, frame++ ) {
        frame->radius = LittleFloat( frame->radius );
        if ( fixRadius ) {
            frame->radius = 256;
            for ( int j = 0; j < 3; j++ ) {
                frame->bounds[ 0 ][ j ] = 128;
                frame->bounds[ 1 ][ j ] = -128;
                frame->localOrigin[ j ] = LittleFloat( frame->localOrigin[ j ] );
            }
        }
        // Hack for Bug using plugin generated model
        else if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) && frame->radius == 1 ) {
            frame->radius = 256;
            for ( int j = 0; j < 3; j++ ) {
                frame->bounds[ 0 ][ j ] = 128;
                frame->bounds[ 1 ][ j ] = -128;
                frame->localOrigin[ j ] = LittleFloat( frame->localOrigin[ j ] );
            }
        } else {
            for ( int 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 ] );
            }
        }
    }

    // swap all the tags
    md3Tag_t* tag = ( md3Tag_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsTags );
    for ( int i = 0; i < mod->q3_md3[ lod ].header->numTags * mod->q3_md3[ lod ].header->numFrames; i++, tag++ ) {
        for ( int j = 0; j < 3; j++ ) {
            tag->origin[ j ] = LittleFloat( tag->origin[ j ] );
            tag->axis[ 0 ][ j ] = LittleFloat( tag->axis[ 0 ][ j ] );
            tag->axis[ 1 ][ j ] = LittleFloat( tag->axis[ 1 ][ j ] );
            tag->axis[ 2 ][ j ] = LittleFloat( tag->axis[ 2 ][ j ] );
        }
    }

    // swap all the surfaces
    mod->q3_md3[ lod ].surfaces = new idSurfaceMD3[ mod->q3_md3[ lod ].header->numSurfaces ];
    md3Surface_t* surf = ( md3Surface_t* )( ( byte* )mod->q3_md3[ lod ].header + mod->q3_md3[ lod ].header->ofsSurfaces );
    for ( int i = 0; i < mod->q3_md3[ lod ].header->numSurfaces; i++ ) {
        mod->q3_md3[ lod ].surfaces[ i ].SetMd3Data( surf );
        LL( surf->ident );
        LL( surf->flags );
        LL( surf->numFrames );
        LL( surf->numShaders );
        LL( surf->numTriangles );
        LL( surf->ofsTriangles );
        LL( surf->numVerts );
        LL( surf->ofsShaders );
        LL( surf->ofsSt );
        LL( surf->ofsXyzNormals );
        LL( surf->ofsEnd );

        if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
            common->Error( "R_LoadMD3: %s has more than %i verts on a surface (%i)",
                           mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
        }
        if ( surf->numTriangles * 3 > SHADER_MAX_INDEXES ) {
            common->Error( "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
                           mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
        }

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

        // strip off a trailing _1 or _2
        // this is a crutch for q3data being a mess
        int Len = String::Length( surf->name );
        if ( Len > 2 && surf->name[ Len - 2 ] == '_' ) {
            surf->name[ Len - 2 ] = 0;
        }

        // register the shaders
        md3Shader_t* shader = ( md3Shader_t* )( ( byte* )surf + surf->ofsShaders );
        for ( int j = 0; j < surf->numShaders; j++, shader++ ) {
            shader_t* sh = R_FindShader( shader->name, LIGHTMAP_NONE, true );
            if ( sh->defaultShader ) {
                shader->shaderIndex = 0;
            } else {
                shader->shaderIndex = sh->index;
            }
        }

        // swap all the triangles
        md3Triangle_t* tri = ( md3Triangle_t* )( ( byte* )surf + surf->ofsTriangles );
        for ( int j = 0; j < surf->numTriangles; j++, tri++ ) {
            LL( tri->indexes[ 0 ] );
            LL( tri->indexes[ 1 ] );
            LL( tri->indexes[ 2 ] );
        }

        // swap all the ST
        md3St_t* st = ( md3St_t* )( ( byte* )surf + surf->ofsSt );
        for ( int j = 0; j < surf->numVerts; j++, st++ ) {
            st->st[ 0 ] = LittleFloat( st->st[ 0 ] );
            st->st[ 1 ] = LittleFloat( st->st[ 1 ] );
        }

        // swap all the XyzNormals
        md3XyzNormal_t* xyz = ( md3XyzNormal_t* )( ( byte* )surf + surf->ofsXyzNormals );
        for ( int j = 0; j < surf->numVerts * surf->numFrames; j++, xyz++ ) {
            xyz->xyz[ 0 ] = LittleShort( xyz->xyz[ 0 ] );
            xyz->xyz[ 1 ] = LittleShort( xyz->xyz[ 1 ] );
            xyz->xyz[ 2 ] = LittleShort( xyz->xyz[ 2 ] );

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

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

    return true;
}
예제 #27
0
파일: tr_model.c 프로젝트: luaman/zq
static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
	int					i, j, k, lodindex;
	md4Header_t			*pinmodel, *md4;
    md4Frame_t			*frame;
	md4LOD_t			*lod;
	md4Surface_t		*surf;
	md4Triangle_t		*tri;
	md4Vertex_t			*v;
	int					version;
	int					size;
	shader_t			*sh;
	int					frameSize;

	pinmodel = (md4Header_t *)buffer;

	version = LittleLong (pinmodel->version);
	if (version != MD4_VERSION) {
		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has wrong version (%i should be %i)\n",
				 mod_name, version, MD4_VERSION);
		return qfalse;
	}

	mod->type = MOD_MD4;
	size = LittleLong(pinmodel->ofsEnd);
	mod->dataSize += size;
	md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );

	memcpy(md4, buffer, size);

    LL(md4->ident);
    LL(md4->version);
    LL(md4->numFrames);
    LL(md4->numBones);
    LL(md4->numLODs);
    LL(md4->ofsFrames);
    LL(md4->ofsLODs);
    md4->ofsEnd = size;

	if ( md4->numFrames < 1 ) {
		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
		return qfalse;
	}

    // we don't need to swap tags in the renderer, they aren't used
    
	// swap all the frames
	frameSize = (size_t)( &((md4Frame_t *)0)->bones[ md4->numBones ] );
    for ( i = 0 ; i < md4->numFrames ; i++, frame++) {
	    frame = (md4Frame_t *) ( (byte *)md4 + md4->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] );
        }
		for ( j = 0 ; j < md4->numBones * sizeof( md4Bone_t ) / 4 ; j++ ) {
			((float *)frame->bones)[j] = LittleFloat( ((float *)frame->bones)[j] );
		}
	}

	// swap all the LOD's
	lod = (md4LOD_t *) ( (byte *)md4 + md4->ofsLODs );
	for ( lodindex = 0 ; lodindex < md4->numLODs ; lodindex++ ) {

		// swap all the surfaces
		surf = (md4Surface_t *) ( (byte *)lod + lod->ofsSurfaces );
		for ( i = 0 ; i < lod->numSurfaces ; i++) {
			LL(surf->ident);
			LL(surf->numTriangles);
			LL(surf->ofsTriangles);
			LL(surf->numVerts);
			LL(surf->ofsVerts);
			LL(surf->ofsEnd);
			
			if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
					mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
			}
			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
				ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
					mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
			}

			// change to surface identifier
			surf->ident = SF_MD4;

			// lowercase the surface name so skin compares are faster
			Q_strlwr( surf->name );
		
			// register the shaders
			sh = R_FindShader( surf->shader, LIGHTMAP_NONE, qtrue );
			if ( sh->defaultShader ) {
				surf->shaderIndex = 0;
			} else {
				surf->shaderIndex = sh->index;
			}

			// swap all the triangles
			tri = (md4Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
			for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
				LL(tri->indexes[0]);
				LL(tri->indexes[1]);
				LL(tri->indexes[2]);
			}

			// swap all the vertexes
			// FIXME
			// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
			// in for reference.
			//v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts + 12);
			v = (md4Vertex_t *) ( (byte *)surf + surf->ofsVerts);
			for ( j = 0 ; j < surf->numVerts ; j++ ) {
				v->normal[0] = LittleFloat( v->normal[0] );
				v->normal[1] = LittleFloat( v->normal[1] );
				v->normal[2] = LittleFloat( v->normal[2] );

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

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

				for ( k = 0 ; k < v->numWeights ; k++ ) {
					v->weights[k].boneIndex = LittleLong( v->weights[k].boneIndex );
					v->weights[k].boneWeight = LittleFloat( v->weights[k].boneWeight );
				   v->weights[k].offset[0] = LittleFloat( v->weights[k].offset[0] );
				   v->weights[k].offset[1] = LittleFloat( v->weights[k].offset[1] );
				   v->weights[k].offset[2] = LittleFloat( v->weights[k].offset[2] );
				}
				// FIXME
				// This makes TFC's skeletons work.  Shouldn't be necessary anymore, but left
				// in for reference.
				//v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights] + 12 );
				v = (md4Vertex_t *)( ( byte * )&v->weights[v->numWeights]);
			}

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

		// find the next LOD
		lod = (md4LOD_t *)( (byte *)lod + lod->ofsEnd );
	}

	return qtrue;
}
예제 #28
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;
}
예제 #29
0
/*
=================
R_LoadFogs

=================
*/
static	void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
    int			i;
    fog_t		*out;
    dfog_t		*fogs;
    dbrush_t 	*brushes, *brush;
    dbrushside_t	*sides;
    int			count, brushesCount, sidesCount;
    int			sideNum;
    int			planeNum;
    shader_t	*shader;
    float		d;
    int			firstSide=0;
    int			lightmaps[MAXLIGHTMAPS] = { LIGHTMAP_NONE } ;

    fogs = (dfog_t *)(fileBase + l->fileofs);
    if (l->filelen % sizeof(*fogs)) {
        ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
    }
    count = l->filelen / sizeof(*fogs);

    // create fog structres for them
    // NOTE: we allocate memory for an extra one so that the LA goggles can turn on their own fog
    s_worldData.numfogs = count + 1;
    s_worldData.fogs = (fog_t *)ri.Hunk_Alloc (( s_worldData.numfogs + 1)*sizeof(*out), qtrue );
    s_worldData.globalFog = -1;
    out = s_worldData.fogs + 1;

    if ( !count ) {
        return;
    }

    brushes = (dbrush_t *)(fileBase + brushesLump->fileofs);
    if (brushesLump->filelen % sizeof(*brushes)) {
        ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
    }
    brushesCount = brushesLump->filelen / sizeof(*brushes);

    sides = (dbrushside_t *)(fileBase + sidesLump->fileofs);
    if (sidesLump->filelen % sizeof(*sides)) {
        ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
    }
    sidesCount = sidesLump->filelen / sizeof(*sides);

    for ( i=0 ; i<count ; i++, fogs++) {
        out->originalBrushNumber = LittleLong( fogs->brushNum );
        if (out->originalBrushNumber == -1)
        {
            out->bounds[0][0] = out->bounds[0][1] = out->bounds[0][2] = MIN_WORLD_COORD;
            out->bounds[1][0] = out->bounds[1][1] = out->bounds[1][2] = MAX_WORLD_COORD;
            s_worldData.globalFog = i+1;
        }
        else
        {
            if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
                ri.Error( ERR_DROP, "fog brushNumber out of range" );
            }
            brush = brushes + out->originalBrushNumber;

            firstSide = LittleLong( brush->firstSide );

            if ( (unsigned)firstSide > sidesCount - 6 ) {
                ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
            }

            // brushes are always sorted with the axial sides first
            sideNum = firstSide + 0;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;

            sideNum = firstSide + 1;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;

            sideNum = firstSide + 2;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;

            sideNum = firstSide + 3;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;

            sideNum = firstSide + 4;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;

            sideNum = firstSide + 5;
            planeNum = LittleLong( sides[ sideNum ].planeNum );
            out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
        }

        // get information from the shader for fog parameters
        shader = R_FindShader( fogs->shader, lightmaps, stylesDefault, qtrue );

        out->parms = shader->fogParms;
        out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
                                      shader->fogParms.color[1] * tr.identityLight,
                                      shader->fogParms.color[2] * tr.identityLight, 1.0 );

        d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
        out->tcScale = 1.0 / ( d * 8 );

        // set the gradient vector
        sideNum = LittleLong( fogs->visibleSide );

        if ( sideNum == -1 ) {
            out->hasSurface = qfalse;
        } else {
            out->hasSurface = qtrue;
            planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
            VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
            out->surface[3] = -s_worldData.planes[ planeNum ].dist;
        }

        out++;
    }

    // Initialise the last fog so we can use it with the LA Goggles
    // NOTE: We are might appear to be off the end of the array, but we allocated an extra memory slot above but [purposely] didn't
    //	increment the total world numFogs to match our array size
    VectorSet(out->bounds[0], MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD);
    VectorSet(out->bounds[1], MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD);
    out->originalBrushNumber = -1;
    out->parms.color[0] = 0.0f;
    out->parms.color[1] = 0.0f;
    out->parms.color[2] = 0.0f;
    out->parms.color[3] = 0.0f;
    out->parms.depthForOpaque = 0.0f;
    out->colorInt = 0x00000000;
    out->tcScale = 0.0f;
    out->hasSurface = false;
}
예제 #30
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);
}