static void LM_AddToSceneOrder (bool parents) { for (int i = 0; i < cl.numLMs; i++) { localModel_t& lm = cl.LMs[i]; if (!lm.inuse) continue; /* check for visibility */ if (!((1 << cl_worldlevel->integer) & lm.levelflags)) continue; /* if we want to render the parents and this is a child (has a parent assigned) * then skip it */ if (parents && lm.parent) continue; /* if we want to render the children and this is a parent (no further parent * assigned), then skip it. */ if (!parents && lm.parent == nullptr) continue; /* set entity values */ entity_t ent(RF_NONE); assert(lm.model); ent.model = lm.model; ent.skinnum = lm.skin; ent.lighting = &lm.lighting; ent.setScale(lm.scale); if (lm.parent) { /** @todo what if the tagent is not rendered due to different level flags? */ ent.tagent = R_GetEntity(lm.parent->renderEntityNum); if (ent.tagent == nullptr) Com_Error(ERR_DROP, "Invalid parent entity num for local model (%s/%s): %i", lm.model->name, lm.id, lm.parent->renderEntityNum); ent.tagname = lm.tagname; } else { R_EntitySetOrigin(&ent, lm.origin); VectorCopy(lm.origin, ent.oldorigin); VectorCopy(lm.angles, ent.angles); if (lm.animname[0] != '\0') { ent.as = lm.as; /* do animation */ R_AnimRun(&lm.as, ent.model, cls.frametime * 1000); } else { ent.as.frame = lm.frame; } } /* renderflags like RF_PULSE */ ent.flags = lm.renderFlags; /* add it to the scene */ lm.renderEntityNum = R_AddEntity(&ent); } }
/** * @brief Calls the le think function and updates the animation. The animation updated even if the * particular local entity is invisible for the client. This ensures, that an animation is always * lerped correctly and won't magically start again once the local entity gets visible again. * @sa LET_StartIdle * @sa LET_PathMove * @sa LET_StartPathMove * @sa LET_Projectile */ void LE_Think (void) { if (cls.state != ca_active) return; le_t* le = nullptr; while ((le = LE_GetNext(le))) { LE_ExecuteThink(le); /* do animation - even for invisible entities */ R_AnimRun(&le->as, le->model1, cls.frametime * 1000); } }
/** * @sa CL_Sequence2D * @sa CL_ViewRender * @sa CL_SequenceEnd_f * @sa UI_PopWindow * @sa CL_SequenceFindEnt */ static void SEQ_Render3D (sequenceContext_t *context) { entity_t ent; seqEnt_t *se; int i; if (context->numEnts == 0) return; /* set camera */ SEQ_SetCamera(context); refdef.numEntities = 0; refdef.mapTiles = cl.mapTiles; /* render sequence */ for (i = 0, se = context->ents; i < context->numEnts; i++, se++) { if (!se->inuse) continue; /* advance in time */ VectorMA(se->origin, cls.frametime, se->speed, se->origin); VectorMA(se->angles, cls.frametime, se->omega, se->angles); R_AnimRun(&se->as, se->model, context->animspeed * cls.frametime); /* add to scene */ OBJZERO(ent); ent.model = se->model; ent.skinnum = se->skin; ent.as = se->as; ent.alpha = se->alpha; R_EntitySetOrigin(&ent, se->origin); VectorCopy(se->origin, ent.oldorigin); VectorCopy(se->angles, ent.angles); if (se->parent && se->tag) { seqEnt_t *parent; parent = SEQ_FindEnt(context, se->parent); if (parent) ent.tagent = parent->ep; ent.tagname = se->tag; } /* add to render list */ se->ep = R_GetFreeEntity(); R_AddEntity(&ent); } refdef.rendererFlags |= RDF_NOWORLDMODEL; /* use a relative fixed size */ viddef.x = context->pos[0]; viddef.y = context->pos[1]; viddef.viewWidth = context->size[0]; viddef.viewHeight = context->size[1]; /* update refdef */ CL_ViewUpdateRenderData(); /** @todo Models are not at the right position (relative to the node position). Maybe R_SetupFrustum erase matrix. Not a trivialous task. */ /* render the world */ R_PushMatrix(); R_RenderFrame(); R_PopMatrix(); }
/** * @todo need to merge UI model case, and the common case (looks to be a copy-pasted code) */ void UI_DrawModelNode (uiNode_t* node, const char* source) { modelInfo_t mi; uiModel_t* model; vec3_t nodeorigin; vec2_t screenPos; assert(UI_NodeInstanceOf(node, "model")); /**< We use model extradata */ if (!source || source[0] == '\0') return; model = UI_GetUIModel(source); /* direct model name - no UI model definition */ if (!model) { /* prevent the searching for a model def in the next frame */ mi.model = R_FindModel(source); mi.name = source; if (!mi.model) { Com_Printf("Could not find model '%s'\n", source); return; } } /* compute the absolute origin ('origin' property is relative to the node center) */ UI_GetNodeScreenPos(node, screenPos); UI_GetNodeAbsPos(node, nodeorigin); R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->box.size[0], node->box.size[1]); if (EXTRADATA(node).clipOverflow) { UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]); } nodeorigin[0] += node->box.size[0] / 2 + EXTRADATA(node).origin[0]; nodeorigin[1] += node->box.size[1] / 2 + EXTRADATA(node).origin[1]; nodeorigin[2] = EXTRADATA(node).origin[2]; VectorMA(EXTRADATA(node).angles, cls.frametime, EXTRADATA(node).omega, EXTRADATA(node).angles); mi.origin = nodeorigin; mi.angles = EXTRADATA(node).angles; mi.scale = EXTRADATA(node).scale; mi.center = nullVector; mi.color = node->color; mi.mesh = 0; /* special case to draw models with UI model */ if (model) { UI_DrawModelNodeWithUIModel(node, source, &mi, model); if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); return; } /* if the node is linked to a parent, the parent will display it */ if (EXTRADATA(node).tag) { if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); return; } /* autoscale? */ if (EXTRADATA(node).autoscale) { vec3_t autoScale; vec3_t autoCenter; const vec2_t size = {node->box.size[0] - node->padding, node->box.size[1] - node->padding}; R_ModelAutoScale(size, &mi, autoScale, autoCenter); } /* no animation */ mi.frame = 0; mi.oldframe = 0; mi.backlerp = 0; /* get skin */ if (EXTRADATA(node).skin && *EXTRADATA(node).skin) mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin)); else mi.skin = 0; /* do animations */ if (EXTRADATA(node).animation && *EXTRADATA(node).animation) { const char* ref; ref = UI_GetReferenceString(node, EXTRADATA(node).animation); /* check whether the cvar value changed */ if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) { Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE); /* model has changed but mem is already reserved in pool */ Mem_Free(EXTRADATA(node).animationState); EXTRADATA(node).animationState = nullptr; } animState_t* as = EXTRADATA(node).animationState; if (!as) { as = Mem_PoolAllocType(animState_t, cl_genericPool); if (!as) Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref); R_AnimChange(as, mi.model, ref); EXTRADATA(node).animationState = as; } else { const char* anim; /* change anim if needed */ anim = R_AnimGetName(as, mi.model); if (anim && !Q_streq(anim, ref)) R_AnimChange(as, mi.model, ref); R_AnimRun(as, mi.model, cls.frametime * 1000); } mi.frame = as->frame; mi.oldframe = as->oldframe; mi.backlerp = as->backlerp; } /* draw the main model on the node */ R_DrawModelDirect(&mi, nullptr, nullptr); /* draw all children */ if (node->firstChild) { uiNode_t* child; modelInfo_t pmi = mi; for (child = node->firstChild; child; child = child->next) { const char* tag; char childSource[MAX_VAR]; const char* childRef; /* skip non "model" nodes */ if (child->behaviour != node->behaviour) continue; /* skip invisible child */ if (child->invis || !UI_CheckVisibility(child)) continue; OBJZERO(mi); mi.angles = EXTRADATA(child).angles; mi.scale = EXTRADATA(child).scale; mi.center = nullVector; mi.origin = EXTRADATA(child).origin; mi.color = pmi.color; /* get the anchor name to link the model into the parent */ tag = EXTRADATA(child).tag; /* init model name */ childRef = UI_GetReferenceString(child, EXTRADATA(child).model); if (Q_strnull(childRef)) childSource[0] = '\0'; else Q_strncpyz(childSource, childRef, sizeof(childSource)); mi.model = R_FindModel(childSource); mi.name = childSource; /* init skin */ if (EXTRADATA(child).skin && *EXTRADATA(child).skin) mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin)); else mi.skin = 0; R_DrawModelDirect(&mi, &pmi, tag); } } if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); }
/** * @brief Draw a model using UI model definition */ static void UI_DrawModelNodeWithUIModel (uiNode_t* node, const char* source, modelInfo_t* mi, uiModel_t* model) { bool autoScaleComputed = false; vec3_t autoScale; vec3_t autoCenter; while (model) { /* no animation */ mi->frame = 0; mi->oldframe = 0; mi->backlerp = 0; assert(model->model); mi->model = R_FindModel(model->model); if (!mi->model) { model = model->next; continue; } mi->skin = model->skin; mi->name = model->model; /* set mi pointers to model */ mi->origin = model->origin; mi->angles = model->angles; mi->center = model->center; mi->color = model->color; mi->scale = model->scale; if (model->tag && model->parent) { /* tag and parent defined */ uiModel_t* parentModel; modelInfo_t pmi; vec3_t pmiorigin; animState_t* as; /* place this model part on an already existing model tag */ parentModel = UI_GetUIModel(model->parent); if (!parentModel) { Com_Printf("UI Model: Could not get the model '%s'\n", model->parent); break; } pmi.model = R_FindModel(parentModel->model); if (!pmi.model) { Com_Printf("UI Model: Could not get the model '%s'\n", parentModel->model); break; } pmi.name = parentModel->model; pmi.origin = pmiorigin; pmi.angles = parentModel->angles; pmi.scale = parentModel->scale; pmi.center = parentModel->center; pmi.color = parentModel->color; pmi.origin[0] = parentModel->origin[0] + mi->origin[0]; pmi.origin[1] = parentModel->origin[1] + mi->origin[1]; pmi.origin[2] = parentModel->origin[2]; /* don't count window offset twice for tagged models */ mi->origin[0] -= node->root->box.pos[0]; mi->origin[1] -= node->root->box.pos[1]; /* autoscale? */ if (EXTRADATA(node).autoscale) { if (!autoScaleComputed) Sys_Error("Wrong order of model nodes - the tag and parent model node must be after the base model node"); pmi.scale = autoScale; pmi.center = autoCenter; } as = &parentModel->animState; pmi.frame = as->frame; pmi.oldframe = as->oldframe; pmi.backlerp = as->backlerp; R_DrawModelDirect(mi, &pmi, model->tag); } else { /* no tag and no parent means - base model or single model */ const char* ref; UI_InitModelInfoView(node, mi, model); Vector4Copy(node->color, mi->color); /* compute the scale and center for the first model. * it think its the bigger of composite models. * All next elements use the same result */ if (EXTRADATA(node).autoscale) { if (!autoScaleComputed) { vec2_t size; size[0] = node->box.size[0] - node->padding; size[1] = node->box.size[1] - node->padding; R_ModelAutoScale(size, mi, autoScale, autoCenter); autoScaleComputed = true; } else { mi->scale = autoScale; mi->center = autoCenter; } } /* get the animation given by node properties */ if (EXTRADATA(node).animation && *EXTRADATA(node).animation) { ref = UI_GetReferenceString(node, EXTRADATA(node).animation); /* otherwise use the standard animation from UI model definition */ } else ref = model->anim; /* only base models have animations */ if (ref && *ref) { animState_t* as = &model->animState; const char* anim = R_AnimGetName(as, mi->model); /* initial animation or animation change */ if (anim == nullptr || !Q_streq(anim, ref)) R_AnimChange(as, mi->model, ref); else R_AnimRun(as, mi->model, cls.frametime * 1000); mi->frame = as->frame; mi->oldframe = as->oldframe; mi->backlerp = as->backlerp; } R_DrawModelDirect(mi, nullptr, nullptr); } /* next */ model = model->next; } }