/** * @brief Calculates transformation matrix for the model and its tags * @note The transformation matrix is only calculated once */ static float* R_CalcTransform (entity_t* e) { transform_t* t; float* mp; float mt[16], mc[16]; /* check if this entity is already transformed */ t = &e->transform; if (t->processing) Com_Error(ERR_DROP, "Ring in entity transformations!"); if (t->done) return t->matrix; /* process this matrix */ t->processing = true; mp = nullptr; /* do parent object transformations first */ if (e->tagent) { /* tag transformation */ const model_t* model = e->tagent->model; const mAliasTagOrientation_t* current = nullptr; const mAliasTagOrientation_t* old = nullptr; const animState_t* as = &e->tagent->as; R_GetTags(model, e->tagname, as->frame, as->oldframe, ¤t, &old); if (current != nullptr && old != nullptr) { float interpolated[16]; /* parent transformation */ mp = R_CalcTransform(e->tagent); /* do interpolation */ R_InterpolateTransform(as->backlerp, model->alias.num_frames, current, old, interpolated); /* transform */ GLMatrixMultiply(mp, interpolated, mt); mp = mt; } } GLMatrixAssemble(e->origin, e->angles, mc); /* combine transformations */ if (mp) GLMatrixMultiply(mp, mc, t->matrix); else memcpy(t->matrix, mc, sizeof(float) * 16); /* matrix elements 12..14 contain (forward) translation vector, which is also the origin of model after transform */ e->distanceFromViewOrigin = VectorDist(&t->matrix[12], refdef.viewOrigin); /* we're done */ t->done = true; t->processing = false; return t->matrix; }
/** * @brief Calculates the muzzle for the current weapon the actor is shooting with * @param[in] actor The actor that is shooting. Might not be @c nullptr * @param[out] muzzle The muzzle vector to spawn the particle at. Might not be @c nullptr. This is not * modified if there is no tag for the muzzle found for the weapon or item the actor has * in the hand (also see the given shoot type) * @param[in] shootType The shoot type to determine which tag of the actor should be used * to resolve the world coordinates. Also used to determine which item (or better which hand) * should be used to resolve the actor's item. */ static void CL_ActorGetMuzzle (const le_t* actor, vec3_t muzzle, shoot_types_t shootType) { if (actor == nullptr) return; const Item* weapon; const char* tag; if (IS_SHOT_RIGHT(shootType)) { tag = "tag_rweapon"; weapon = actor->getRightHandItem(); } else { tag = "tag_lweapon"; weapon = actor->getLeftHandItem(); } if (!weapon || !weapon->def()) return; const objDef_t* od = weapon->def(); const model_t* model = cls.modelPool[od->idx]; if (!model) Com_Error(ERR_DROP, "Model for item %s is not precached", od->id); /* not every weapon has a muzzle tag assigned */ if (R_GetTagIndexByName(model, "tag_muzzle") == -1) return; float modifiedMatrix[16]; if (!R_GetTagMatrix(actor->model1, tag, actor->as.frame, modifiedMatrix)) Com_Error(ERR_DROP, "Could not find tag %s for actor model %s", tag, actor->model1->name); float mc[16]; GLMatrixAssemble(actor->origin, actor->angles, mc); float matrix[16]; GLMatrixMultiply(mc, modifiedMatrix, matrix); R_GetTagMatrix(model, "tag_muzzle", 0, modifiedMatrix); GLMatrixMultiply(matrix, modifiedMatrix, mc); muzzle[0] = mc[12]; muzzle[1] = mc[13]; muzzle[2] = mc[14]; }