/** * @brief Add function for brush models * @sa LE_AddToScene */ bool LE_BrushModelAction (le_t* le, entity_t* ent) { switch (le->type) { case ET_ROTATING: case ET_DOOR: /* These cause the model to render correctly */ le->aabb.set(ent->eBox); VectorCopy(ent->origin, le->origin); VectorCopy(ent->angles, le->angles); break; case ET_DOOR_SLIDING: VectorCopy(le->origin, ent->origin); break; case ET_BREAKABLE: break; case ET_TRIGGER_RESCUE: { const int drawFlags = cl_map_draw_rescue_zone->integer; if (!((1 << cl_worldlevel->integer) & le->levelflags)) return false; ent->flags = 0; /* Do not draw anything at all, if drawFlags set to 0 */ enum { DRAW_TEXTURE = 0x1, DRAW_CIRCLES = 0x2 }; ent->model = nullptr; ent->alpha = 0.3f; VectorSet(ent->color, 0.5f, 1.0f, 0.0f); if ((drawFlags & DRAW_TEXTURE) && ent->texture == nullptr) { ent->flags = RF_BOX; ent->texture = R_FindPics("sfx/misc/rescue"); VectorSet(ent->color, 1, 1, 1); } ent->eBox.set(le->aabb); if (!(drawFlags & DRAW_CIRCLES)) return false; /* The triggerbox seems to be 'off-by-one'. The '- UNIT_SIZE' compensates for that. */ for (vec_t x = le->aabb.getMinX(); x < le->aabb.getMaxX() - UNIT_SIZE; x += UNIT_SIZE) { for (vec_t y = le->aabb.getMinY(); y < le->aabb.getMaxY() - UNIT_SIZE; y += UNIT_SIZE) { const vec3_t center = {x + UNIT_SIZE / 2, y + UNIT_SIZE / 2, le->aabb.getMinZ()}; entity_t circle(RF_PATH); VectorCopy(center, circle.origin); circle.oldorigin[0] = circle.oldorigin[1] = circle.oldorigin[2] = UNIT_SIZE / 2.0f; VectorCopy(ent->color, circle.color); circle.alpha = ent->alpha; R_AddEntity(&circle); } } /* no other rendering entities should be added for the local entity */ return false; } default: break; } return true; }
/** * @brief Binds a linked model to its parent, and copies it into the view structure. */ const r_entity_t *R_AddLinkedEntity(const r_entity_t *parent, const r_model_t *model, const char *tag_name) { if (!parent) { Com_Warn("NULL parent\n"); return NULL; } r_entity_t ent = *parent; ent.parent = parent; ent.tag_name = tag_name; ent.model = model; memset(ent.skins, 0, sizeof(ent.skins)); ent.num_skins = 0; ent.frame = ent.old_frame = 0; ent.lerp = 1.0; ent.back_lerp = 0.0; return R_AddEntity(&ent); }
/* ================= UI_PlayerSetup_Ownerdraw ================= */ static void UI_PlayerSetup_Ownerdraw( void *self ) { menuCommon_s *item = (menuCommon_s *)self; // draw the background UI_FillRect( item->x, item->y, item->width, item->height, uiPromptBgColor ); // draw the rectangle UI_DrawRectangle( item->x, item->y, item->width, item->height, uiInputFgColor ); if( !ui_showmodels->value && playerImage != 0 ) { PIC_Set( playerImage, 255, 255, 255, 255 ); PIC_Draw( item->x, item->y, item->width, item->height ); } else { R_ClearScene (); // update renderer timings uiPlayerSetup.refdef.time = gpGlobals->time; uiPlayerSetup.refdef.frametime = gpGlobals->frametime; uiPlayerSetup.ent->curstate.body = 0; // clearing body each frame // draw the player model R_AddEntity( ET_NORMAL, uiPlayerSetup.ent ); R_RenderFrame( &uiPlayerSetup.refdef ); } }
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 Adds a box that highlights the current active door */ static void LE_AddEdictHighlight (const le_t* le) { const cBspModel_t* model = LE_GetClipModel(le); entity_t ent(RF_BOX); VectorSet(ent.color, 1, 1, 1); ent.alpha = (sin(cl.time * 6.28) + 1.0) / 2.0; CalculateMinsMaxs(le->angles, model->cbmBox, le->origin, ent.eBox); R_AddEntity(&ent); }
/** * @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(); }
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ) { if( !ent || !ent->model ) return false; if( entityType == ET_TEMPENTITY ) { // copy actual origin and angles back to let StudioModelRenderer // get actual value directly from curstate VectorCopy( ent->origin, ent->curstate.origin ); VectorCopy( ent->angles, ent->curstate.angles ); } if( CL_IsInMenu( ) && ( !cl.background || ent->player )) { // menu entities ignores client filter if( !R_AddEntity( ent, entityType )) return false; } else { // check for adding this entity if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, ent->model->name )) return false; // don't add himself on firstperson if( RP_LOCALCLIENT( ent ) && !cl.thirdperson && cls.key_dest != key_menu && cl.refdef.viewentity == ( cl.playernum + 1 )) { if( gl_allow_mirrors->integer && world.has_mirrors ) { if( !R_AddEntity( ent, entityType )) return false; } // otherwise just pass to player effects like flashlight, particles etc } else if( entityType == ET_BEAM ) { CL_AddCustomBeam( ent ); return true; } else if( !R_AddEntity( ent, entityType )) { return false; } } // set actual entity type ent->curstate.entityType = entityType; // apply effects if( ent->curstate.effects & EF_BRIGHTFIELD ) CL_EntityParticles( ent ); // add in muzzleflash effect if( ent->curstate.effects & EF_MUZZLEFLASH ) { dlight_t *dl; if( ent == &clgame.viewent ) ent->curstate.effects &= ~EF_MUZZLEFLASH; dl = CL_AllocElight( 0 ); VectorCopy( ent->attachment[0], dl->origin ); dl->die = cl.time + 0.05f; dl->color.r = 255; dl->color.g = 180; dl->color.b = 64; dl->radius = 100; } // add light effect if( ent->curstate.effects & EF_LIGHT ) { dlight_t *dl = CL_AllocDlight( ent->curstate.number ); VectorCopy( ent->origin, dl->origin ); dl->die = cl.time; // die at next frame dl->color.r = 100; dl->color.g = 100; dl->color.b = 100; dl->radius = 200; CL_RocketFlare( ent->origin ); } // add dimlight if( ent->curstate.effects & EF_DIMLIGHT ) { if( entityType == ET_PLAYER ) { CL_UpdateFlashlight( ent ); } else { dlight_t *dl = CL_AllocDlight( ent->curstate.number ); VectorCopy( ent->origin, dl->origin ); dl->die = cl.time; // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; dl->radius = Com_RandomLong( 200, 230 ); } } if( ent->curstate.effects & EF_BRIGHTLIGHT ) { dlight_t *dl = CL_AllocDlight( 0 ); VectorSet( dl->origin, ent->origin[0], ent->origin[1], ent->origin[2] + 16.0f ); dl->die = cl.time + 0.001f; // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; if( entityType == ET_PLAYER ) dl->radius = 430; else dl->radius = Com_RandomLong( 400, 430 ); } if( ent->model->type == mod_studio ) { if( ent->model->flags & STUDIO_ROTATE ) ent->angles[1] = anglemod( 100.0f * cl.time ); if( ent->model->flags & STUDIO_GIB ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 2 ); else if( ent->model->flags & STUDIO_ZOMGIB ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 4 ); else if( ent->model->flags & STUDIO_TRACER ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 3 ); else if( ent->model->flags & STUDIO_TRACER2 ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 5 ); else if( ent->model->flags & STUDIO_ROCKET ) { dlight_t *dl = CL_AllocDlight( ent->curstate.number ); VectorCopy( ent->origin, dl->origin ); dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; // HACKHACK: get radius from head entity if( ent->curstate.rendermode != kRenderNormal ) dl->radius = max( 0, ent->curstate.renderamt - 55 ); else dl->radius = 200; dl->die = cl.time + 0.01f; CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 0 ); } else if( ent->model->flags & STUDIO_GRENADE ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 1 ); else if( ent->model->flags & STUDIO_TRACER3 ) CL_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 6 ); } return true; }
/** * @brief Adds an UGV to the render entities. * @param[in] le The local entity the UGV should be created from * @param[out] ent * @sa CL_AddActor */ bool CL_AddUGV (le_t * le, entity_t * ent) { entity_t add; if (!LE_IsDead(le)) { /* add weapon */ if (le->left != NONE) { OBJZERO(add); add.model = cls.modelPool[le->left]; add.tagent = R_GetFreeEntity() + 2 + (le->right != NONE); add.tagname = "tag_lweapon"; R_AddEntity(&add); } /* add weapon */ if (le->right != NONE) { OBJZERO(add); add.alpha = le->alpha; add.model = cls.modelPool[le->right]; add.tagent = R_GetFreeEntity() + 2; add.tagname = "tag_rweapon"; R_AddEntity(&add); } } /* add head */ OBJZERO(add); add.alpha = le->alpha; add.model = le->model2; add.skinnum = le->bodySkin; /** @todo */ add.tagent = R_GetFreeEntity() + 1; add.tagname = "tag_head"; R_AddEntity(&add); /* add actor special effects */ ent->flags |= RF_SHADOW; ent->flags |= RF_ACTOR; if (!LE_IsDead(le)) { if (LE_IsSelected(le)) ent->flags |= RF_SELECTED; if (le->team == cls.team) { if (le->pnum == cl.pnum) ent->flags |= RF_MEMBER; if (le->pnum != cl.pnum) ent->flags |= RF_ALLIED; } if (le->team == TEAM_CIVILIAN) ent->flags |= RF_NEUTRAL; } return true; }
/* ======================== HUD_AddEntity Return 0 to filter entity from visible list for rendering ======================== */ int HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) { if( g_fRenderInitialized ) { // use engine renderer if( gl_renderer->value == 0 ) return 1; if( ent->curstate.effects & EF_SKYCAMERA ) { // found env_sky tr.sky_camera = ent; return 0; } if( type == ET_BEAM ) { R_AddServerBeam( ent ); return 0; } if( !R_AddEntity( ent, type )) return 0; // apply effects if( ent->curstate.effects & EF_BRIGHTFIELD ) gEngfuncs.pEfxAPI->R_EntityParticles( ent ); // add in muzzleflash effect if( ent->curstate.effects & EF_MUZZLEFLASH ) { if( ent == gEngfuncs.GetViewModel( )) ent->curstate.effects &= ~EF_MUZZLEFLASH; // make sure what attachment is valid if( ent->origin != ent->attachment[0] ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocElight( 0 ); dl->origin = ent->attachment[0]; dl->die = gEngfuncs.GetClientTime() + 0.05f; dl->color.r = 255; dl->color.g = 180; dl->color.b = 64; dl->radius = 100; } } // add light effect if( ent->curstate.effects & EF_LIGHT ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->die = gEngfuncs.GetClientTime(); // die at next frame dl->color.r = 100; dl->color.g = 100; dl->color.b = 100; dl->radius = 200; gEngfuncs.pEfxAPI->R_RocketFlare( ent->origin ); } // add dimlight if( ent->curstate.effects & EF_DIMLIGHT ) { if( type == ET_PLAYER ) { HUD_UpdateFlashlight( ent ); } else { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->die = gEngfuncs.GetClientTime(); // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; dl->radius = gEngfuncs.pfnRandomLong( 200, 230 ); } } if( ent->curstate.effects & EF_BRIGHTLIGHT ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); dl->origin = ent->origin; dl->origin.z += 16; dl->die = GET_CLIENT_TIME() + 0.001f; // die at next frame dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; if( type == ET_PLAYER ) dl->radius = 430; else dl->radius = gEngfuncs.pfnRandomLong( 400, 430 ); } // projected light can be attached like as normal dlight if( ent->curstate.effects & EF_PROJECTED_LIGHT ) { plight_t *pl = CL_AllocPlight( ent->curstate.number ); float factor = 1.0f; if( ent->curstate.renderfx ) { factor = RI.lightstylevalue[ent->curstate.renderfx] * (1.0f/255.0f); } if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { pl->color.r = pl->color.g = pl->color.b = 255; } else { pl->color.r = ent->curstate.rendercolor.r; pl->color.g = ent->curstate.rendercolor.g; pl->color.b = ent->curstate.rendercolor.b; } pl->color.r *= factor; pl->color.g *= factor; pl->color.b *= factor; float radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 500; // default light radius float fov = ent->curstate.iuser2 ? ent->curstate.iuser2 : 50; pl->die = GET_CLIENT_TIME() + 0.05f; // die at next frame pl->flags = ent->curstate.iuser1; Vector origin, angles; R_GetLightVectors( ent, origin, angles ); R_SetupLightProjectionTexture( pl, ent ); R_SetupLightProjection( pl, origin, angles, radius, fov ); R_SetupLightAttenuationTexture( pl, ent->curstate.renderamt ); } // dynamic light can be attached like as normal dlight if( ent->curstate.effects & EF_DYNAMIC_LIGHT ) { if( tr.attenuationTexture3D && tr.dlightCubeTexture ) { plight_t *pl = CL_AllocPlight( ent->curstate.number ); float factor = 1.0f; if( ent->curstate.renderfx ) { factor = RI.lightstylevalue[ent->curstate.renderfx] * (1.0f/255.0f); factor = bound( 0.0f, factor, 1.0f ); } if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { pl->color.r = pl->color.g = pl->color.b = 255; } else { pl->color.r = ent->curstate.rendercolor.r; pl->color.g = ent->curstate.rendercolor.g; pl->color.b = ent->curstate.rendercolor.b; } pl->color.r *= factor; pl->color.g *= factor; pl->color.b *= factor; float radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 300; // default light radius pl->die = GET_CLIENT_TIME() + 0.05f; // die at next frame pl->flags = ent->curstate.iuser1; pl->projectionTexture = tr.dlightCubeTexture; pl->pointlight = true; Vector origin, angles; R_GetLightVectors( ent, origin, angles ); if( pl->flags & CF_NOLIGHT_IN_SOLID ) { pmtrace_t tr; // test the lights who stuck in the solid geometry gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( origin, origin, PM_STUDIO_IGNORE, -1, &tr ); // an experimental feature for point lights if( tr.allsolid ) radius = 0.0f; } if( radius != 0.0f ) { R_SetupLightProjection( pl, origin, angles, radius, 90.0f ); R_SetupLightAttenuationTexture( pl ); } else { // light in solid pl->radius = 0.0f; } } else { // cubemaps or 3d textures isn't supported: use old-style dlights dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); if( ent->curstate.rendercolor.r == 0 && ent->curstate.rendercolor.g == 0 && ent->curstate.rendercolor.b == 0 ) { dl->color.r = dl->color.g = dl->color.b = 255; } else { dl->color.r = ent->curstate.rendercolor.r; dl->color.g = ent->curstate.rendercolor.g; dl->color.b = ent->curstate.rendercolor.b; } dl->radius = ent->curstate.scale ? (ent->curstate.scale * 8.0f) : 300; // default light radius dl->die = GET_CLIENT_TIME() + 0.001f; // die at next frame dl->origin = ent->origin; } } if( ent->model->type == mod_studio ) { if (ent->model->flags & STUDIO_ROTATE) ent->angles[1] = anglemod(100 * GET_CLIENT_TIME()); if( ent->model->flags & STUDIO_GIB ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 2 ); else if( ent->model->flags & STUDIO_ZOMGIB ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 4 ); else if( ent->model->flags & STUDIO_TRACER ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 3 ); else if( ent->model->flags & STUDIO_TRACER2 ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 5 ); else if( ent->model->flags & STUDIO_ROCKET ) { dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( ent->curstate.number ); dl->origin = ent->origin; dl->color.r = 255; dl->color.g = 255; dl->color.b = 255; // HACKHACK: get radius from head entity if( ent->curstate.rendermode != kRenderNormal ) dl->radius = max( 0, ent->curstate.renderamt - 55 ); else dl->radius = 200; dl->die = GET_CLIENT_TIME() + 0.01; gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 0 ); } else if( ent->model->flags & STUDIO_GRENADE ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 1 ); else if( ent->model->flags & STUDIO_TRACER3 ) gEngfuncs.pEfxAPI->R_RocketTrail( ent->prevstate.origin, ent->curstate.origin, 6 ); } return 0; } return 1; }
/** * @sa CL_ViewRender * @sa CL_AddUGV * @sa CL_AddActor */ void LE_AddToScene (void) { for (int i = 0; i < cl.numLEs; i++) { le_t& le = cl.LEs[i]; if (le.flags & LE_REMOVE_NEXT_FRAME) { le.inuse = false; le.flags &= ~LE_REMOVE_NEXT_FRAME; } if (le.inuse && !LE_IsInvisible(&le)) { if (le.flags & LE_CHECK_LEVELFLAGS) { if (!((1 << cl_worldlevel->integer) & le.levelflags)) continue; } else if (le.flags & LE_ALWAYS_VISIBLE) { /* show them always */ } else if (le.pos[2] > cl_worldlevel->integer) continue; entity_t ent(RF_NONE); ent.alpha = le.alpha; VectorCopy(le.angles, ent.angles); ent.model = le.model1; ent.skinnum = le.bodySkin; ent.lighting = &le.lighting; switch (le.contents) { /* Only breakables do not use their origin; func_doors and func_rotating do!!! * But none of them have animations. */ case CONTENTS_SOLID: case CONTENTS_DETAIL: /* they use mins/maxs */ break; default: /* set entity values */ R_EntitySetOrigin(&ent, le.origin); VectorCopy(le.origin, ent.oldorigin); /* store animation values */ ent.as = le.as; break; } if (LE_IsOriginBrush(&le)) { ent.isOriginBrushModel = true; R_EntitySetOrigin(&ent, le.origin); VectorCopy(le.origin, ent.oldorigin); } if (LE_IsSelected(&le) && le.clientAction != nullptr) { const le_t* action = le.clientAction; if (action->inuse && action->type > ET_NULL && action->type < ET_MAX) LE_AddEdictHighlight(action); } /* call add function */ /* if it returns false, don't draw */ if (le.addFunc) if (!le.addFunc(&le, &ent)) continue; /* add it to the scene */ R_AddEntity(&ent); if (cl_le_debug->integer) CL_ParticleSpawn("cross", 0, le.origin); } } }