예제 #1
0
static void ComputeJointMats(iqmData_t* data, int frame, int oldframe,
                             float backlerp, float* mat) {
    float*   mat1, *mat2;
    int* joint = data->jointParents;
    int i;

    if (oldframe == frame) {
        mat1 = data->poseMats + 12 * data->num_joints * frame;
        for (i = 0; i < data->num_joints; i++, joint++) {
            if (*joint >= 0) {
                Matrix34Multiply(mat + 12 * *joint,
                                 mat1 + 12 * i, mat + 12 * i);
            } else {
                Com_Memcpy(mat + 12 * i, mat1 + 12 * i, 12 * sizeof(float));
            }
        }
    } else  {
        mat1 = data->poseMats + 12 * data->num_joints * frame;
        mat2 = data->poseMats + 12 * data->num_joints * oldframe;

        for (i = 0; i < data->num_joints; i++, joint++) {
            if (*joint >= 0) {
                float tmpMat[12];
                InterpolateMatrix(mat1 + 12 * i, mat2 + 12 * i,
                                  backlerp, tmpMat);
                Matrix34Multiply(mat + 12 * *joint,
                                 tmpMat, mat + 12 * i);

            } else {
                InterpolateMatrix(mat1 + 12 * i, mat2 + 12 * i,
                                  backlerp, mat);
            }
        }
    }
}
예제 #2
0
static void BuildPoseMat( iqmData_t *iqmData, iqmData_t *skeleton, float *poseMat, int poseNum, int parent, float *mat ) {
	float tmpMat[12];

	if( parent >= 0 ) {
		Matrix34Multiply( iqmData->jointMats + 12 * parent, poseMat, tmpMat );
	} else {
		Com_Memcpy( tmpMat, poseMat, sizeof(tmpMat) );
	}

	Matrix34Multiply( tmpMat, iqmData->jointInvMats + 12 * poseNum, mat );
}
예제 #3
0
static void ComputePoseMats( iqmData_t *data, iqmData_t *skeleton, iqmData_t *oldSkeleton, int frame, int oldframe,
			      float backlerp, float *mat ) {
	float tmpMat1[12], tmpMat2[12];
	float	*mat1, *mat2;
	int	*joint = data->jointParents;
	int	i;

	if ( skeleton->num_poses == 0 ) {
		for( i = 0; i < data->num_joints; i++, joint++ ) {
			if( *joint >= 0 ) {
				Matrix34Multiply( mat + 12 * *joint,
						  identityMatrix, mat + 12*i );
			} else {
				Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) );
			}
		}
		return;
	}

	if ( oldframe == frame && skeleton == oldSkeleton ) {
		mat1 = skeleton->poseMats + 12 * skeleton->num_poses * frame;
		for( i = 0; i < skeleton->num_poses; i++, joint++ ) {
			BuildPoseMat( data, skeleton, mat1 + 12*i, i, *joint, tmpMat1 );
			if( *joint >= 0 ) {
				Matrix34Multiply( mat + 12 * *joint,
						  tmpMat1, mat + 12*i );
			} else {
				Com_Memcpy( mat + 12*i, tmpMat1, 12 * sizeof(float) );
			}
		}
	} else  {
		mat1 = skeleton->poseMats + 12 * skeleton->num_poses * frame;
		mat2 = oldSkeleton->poseMats + 12 * oldSkeleton->num_poses * oldframe;
		
		for( i = 0; i < skeleton->num_poses; i++, joint++ ) {
			BuildPoseMat( data, skeleton, mat1 + 12*i, i, *joint, tmpMat1 );
			BuildPoseMat( data, oldSkeleton, mat2 + 12*i, i, *joint, tmpMat2 );
			if( *joint >= 0 ) {
				float tmpMat[12];
				InterpolateMatrix( tmpMat1, tmpMat2,
						   backlerp, tmpMat );
				Matrix34Multiply( mat + 12 * *joint,
						  tmpMat, mat + 12*i );
				
			} else {
				InterpolateMatrix( tmpMat1, tmpMat2,
						   backlerp, mat );
			}
		}
	}
}
예제 #4
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;
}