void RF_ResetScissor( void ) { rrf.frame->ResetScissor( rrf.frame ); Vector4Set( rrf.scissor, 0, 0, glConfig.width, glConfig.height ); }
/* ============== CG_DrawCursorHints cg_cursorHints.integer == 0: no hints 1: sin size pulse 2: one way size pulse 3: alpha pulse 4+: static image ============== */ void CG_DrawCursorhint(rectDef_t *rect) { float *color; qhandle_t icon, icon2 = 0; float scale, halfscale; //qboolean redbar = qfalse; qboolean yellowbar = qfalse; if(!cg_cursorHints.integer) return; CG_CheckForCursorHints(); switch(cg.cursorHintIcon) { case HINT_NONE: case HINT_FORCENONE: icon = 0; break; case HINT_DOOR: icon = cgs.media.doorHintShader; break; case HINT_DOOR_ROTATING: icon = cgs.media.doorRotateHintShader; break; case HINT_DOOR_LOCKED: icon = cgs.media.doorLockHintShader; break; case HINT_DOOR_ROTATING_LOCKED: icon = cgs.media.doorRotateLockHintShader; break; case HINT_MG42: icon = cgs.media.mg42HintShader; break; case HINT_BREAKABLE: icon = cgs.media.breakableHintShader; break; case HINT_BREAKABLE_DYNAMITE: icon = cgs.media.dynamiteHintShader; break; case HINT_TANK: icon = cgs.media.tankHintShader; break; case HINT_SATCHELCHARGE: icon = cgs.media.satchelchargeHintShader; break; case HINT_CONSTRUCTIBLE: icon = cgs.media.buildHintShader; break; case HINT_UNIFORM: icon = cgs.media.uniformHintShader; break; case HINT_LANDMINE: icon = cgs.media.landmineHintShader; break; case HINT_CHAIR: icon = cgs.media.notUsableHintShader; // only show 'pickupable' if you're not armed, or are armed with a single handed weapon // rain - WEAPS_ONE_HANDED isn't valid anymore, because // WP_SILENCED_COLT uses a bit >31 (and, therefore, is too large // to be shifted in the way WEAPS_ONE_HANDED does on a 32-bit // system.) If you want to use HINT_CHAIR, you'll need to fix // this. #if 0 if( !(cg.predictedPlayerState.weapon) || WEAPS_ONE_HANDED & (1<<(cg.predictedPlayerState.weapon)) ) { icon = cgs.media.chairHintShader; } #endif break; case HINT_ALARM: icon = cgs.media.alarmHintShader; break; case HINT_HEALTH: icon = cgs.media.healthHintShader; break; case HINT_TREASURE: icon = cgs.media.treasureHintShader; break; case HINT_KNIFE: icon = cgs.media.knifeHintShader; break; case HINT_LADDER: icon = cgs.media.ladderHintShader; break; case HINT_BUTTON: icon = cgs.media.buttonHintShader; break; case HINT_WATER: icon = cgs.media.waterHintShader; break; case HINT_CAUTION: icon = cgs.media.cautionHintShader; break; case HINT_DANGER: icon = cgs.media.dangerHintShader; break; case HINT_SECRET: icon = cgs.media.secretHintShader; break; case HINT_QUESTION: icon = cgs.media.qeustionHintShader; break; case HINT_EXCLAMATION: icon = cgs.media.exclamationHintShader; break; case HINT_CLIPBOARD: icon = cgs.media.clipboardHintShader; break; case HINT_WEAPON: icon = cgs.media.weaponHintShader; break; case HINT_AMMO: icon = cgs.media.ammoHintShader; break; case HINT_ARMOR: icon = cgs.media.armorHintShader; break; case HINT_POWERUP: icon = cgs.media.powerupHintShader; break; case HINT_HOLDABLE: icon = cgs.media.holdableHintShader; break; case HINT_INVENTORY: icon = cgs.media.inventoryHintShader; break; case HINT_PLYR_FRIEND: icon = cgs.media.hintPlrFriendShader; break; case HINT_PLYR_NEUTRAL: icon = cgs.media.hintPlrNeutralShader; break; case HINT_PLYR_ENEMY: icon = cgs.media.hintPlrEnemyShader; break; case HINT_PLYR_UNKNOWN: icon = cgs.media.hintPlrUnknownShader; break; // DHM - Nerve :: multiplayer hints case HINT_BUILD: icon = cgs.media.buildHintShader; break; case HINT_DISARM: icon = cgs.media.disarmHintShader; break; case HINT_REVIVE: icon = cgs.media.reviveHintShader; break; case HINT_DYNAMITE: icon = cgs.media.dynamiteHintShader; break; // dhm - end // Mad Doc - TDF case HINT_LOCKPICK: icon = cgs.media.doorLockHintShader; // TAT 1/30/2003 - use the locked door hint cursor yellowbar = qtrue; // draw the status bar in yellow so it shows up better break; case HINT_ACTIVATE: case HINT_PLAYER: default: icon = cgs.media.usableHintShader; break; } if(!icon) return; // color color = CG_FadeColor( cg.cursorHintTime, cg.cursorHintFade ); if ( !color ) { trap_R_SetColor( NULL ); return; } if(cg_cursorHints.integer == 3) { color[3] *= 0.5+0.5*sin((float)cg.time/150.0); } // size if(cg_cursorHints.integer >= 3) { // no size pulsing scale = halfscale = 0; } else { if(cg_cursorHints.integer == 2) scale = (float)((cg.cursorHintTime)%1000) / 100.0f; // one way size pulse else scale = CURSORHINT_SCALE * (0.5+0.5*sin((float)cg.time/150.0)); // sin pulse halfscale = scale * 0.5f; } // set color and draw the hint trap_R_SetColor( color ); CG_DrawPic( rect->x - halfscale, rect->y - halfscale, rect->w + scale, rect->h + scale, icon ); if( icon2 ) { CG_DrawPic( rect->x - halfscale, rect->y - halfscale, rect->w + scale, rect->h + scale, icon2 ); } trap_R_SetColor( NULL ); // draw status bar under the cursor hint if(cg.cursorHintValue) { if (yellowbar) { Vector4Set(color, 1, 1, 0, 1.0f); } else { Vector4Set(color, 0, 0, 1, 0.5f); } CG_FilledBar(rect->x, rect->y + rect->h + 4, rect->w, 8, color, NULL, NULL, (float)cg.cursorHintValue/255.0f, 0); } }
/** * @brief Enable or disable realtime dynamic lighting for models * @param lights The lights to enable * @param numLights The amount of lights in the given lights list * @param inShadow Whether model is shadowed from the sun * @param enable Whether to turn realtime lighting on or off */ void R_EnableModelLights (const light_t **lights, int numLights, bool inShadow, bool enable) { int i; int maxLights = r_dynamic_lights->integer; vec4_t blackColor = {0.0, 0.0, 0.0, 1.0}; const vec4_t whiteColor = {1.0, 1.0, 1.0, 1.0}; const vec4_t defaultLight0Position = {0.0, 0.0, 1.0, 0.0}; vec3_t lightPositions[MAX_GL_LIGHTS]; vec4_t lightParams[MAX_GL_LIGHTS]; if (r_programs->integer == 0) { /* Fixed function path renderer got only the sunlight */ /* Setup OpenGL light #0 to act as a sun and environment light */ glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); #ifndef GL_VERSION_ES_CM_1_0 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); #endif glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0); glLightfv(GL_LIGHT0, GL_SPECULAR, blackColor); glLightfv(GL_LIGHT0, GL_AMBIENT, refdef.modelAmbientColor); glLightfv(GL_LIGHT0, GL_POSITION, refdef.sunVector); if (enable) { if (inShadow) { /* ambient only */ glLightfv(GL_LIGHT0, GL_DIFFUSE, blackColor); } else { /* Full sunlight */ glLightfv(GL_LIGHT0, GL_DIFFUSE, refdef.sunDiffuseColor); } } else { /* restore the default OpenGL state */ glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glLightfv(GL_LIGHT0, GL_POSITION, defaultLight0Position); glLightfv(GL_LIGHT0, GL_AMBIENT, blackColor); glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteColor); glLightfv(GL_LIGHT0, GL_SPECULAR, whiteColor); } return; } assert(numLights <= MAX_GL_LIGHTS); if (!enable || !r_state.lighting_enabled) { if (r_state.dynamic_lighting_enabled) { R_DisableAttribute("TANGENTS"); /** @todo is it a good idea? */ if (maxLights) { for (i = 0; i < maxLights; i++) Vector4Set(lightParams[i], 0, 0, 0, 1); /* Send light data to shaders */ R_ProgramParameter3fvs("LIGHTPOSITIONS", maxLights, (GLfloat *)lightPositions); R_ProgramParameter4fvs("LIGHTPARAMS", maxLights, (GLfloat *)lightParams); } } r_state.dynamic_lighting_enabled = false; return; } /** @todo assert? */ if (numLights > maxLights) numLights = maxLights; r_state.dynamic_lighting_enabled = true; R_EnableAttribute("TANGENTS"); R_UseMaterial(&defaultMaterial); R_ProgramParameter3fv("AMBIENT", refdef.modelAmbientColor); if (inShadow) { R_ProgramParameter3fv("SUNCOLOR", blackColor); } else { R_ProgramParameter3fv("SUNCOLOR", refdef.sunDiffuseColor); } if (!maxLights) return; for (i = 0; i < numLights; i++) { const light_t *light = lights[i]; GLPositionTransform(r_locals.world_matrix, light->origin, lightPositions[i]); VectorCopy(light->color, lightParams[i]); lightParams[i][3] = 16.0 / (light->radius * light->radius); } /* if there aren't enough active lights, turn off the rest */ for (; i < maxLights; i++) Vector4Set(lightParams[i], 0, 0, 0, 1); /* Send light data to shaders */ R_ProgramParameter3fvs("LIGHTPOSITIONS", maxLights, (GLfloat *)lightPositions); R_ProgramParameter4fvs("LIGHTPARAMS", maxLights, (GLfloat *)lightParams); }
/* * R_DrawAliasSurf * * Interpolates between two frames and origins */ qboolean R_DrawAliasSurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceAlias_t *drawSurf ) { int i; int framenum, oldframenum; float backv[3], frontv[3]; vec3_t normal, oldnormal; qboolean calcVerts, calcNormals, calcSTVectors; vec3_t move; const maliasframe_t *frame, *oldframe; const maliasvertex_t *v, *ov; float backlerp = e->backlerp; const maliasmodel_t *model = ( const maliasmodel_t * )drawSurf->model->extradata; const maliasmesh_t *aliasmesh = drawSurf->mesh; vattribmask_t vattribs; // see what vertex attribs backend needs vattribs = RB_GetVertexAttribs(); framenum = bound( e->frame, 0, model->numframes ); oldframenum = bound( e->oldframe, 0, model->numframes ); frame = model->frames + framenum; oldframe = model->frames + oldframenum; for( i = 0; i < 3; i++ ) move[i] = frame->translate[i] + ( oldframe->translate[i] - frame->translate[i] ) * backlerp; // based on backend's needs calcNormals = ( ( ( vattribs & VATTRIB_NORMAL_BIT ) != 0 ) && ( ( framenum != 0 ) || ( oldframenum != 0 ) ) ) ? qtrue : qfalse; calcSTVectors = ( ( ( vattribs & VATTRIB_SVECTOR_BIT ) != 0 ) && calcNormals ) ? qtrue : qfalse; if( aliasmesh->vbo != NULL && !framenum && !oldframenum ) { RB_BindVBO( aliasmesh->vbo->index, GL_TRIANGLES ); RB_DrawElements( 0, aliasmesh->numverts, 0, aliasmesh->numtris * 3 ); } else { mesh_t *rb_mesh; vec4_t *inVertsArray; vec4_t *inNormalsArray; vec4_t *inSVectorsArray; RB_BindVBO( RB_VBO_STREAM, GL_TRIANGLES ); rb_mesh = RB_MapBatchMesh( aliasmesh->numverts, aliasmesh->numtris * 3 ); if( !rb_mesh ) { ri.Com_DPrintf( S_COLOR_YELLOW "R_DrawAliasSurf: RB_MapBatchMesh returned NULL for (%s)(%s)", drawSurf->model->name, aliasmesh->name ); return qfalse; } inVertsArray = rb_mesh->xyzArray; inNormalsArray = rb_mesh->normalsArray; inSVectorsArray = rb_mesh->sVectorsArray; if( !framenum && !oldframenum ) { calcVerts = qfalse; if( calcNormals ) { v = aliasmesh->vertexes; for( i = 0; i < aliasmesh->numverts; i++, v++ ) R_LatLongToNorm( v->latlong, inNormalsArray[i] ); } } else if( framenum == oldframenum ) { calcVerts = qtrue; for( i = 0; i < 3; i++ ) frontv[i] = frame->scale[i]; v = aliasmesh->vertexes + framenum * aliasmesh->numverts; for( i = 0; i < aliasmesh->numverts; i++, v++ ) { Vector4Set( inVertsArray[i], move[0] + v->point[0]*frontv[0], move[1] + v->point[1]*frontv[1], move[2] + v->point[2]*frontv[2], 1); if( calcNormals ) R_LatLongToNorm4( v->latlong, inNormalsArray[i] ); } } else { calcVerts = qtrue; for( i = 0; i < 3; i++ ) { backv[i] = backlerp * oldframe->scale[i]; frontv[i] = ( 1.0f - backlerp ) * frame->scale[i]; } v = aliasmesh->vertexes + framenum * aliasmesh->numverts; ov = aliasmesh->vertexes + oldframenum * aliasmesh->numverts; for( i = 0; i < aliasmesh->numverts; i++, v++, ov++ ) { VectorSet( inVertsArray[i], move[0] + v->point[0]*frontv[0] + ov->point[0]*backv[0], move[1] + v->point[1]*frontv[1] + ov->point[1]*backv[1], move[2] + v->point[2]*frontv[2] + ov->point[2]*backv[2] ); if( calcNormals ) { R_LatLongToNorm( v->latlong, normal ); R_LatLongToNorm( ov->latlong, oldnormal ); VectorSet( inNormalsArray[i], normal[0] + ( oldnormal[0] - normal[0] ) * backlerp, normal[1] + ( oldnormal[1] - normal[1] ) * backlerp, normal[2] + ( oldnormal[2] - normal[2] ) * backlerp ); } } } if( calcSTVectors ) R_BuildTangentVectors( aliasmesh->numverts, inVertsArray, inNormalsArray, aliasmesh->stArray, aliasmesh->numtris, aliasmesh->elems, inSVectorsArray ); if( !calcVerts ) { rb_mesh->xyzArray = aliasmesh->xyzArray; } rb_mesh->elems = aliasmesh->elems; rb_mesh->numElems = aliasmesh->numtris * 3; rb_mesh->numVerts = aliasmesh->numverts; rb_mesh->stArray = aliasmesh->stArray; if( !calcNormals ) { rb_mesh->normalsArray = aliasmesh->normalsArray; } if( !calcSTVectors ) { rb_mesh->sVectorsArray = aliasmesh->sVectorsArray; } RB_UploadMesh( rb_mesh ); RB_EndBatch(); } return qfalse; }
/** * @brief parses the models.ufo and all files where UI models (menu_model) are defined * @sa CL_ParseClientData */ bool UI_ParseUIModel (const char *name, const char **text) { uiModel_t *model; const char *token; int i; const value_t *v = nullptr; const char *errhead = "UI_ParseUIModel: unexpected end of file (names "; /* search for a UI models with same name */ for (i = 0; i < ui_global.numModels; i++) if (Q_streq(ui_global.models[i].id, name)) { Com_Printf("UI_ParseUIModel: menu_model \"%s\" with same name found, second ignored\n", name); return false; } if (ui_global.numModels >= UI_MAX_MODELS) { Com_Printf("UI_ParseUIModel: Max UI models reached\n"); return false; } /* initialize the model */ model = &ui_global.models[ui_global.numModels]; OBJZERO(*model); Vector4Set(model->color, 1, 1, 1, 1); model->id = Mem_PoolStrDup(name, ui_sysPool, 0); Com_DPrintf(DEBUG_CLIENT, "Found UI model %s (%i)\n", model->id, ui_global.numModels); /* get it's body */ token = Com_Parse(text); if (!*text || token[0] != '{') { Com_Printf("UI_ParseUIModel: Model \"%s\" without body ignored\n", model->id); return false; } ui_global.numModels++; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) return false; if (token[0] == '}') break; v = UI_FindPropertyByName(uiModelProperties, token); if (!v) { Com_Printf("UI_ParseUIModel: unknown token \"%s\" ignored (UI model %s)\n", token, name); return false; } if (v->type == V_nullptr) { if (Q_streq(v->string, "need")) { token = Com_EParse(text, errhead, name); if (!*text) return false; if (model->next != nullptr) Sys_Error("UI_ParseUIModel: second 'need' token found in model %s", name); model->next = UI_GetUIModel(token); if (!model->next) Com_Printf("Could not find UI model %s", token); } } else { token = Com_EParse(text, errhead, name); if (!*text) return false; switch (v->type) { case V_HUNK_STRING: Mem_PoolStrDupTo(token, &Com_GetValue<char*>(model, v), ui_sysPool, 0); break; default: Com_EParseValue(model, token, v->type, v->ofs, v->size); break; } } } while (*text); return true; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); if ( !tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error(errorParm_t::ERR_DROP, "R_RenderScene: NULL worldmodel" ); } tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[ 0 ], tr.refdef.viewaxis[ 0 ] ); VectorCopy( fd->viewaxis[ 1 ], tr.refdef.viewaxis[ 1 ] ); VectorCopy( fd->viewaxis[ 2 ], tr.refdef.viewaxis[ 2 ] ); VectorCopy( fd->blurVec, tr.refdef.blurVec ); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = false; if ( !( tr.refdef.rdflags & RDF_NOWORLDMODEL ) && !( ( tr.refdef.rdflags & RDF_SKYBOXPORTAL ) && tr.world->numSkyNodes > 0 ) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for ( i = 0; i < MAX_MAP_AREA_BYTES / 4; i++ ) { areaDiff |= ( ( int * ) tr.refdef.areamask ) [ i ] ^ ( ( int * ) fd->areamask ) [ i ]; ( ( int * ) tr.refdef.areamask ) [ i ] = ( ( int * ) fd->areamask ) [ i ]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = true; } } R_AddWorldLightsToScene(); // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData[ tr.smpFrame ]->drawSurfs; tr.refdef.numInteractions = r_firstSceneInteraction; tr.refdef.interactions = backEndData[ tr.smpFrame ]->interactions; tr.refdef.numEntities = r_numEntities - r_firstSceneEntity; tr.refdef.entities = &backEndData[ tr.smpFrame ]->entities[ r_firstSceneEntity ]; tr.refdef.numLights = r_numLights - r_firstSceneLight; tr.refdef.lights = &backEndData[ tr.smpFrame ]->lights[ r_firstSceneLight ]; tr.refdef.numPolys = r_numPolys - r_firstScenePoly; tr.refdef.polys = &backEndData[ tr.smpFrame ]->polys[ r_firstScenePoly ]; tr.refdef.numPolybuffers = r_numPolybuffers - r_firstScenePolybuffer; tr.refdef.polybuffers = &backEndData[ tr.smpFrame ]->polybuffers[ r_firstScenePolybuffer ]; tr.refdef.numDecalProjectors = r_numDecalProjectors - r_firstSceneDecalProjector; tr.refdef.decalProjectors = &backEndData[ tr.smpFrame ]->decalProjectors[ r_firstSceneDecalProjector ]; tr.refdef.numDecals = r_numDecals - r_firstSceneDecal; tr.refdef.decals = &backEndData[ tr.smpFrame ]->decals[ r_firstSceneDecal ]; tr.refdef.numVisTests = r_numVisTests - r_firstSceneVisTest; tr.refdef.visTests = &backEndData[ tr.smpFrame ]->visTests[ r_firstSceneVisTest ]; // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // Tr3B: a scene can have multiple views caused by mirrors or portals // the number of views is restricted so we can use hardware occlusion queries // and put them into the BSP nodes for each view tr.viewCount = -1; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); if ( tr.refdef.pixelTarget == nullptr ) { parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); } else { //Driver bug, if we try and do pixel target work along the top edge of a window //we can end up capturing part of the status bar. (see screenshot corruption..) //Soooo.. use the middle. parms.viewportX = glConfig.vidWidth / 2; parms.viewportY = glConfig.vidHeight / 2; } parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; Vector4Set( parms.viewportVerts[ 0 ], parms.viewportX, parms.viewportY, 0, 1 ); Vector4Set( parms.viewportVerts[ 1 ], parms.viewportX + parms.viewportWidth, parms.viewportY, 0, 1 ); Vector4Set( parms.viewportVerts[ 2 ], parms.viewportX + parms.viewportWidth, parms.viewportY + parms.viewportHeight, 0, 1 ); Vector4Set( parms.viewportVerts[ 3 ], parms.viewportX, parms.viewportY + parms.viewportHeight, 0, 1 ); parms.isPortal = false; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; VectorCopy( fd->vieworg, parms.orientation.origin ); VectorCopy( fd->viewaxis[ 0 ], parms.orientation.axis[ 0 ] ); VectorCopy( fd->viewaxis[ 1 ], parms.orientation.axis[ 1 ] ); VectorCopy( fd->viewaxis[ 2 ], parms.orientation.axis[ 2 ] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); Vector4Copy( fd->gradingWeights, parms.gradingWeights ); R_RenderView( &parms ); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneInteraction = tr.refdef.numInteractions; r_firstSceneEntity = r_numEntities; r_firstSceneLight = r_numLights; r_firstScenePoly = r_numPolys; r_firstScenePolybuffer = r_numPolybuffers; r_firstSceneVisTest = r_numVisTests; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/** * @brief Spawn a new particle to the map * @param[in] name The id of the particle (see ptl_*.ufo script files in base/ufos) * @param[in] levelFlags Show at which levels * @param[in] s starting/location vector * @param[in] v velocity vector * @param[in] a acceleration vector * @sa CL_ParticleFree * @sa CL_ViewUpdateRenderData * @sa R_DrawParticles */ ptl_t* CL_ParticleSpawn (const char* name, int levelFlags, const vec3_t s, const vec3_t v, const vec3_t a) { int i; if (Q_strnull(name)) return nullptr; /* find the particle definition */ ptlDef_t* pd = CL_ParticleGet(name); if (pd == nullptr) { Com_Printf("Particle definition \"%s\" not found\n", name); return nullptr; } /* add the particle */ for (i = 0; i < r_numParticles; i++) if (!r_particleArray[i].inuse) break; if (i == r_numParticles) { if (r_numParticles < MAX_PTLS) r_numParticles++; else { Com_DPrintf(DEBUG_CLIENT, "Too many particles (don't add %s) - exceeded %i\n", name, MAX_PTLS); return nullptr; } } /* allocate particle */ ptl_t* p = &r_particleArray[i]; OBJZERO(*p); /* set basic values */ p->inuse = true; p->startTime = cl.time; p->ctrl = pd; Vector4Set(p->color, 1.0f, 1.0f, 1.0f, 1.0f); p->pic = nullptr; p->model = nullptr; /* copy location */ if (s) { VectorCopy(s, p->origin); VectorCopy(s, p->s); } /* copy velocity */ if (v) VectorCopy(v, p->v); /* copy acceleration */ if (a) VectorCopy(a, p->a); /* copy levelflags */ p->levelFlags = levelFlags; /* run init function */ CL_ParticleFunction(p, pd->init); if (p->inuse && !p->tps && !p->life) { Com_DPrintf(DEBUG_CLIENT, "Particle %s does not have a tps nor a life set - this is only valid for projectile particles\n", name); p->tps = 1; } return p; }
static void UI_TodoNodeLoading (uiNode_t *node) { Vector4Set(node->color, 1.0, 1.0, 1.0, 1.0); }
void R_DrawCameraEffect (void) { image_t *image[2]; int32_t x, y, w, h, i, j; float texparms[2][4]; vec2_t texCoord[4]; vec3_t verts[4]; renderparms_t cameraParms; static const vec4_t color = {1.0, 1.0, 1.0, 1.0}; image[0] = R_DrawFindPic ("/gfx/2d/screenstatic.tga"); image[1] = R_DrawFindPic ("/gfx/2d/scanlines.tga"); if (!image[0] || !image[1]) return; x = y = 0; w = vid.width; h = vid.height; GL_Disable (GL_ALPHA_TEST); GL_TexEnv (GL_MODULATE); GL_Enable (GL_BLEND); GL_BlendFunc (GL_DST_COLOR, GL_SRC_COLOR); GL_DepthMask (false); VectorSet(verts[0], x, y, 0); VectorSet(verts[1], x+w, y, 0); VectorSet(verts[2], x+w, y+h, 0); VectorSet(verts[3], x, y+h, 0); Vector4Set(texparms[0], 2, 2, -30, 10); Vector4Set(texparms[1], 1, 10, 0, 0); rb_vertex = rb_index = 0; memcpy(&indexArray[rb_index], indices, sizeof(indices)); rb_index += 6; rb_vertex = 4; for (i=0; i<2; i++) { GL_Bind (image[i]->texnum); Vector2Set(texCoord[0], x/image[i]->width, y/image[i]->height); Vector2Set(texCoord[1], (x+w)/image[i]->width, y/image[i]->height); Vector2Set(texCoord[2], (x+w)/image[i]->width, (y+h)/image[i]->height); Vector2Set(texCoord[3], x/image[i]->width, (y+h)/image[i]->height); Mod_SetRenderParmsDefaults (&cameraParms); cameraParms.scale_x = texparms[i][0]; cameraParms.scale_y = texparms[i][1]; cameraParms.scroll_x = texparms[i][2]; cameraParms.scroll_y = texparms[i][3]; RB_ModifyTextureCoords (&texCoord[0][0], &verts[0][0], 4, cameraParms); memcpy(texCoordArray[0][0], texCoord, sizeof(vec2_t) * 4); memcpy(vertexArray[0], verts, sizeof(vec3_t) * 4); for (j=0; j<4; j++) { VA_SetElem4v(colorArray[j], color); } RB_DrawArrays (); } rb_vertex = rb_index = 0; GL_DepthMask (true); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Disable (GL_BLEND); GL_TexEnv (GL_REPLACE); GL_Enable (GL_ALPHA_TEST); }
/* * R_RenderScene */ void R_RenderScene( const refdef_t *fd ) { int fbFlags = 0; if( r_norefresh->integer ) return; R_Set2DMode( qfalse ); RB_SetTime( fd->time ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) rsc.refdef = *fd; rn.refdef = *fd; if( !rn.refdef.minLight ) { rn.refdef.minLight = 0.1f; } if( !rsh.screenWeaponTexture || rn.refdef.weaponAlpha == 1 ) { rn.refdef.rdflags &= ~RDF_WEAPONALPHA; } fd = &rn.refdef; rn.renderFlags = RF_NONE; rn.farClip = R_DefaultFarClip(); rn.clipFlags = 15; if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog ) rn.clipFlags |= 16; rn.meshlist = &r_worldlist; rn.shadowBits = 0; rn.dlightBits = 0; rn.shadowGroup = NULL; fbFlags = 0; rn.fbColorAttachment = rn.fbDepthAttachment = NULL; if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { // soft particles require GL_EXT_framebuffer_blit as we need to copy the depth buffer // attachment into a texture we're going to read from in GLSL shader if( r_soft_particles->integer && glConfig.ext.framebuffer_blit && ( rsh.screenTexture != NULL ) ) { rn.fbColorAttachment = rsh.screenTexture; rn.fbDepthAttachment = rsh.screenDepthTexture; rn.renderFlags |= RF_SOFT_PARTICLES; fbFlags |= 1; } if( ( fd->rdflags & RDF_WEAPONALPHA ) && ( rsh.screenWeaponTexture != NULL ) ) { fbFlags |= 2; } if( r_fxaa->integer && ( rsh.screenFxaaCopy != NULL ) ) { if( !rn.fbColorAttachment ) { rn.fbColorAttachment = rsh.screenFxaaCopy; } fbFlags |= 4; } } // adjust field of view for widescreen if( glConfig.wideScreen && !( fd->rdflags & RDF_NOFOVADJUSTMENT ) ) AdjustFov( &rn.refdef.fov_x, &rn.refdef.fov_y, glConfig.width, glConfig.height, qfalse ); // clip new scissor region to the one currently set Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height ); Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height ); VectorCopy( fd->vieworg, rn.pvsOrigin ); VectorCopy( fd->vieworg, rn.lodOrigin ); if( gl_finish->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) ) qglFinish(); if( fbFlags & 2 ) { // clear the framebuffer we're going to render the weapon model to // set the alpha to 0, visible parts of the model will overwrite that, // creating proper alpha mask R_BindFrameBufferObject( rsh.screenWeaponTexture->fbo ); RB_Clear( GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, 0, 0, 0, 0 ); } R_BindFrameBufferObject( 0 ); R_BuildShadowGroups(); R_RenderView( fd ); R_RenderDebugSurface( fd ); R_RenderDebugBounds(); R_BindFrameBufferObject( 0 ); R_Set2DMode( qtrue ); // blit and blend framebuffers in proper order if( fbFlags & 1 ) { // copy to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rn.fbColorAttachment, fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, GLSL_PROGRAM_TYPE_NONE, colorWhite, 0 ); } if( fbFlags & 2 ) { vec4_t color = { 1, 1, 1, 1 }; color[3] = fd->weaponAlpha; // blend to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rsh.screenWeaponTexture, fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, GLSL_PROGRAM_TYPE_NONE, color, GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } // blit FXAA to default framebuffer if( fbFlags & 4 ) { // blend to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rsh.screenFxaaCopy, 0, GLSL_PROGRAM_TYPE_FXAA, colorWhite, 0 ); } }
/** * @brief Called before loading. Used to set default attribute values */ static void UI_SelectBoxNodeLoading (uiNode_t *node) { Vector4Set(node->color, 0.6, 0.6, 0.6, 0.3); }
/* ================= 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 = (md5Model_t*) 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 = (md5Bone_t*) 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", 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 ); // 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 = (md5Surface_t*) 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 = (md5Vertex_t*) 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 = (md5Triangle_t*) 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 = (md5Weight_t*) 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 through all vertices and set up the vertex weights and base positions for ( j = 0, v = surf->verts; j < surf->numVerts; j++, v++ ) { md5Weight_t *w = surf->weights + v->firstWeight; Vector4Set( v->position, 0, 0, 0, 1 ); for ( k = 0; k < v->numWeights; k++, w++ ) { vec3_t offsetVec; v->boneIndexes[ k ] = w->boneIndex; v->boneWeights[ k ] = w->boneWeight; bone = &md5->bones[ w->boneIndex ]; QuatTransformVector( bone->rotation, w->offset, offsetVec ); VectorAdd( bone->origin, offsetVec, offsetVec ); VectorMA( v->position, w->boneWeight, offsetVec, v->position ); } } } // 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++ ) { AddPointToBounds( v->position, 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->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 ); v->normal[ 3 ] = 0; } } #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; }
/* * R_RenderScene */ void R_RenderScene( const refdef_t *fd ) { int fbFlags = 0; int ppFrontBuffer = 0; image_t *ppSource; if( r_norefresh->integer ) return; R_Set2DMode( false ); RB_SetTime( fd->time ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) rsc.refdef = *fd; rn.refdef = *fd; if( !rn.refdef.minLight ) { rn.refdef.minLight = 0.1f; } fd = &rn.refdef; rn.renderFlags = RF_NONE; rn.farClip = R_DefaultFarClip(); rn.clipFlags = 15; if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog ) rn.clipFlags |= 16; rn.meshlist = &r_worldlist; rn.portalmasklist = &r_portalmasklist; rn.shadowBits = 0; rn.dlightBits = 0; rn.shadowGroup = NULL; fbFlags = 0; rn.fbColorAttachment = rn.fbDepthAttachment = NULL; if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { if( r_soft_particles->integer && ( rsh.screenTexture != NULL ) ) { rn.fbColorAttachment = rsh.screenTexture; rn.fbDepthAttachment = rsh.screenDepthTexture; rn.renderFlags |= RF_SOFT_PARTICLES; fbFlags |= PPFX_BIT_SOFT_PARTICLES; } if( rsh.screenPPCopies[0] && rsh.screenPPCopies[1] ) { int oldFlags = fbFlags; shader_t *cc = rn.refdef.colorCorrection; if( cc && cc->numpasses > 0 && cc->passes[0].images[0] && cc->passes[0].images[0] != rsh.noTexture ) { fbFlags |= PPFX_BIT_COLOR_CORRECTION; } if( r_fxaa->integer ) { fbFlags |= PPFX_BIT_FXAA; } if( fbFlags != oldFlags ) { if( !rn.fbColorAttachment ) { rn.fbColorAttachment = rsh.screenPPCopies[0]; ppFrontBuffer = 1; } } } } ppSource = rn.fbColorAttachment; // clip new scissor region to the one currently set Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height ); Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height ); VectorCopy( fd->vieworg, rn.pvsOrigin ); VectorCopy( fd->vieworg, rn.lodOrigin ); R_BindFrameBufferObject( 0 ); R_BuildShadowGroups(); R_RenderView( fd ); R_RenderDebugSurface( fd ); R_RenderDebugBounds(); R_BindFrameBufferObject( 0 ); R_Set2DMode( true ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Mutex_Lock( rf.speedsMsgLock ); R_WriteSpeedsMessage( rf.speedsMsg, sizeof( rf.speedsMsg ) ); ri.Mutex_Unlock( rf.speedsMsgLock ); } // blit and blend framebuffers in proper order if( fbFlags == PPFX_BIT_SOFT_PARTICLES ) { // only blit soft particles directly when we don't have any other post processing // otherwise use the soft particles FBO as the base texture on the next layer // to avoid wasting time on resolves and the fragment shader to blit to a temp texture R_BlitTextureToScrFbo( fd, ppSource, 0, GLSL_PROGRAM_TYPE_NONE, colorWhite, 0, 0, NULL ); return; } fbFlags &= ~PPFX_BIT_SOFT_PARTICLES; // apply color correction if( fbFlags & PPFX_BIT_COLOR_CORRECTION ) { image_t *dest; fbFlags &= ~PPFX_BIT_COLOR_CORRECTION; dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL; R_BlitTextureToScrFbo( fd, ppSource, dest ? dest->fbo : 0, GLSL_PROGRAM_TYPE_COLORCORRECTION, colorWhite, 0, 1, rn.refdef.colorCorrection->passes[0].images ); ppFrontBuffer ^= 1; ppSource = dest; } // apply FXAA if( fbFlags & PPFX_BIT_FXAA ) { image_t *dest; fbFlags &= ~PPFX_BIT_FXAA; dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL; R_BlitTextureToScrFbo( fd, ppSource, dest ? dest->fbo : 0, GLSL_PROGRAM_TYPE_FXAA, colorWhite, 0, 0, NULL ); ppFrontBuffer ^= 1; ppSource = dest; } }
UI_Main::UI_Main( int vidWidth, int vidHeight, int protocol, const char *demoExtension ) // pointers to zero : asmodule(0), rocketModule(0), levelshot_fmt(0), datetime_fmt(0), duration_fmt(0), filetype_fmt(0), colorcode_fmt(0), crosshair_fmt(0), empty_fmt(0), serverBrowser(0), gameTypes(0), maps(0), vidProfiles(0), huds(0), videoModes(0), demos(0), mods(0), playerModels(0), crosshairs(0), tvchannels(0), ircchannels(0), gameajax(0), navigator(0), /* backwards development compatibility: */ currentLoader(0), // other members mousex(0), mousey(0), gameProtocol(protocol), menuVisible(false), forceMenu(false), showNavigationStack(false), serverName(""), rejectMessage(""), demoExtension(demoExtension), connectCount(0), invalidateAjaxCache(false) { // instance self = this; Vector4Set( colorWhite, 1, 1, 1, 1 ); ui_basepath = trap::Cvar_Get( "ui_basepath", "/ui/baseui", CVAR_ARCHIVE ); ui_cursor = trap::Cvar_Get( "ui_cursor", "cursors/default.rml", CVAR_DEVELOPER ); ui_developer = trap::Cvar_Get( "developer", "0", 0 ); // temp fix for missing background on start.. populate refreshState with some nice values refreshState.clientState = CA_UNINITIALIZED; refreshState.width = vidWidth; refreshState.height = vidHeight; refreshState.drawBackground = true; demoInfo.setPlaying( false ); if( !initRocket() ) throw std::runtime_error( "UI: Failed to initialize libRocket" ); registerRocketCustoms(); createDataSources(); createFormatters(); navigator = __new__( NavigationStack )(); streamCache = __new__( StreamCache )(); streamCache->Init(); if( !initAS() ) throw std::runtime_error( "UI: Failed to initialize AngelScript" ); // this after instantiation ASUI::BindGlobals( self->getAS() ); // load cursor document loadCursor(); // this has to be called after AS API is fully loaded preloadUI(); // commands trap::Cmd_AddCommand( "ui_reload", ReloadUI_Cmd_f ); trap::Cmd_AddCommand( "ui_dumpapi", DumpAPI_f ); trap::Cmd_AddCommand( "ui_printdocs", PrintDocuments_Cmd ); trap::Cmd_AddCommand( "menu_force", M_Menu_Force_f ); trap::Cmd_AddCommand( "menu_open", M_Menu_Open_f ); trap::Cmd_AddCommand( "menu_close", M_Menu_Close_f ); trap::Cmd_AddCommand( "menu_tvchannel_add", &M_Menu_AddTVChannel_f ); trap::Cmd_AddCommand( "menu_tvchannel_remove", &M_Menu_RemoveTVChannel_f ); }
/** * @brief Called before loading. Used to set default attribute values */ void uiOptionTreeNode::onLoading (uiNode_t *node) { Vector4Set(node->color, 1, 1, 1, 1); EXTRADATA(node).versionId = -1; node->padding = 3; }
void CG_SmallPileOfGibs( const vec3_t origin, int damage, const vec3_t initialVelocity, int team ) { lentity_t *le; int i, j, count; vec3_t angles, velocity; int time; if( !cg_gibs->integer ) return; time = 50; count = 14 + cg_gibs->integer; // 15 models minimum clamp( count, 15, 128 ); for( i = 0; i < count; i++ ) { vec4_t color; // coloring switch ( rand( ) % 3 ) { case 0: // orange Vector4Set( color, 1, 0.5, 0, 1 ); break; case 1: // purple Vector4Set( color, 1, 0, 1, 1 ); break; case 2: default: if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) ) { // team CG_TeamColor( team, color ); for( j = 0; j < 3; j++ ) { color[j] = bound( 60.0f / 255.0f, color[j], 1.0f ); } } else { // grey Vector4Set( color, 60.0f / 255.0f, 60.0f / 255.0f, 60.0f / 255.0f, 1.0f ); } break; } le = CG_AllocModel( LE_ALPHA_FADE, origin, vec3_origin, time + time * random( ), color[0], color[1], color[2], color[3], 0, 0, 0, 0, CG_MediaModel( cgs.media.modIlluminatiGibs ), NULL ); // random rotation and scale variations VectorSet( angles, crandom() * 360, crandom() * 360, crandom() * 360 ); AnglesToAxis( angles, le->ent.axis ); le->ent.scale = 0.8f - ( random() * 0.25 ); le->ent.renderfx = RF_FULLBRIGHT|RF_NOSHADOW; velocity[0] = crandom() * 0.5; velocity[1] = crandom() * 0.5; velocity[2] = 0.5 + random() * 0.5; // always have upwards VectorNormalize( velocity ); VectorScale( velocity, min( damage * 10, 300 ), velocity ); velocity[0] += crandom() * bound( 0, damage, 150 ); velocity[1] += crandom() * bound( 0, damage, 150 ); velocity[2] += random() * bound( 0, damage, 250 ); VectorAdd( initialVelocity, velocity, le->velocity ); le->avelocity[0] = random() * 1200; le->avelocity[1] = random() * 1200; le->avelocity[2] = random() * 1200; //friction and gravity VectorSet( le->accel, -0.2f, -0.2f, -900 ); le->bounce = 75; } }
/* RE_ProjectDecal() creates a new decal projector from a triangle projected polygons should be 3 or 4 points if a single point is passed in (numPoints == 1) then the decal will be omnidirectional omnidirectional decals use points[ 0 ] as center and projection[ 3 ] as radius pass in lifeTime < 0 for a temporary mark */ void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime) { static int totalProjectors = 0; int i; float radius, iDist; vec3_t xyz; decalVert_t dv[4]; decalProjector_t *dp, temp; if (r_numDecalProjectors >= MAX_DECAL_PROJECTORS) { Ren_Print("WARNING: RE_ProjectDecal() Max decal projectors reached (%d)\n", MAX_DECAL_PROJECTORS); return; } // dummy check if (numPoints != 1 && numPoints != 3 && numPoints != 4) { Ren_Warning("WARNING: Invalid number of decal points (%d)\n", numPoints); return; } // early outs if (lifeTime == 0) { return; } if (projection[3] <= 0.0f) { return; } // set times properly if (lifeTime < 0 || fadeTime < 0) { lifeTime = 0; fadeTime = 0; } // basic setup temp.shader = R_GetShaderByHandle(hShader); temp.color[0] = color[0] * 255; temp.color[1] = color[1] * 255; temp.color[2] = color[2] * 255; temp.color[3] = color[3] * 255; temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; // fixme: stale refdef time temp.fadeEndTime = temp.fadeStartTime + fadeTime; // set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) dv[0].st[0] = 0.0f; dv[0].st[1] = 0.0f; dv[1].st[0] = 0.0f; dv[1].st[1] = 1.0f; dv[2].st[0] = 1.0f; dv[2].st[1] = 1.0f; dv[3].st[0] = 1.0f; dv[3].st[1] = 0.0f; // omnidirectional? if (numPoints == 1) { // set up omnidirectional numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[3]; Vector4Set(projection, 0.0f, 0.0f, -1.0f, radius * 2.0f); iDist = 1.0f / (radius * 2.0f); // set corner VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); // make x axis texture matrix (yz) VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f); temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz); VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist); temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz); // make y axis texture matrix (xz) VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f); temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz); VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist); temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz); // make z axis texture matrix (xy) VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f); temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz); VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f); temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz); // setup decal points VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius); } else { // set up unidirectional temp.omnidirectional = qfalse; // set up decal points VectorCopy(points[0], dv[0].xyz); VectorCopy(points[1], dv[1].xyz); VectorCopy(points[2], dv[2].xyz); VectorCopy(points[3], dv[3].xyz); // make texture matrix if (!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2])) { return; } } // bound the projector ClearBounds(temp.mins, temp.maxs); for (i = 0; i < numPoints; i++) { AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs); VectorMA(dv[i].xyz, projection[3], projection, xyz); AddPointToBounds(xyz, temp.mins, temp.maxs); } // make bounding sphere VectorAdd(temp.mins, temp.maxs, temp.center); VectorScale(temp.center, 0.5f, temp.center); VectorSubtract(temp.maxs, temp.center, xyz); temp.radius = VectorLength(xyz); temp.radius2 = temp.radius * temp.radius; // make the front plane if (!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz)) { return; } // make the back plane VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]); VectorMA(dv[0].xyz, projection[3], projection, xyz); temp.planes[1][3] = DotProduct(xyz, temp.planes[1]); // make the side planes for (i = 0; i < numPoints; i++) { VectorMA(dv[i].xyz, projection[3], projection, xyz); if (!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz)) { return; } } // create a new projector dp = &backEndData->decalProjectors[r_numDecalProjectors]; Com_Memcpy(dp, &temp, sizeof(*dp)); dp->projectorNum = totalProjectors++; // we have a winner r_numDecalProjectors++; }
/* * CG_DamageIndicatorAdd */ void CG_DamageIndicatorAdd( int damage, const vec3_t dir ) { int i; unsigned int damageTime; vec3_t playerAngles; mat3_t playerAxis; // epsilons are 30 degrees #define INDICATOR_EPSILON 0.5f #define INDICATOR_EPSILON_UP 0.85f #define TOP_BLEND 0 #define RIGHT_BLEND 1 #define BOTTOM_BLEND 2 #define LEFT_BLEND 3 float blends[4]; float forward, side; if( !cg_damage_indicator->integer ) return; playerAngles[PITCH] = 0; playerAngles[YAW] = cg.predictedPlayerState.viewangles[YAW]; playerAngles[ROLL] = 0; Matrix3_FromAngles( playerAngles, playerAxis ); if( cg_damage_indicator_time->value < 0 ) trap_Cvar_SetValue( "cg_damage_indicator_time", 0 ); Vector4Set( blends, 0, 0, 0, 0 ); damageTime = damage * cg_damage_indicator_time->value; // up and down go distributed equally to all blends and assumed when no dir is given if( !dir || VectorCompare( dir, vec3_origin ) || cg_damage_indicator->integer == 2 || GS_Instagib() || ( fabs( DotProduct( dir, &playerAxis[AXIS_UP] ) ) > INDICATOR_EPSILON_UP ) ) { blends[RIGHT_BLEND] += damageTime; blends[LEFT_BLEND] += damageTime; blends[TOP_BLEND] += damageTime; blends[BOTTOM_BLEND] += damageTime; } else { side = DotProduct( dir, &playerAxis[AXIS_RIGHT] ); if( side > INDICATOR_EPSILON ) blends[LEFT_BLEND] += damageTime; else if( side < -INDICATOR_EPSILON ) blends[RIGHT_BLEND] += damageTime; forward = DotProduct( dir, &playerAxis[AXIS_FORWARD] ); if( forward > INDICATOR_EPSILON ) blends[BOTTOM_BLEND] += damageTime; else if( forward < -INDICATOR_EPSILON ) blends[TOP_BLEND] += damageTime; } for( i = 0; i < 4; i++ ) { if( cg.damageBlends[i] < cg.time + blends[i] ) cg.damageBlends[i] = cg.time + blends[i]; } #undef TOP_BLEND #undef RIGHT_BLEND #undef BOTTOM_BLEND #undef LEFT_BLEND #undef INDICATOR_EPSILON #undef INDICATOR_EPSILON_UP }
/** * @brief Called before loading. Used to set default attribute values */ void uiModelNode::onLoading (uiNode_t* node) { Vector4Set(node->color, 1, 1, 1, 1); VectorSet(EXTRADATA(node).scale, 1, 1, 1); EXTRADATA(node).clipOverflow = true; }
/* * ClientUserinfoChanged * called whenever the player updates a userinfo variable. * * The game can override any of the settings in place * (forcing skins or names, etc) before copying it off. */ void ClientUserinfoChanged( edict_t *ent, char *userinfo ) { char *s; char oldname[MAX_INFO_VALUE]; gclient_t *cl; int rgbcolor, i; assert( ent && ent->r.client ); assert( userinfo && Info_Validate( userinfo ) ); // check for malformed or illegal info strings if( !Info_Validate( userinfo ) ) { trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Invalid userinfo" ); return; } cl = ent->r.client; // ip s = Info_ValueForKey( userinfo, "ip" ); if( !s ) { trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Server didn't provide client IP" ); return; } Q_strncpyz( cl->ip, s, sizeof( cl->ip ) ); // socket s = Info_ValueForKey( userinfo, "socket" ); if( !s ) { trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Server didn't provide client socket" ); return; } Q_strncpyz( cl->socket, s, sizeof( cl->socket ) ); // color s = Info_ValueForKey( userinfo, "color" ); if( s ) rgbcolor = COM_ReadColorRGBString( s ); else rgbcolor = -1; if( rgbcolor != -1 ) { rgbcolor = COM_ValidatePlayerColor( rgbcolor ); Vector4Set( cl->color, COLOR_R( rgbcolor ), COLOR_G( rgbcolor ), COLOR_B( rgbcolor ), 255 ); } else { Vector4Set( cl->color, 255, 255, 255, 255 ); } // set name, it's validated and possibly changed first Q_strncpyz( oldname, cl->netname, sizeof( oldname ) ); G_SetName( ent, Info_ValueForKey( userinfo, "name" ) ); if( oldname[0] && Q_stricmp( oldname, cl->netname ) && !cl->isTV && !CheckFlood( ent, false ) ) G_PrintMsg( NULL, "%s%s is now known as %s%s\n", oldname, S_COLOR_WHITE, cl->netname, S_COLOR_WHITE ); if( !Info_SetValueForKey( userinfo, "name", cl->netname ) ) { trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (name)" ); return; } // clan tag G_SetClan( ent, Info_ValueForKey( userinfo, "clan" ) ); // handedness s = Info_ValueForKey( userinfo, "hand" ); if( !s ) cl->hand = 2; else cl->hand = bound( atoi( s ), 0, 2 ); // handicap s = Info_ValueForKey( userinfo, "handicap" ); if( s ) { i = atoi( s ); if( i > 90 || i < 0 ) { G_PrintMsg( ent, "Handicap must be defined in the [0-90] range.\n" ); cl->handicap = 0; } else { cl->handicap = i; } } s = Info_ValueForKey( userinfo, "cg_movementStyle" ); if( s ) { i = bound( atoi( s ), 0, GS_MAXBUNNIES - 1 ); if( trap_GetClientState( PLAYERNUM(ent) ) < CS_SPAWNED ) { if( i != cl->movestyle ) cl->movestyle = cl->movestyle_latched = i; } else if( cl->movestyle_latched != cl->movestyle ) { G_PrintMsg( ent, "A movement style change is already in progress. Please wait.\n" ); } else if( i != cl->movestyle_latched ) { cl->movestyle_latched = i; if( cl->movestyle_latched != cl->movestyle ) { edict_t *switcher; switcher = G_Spawn(); switcher->think = think_MoveTypeSwitcher; switcher->nextThink = level.time + 10000; switcher->s.ownerNum = ENTNUM( ent ); G_PrintMsg( ent, "Movement style will change in 10 seconds.\n" ); } } } // update the movement features depending on the movestyle if( !G_ISGHOSTING( ent ) && g_allow_bunny->integer ) { if( cl->movestyle == GS_CLASSICBUNNY ) cl->ps.pmove.stats[PM_STAT_FEATURES] &= ~PMFEAT_FWDBUNNY; else cl->ps.pmove.stats[PM_STAT_FEATURES] |= PMFEAT_FWDBUNNY; } s = Info_ValueForKey( userinfo, "cg_noAutohop" ); if( s && s[0] ) { if( atoi( s ) != 0 ) cl->ps.pmove.stats[PM_STAT_FEATURES] &= ~PMFEAT_CONTINOUSJUMP; else cl->ps.pmove.stats[PM_STAT_FEATURES] |= PMFEAT_CONTINOUSJUMP; } #ifdef UCMDTIMENUDGE s = Info_ValueForKey( userinfo, "cl_ucmdTimeNudge" ); if( !s ) { cl->ucmdTimeNudge = 0; } else { cl->ucmdTimeNudge = atoi( s ); clamp( cl->ucmdTimeNudge, -MAX_UCMD_TIMENUDGE, MAX_UCMD_TIMENUDGE ); } #endif // mm session // TODO: remove the key after storing it to gclient_t ! s = Info_ValueForKey( userinfo, "cl_mm_session" ); cl->mm_session = ( s == NULL ) ? 0 : atoi( s ); // tv if( cl->isTV ) { s = Info_ValueForKey( userinfo, "tv_port" ); cl->tv.port = s ? atoi( s ) : 0; s = Info_ValueForKey( userinfo, "tv_port6" ); cl->tv.port6 = s ? atoi( s ) : 0; s = Info_ValueForKey( userinfo, "max_cl" ); cl->tv.maxclients = s ? atoi( s ) : 0; s = Info_ValueForKey( userinfo, "num_cl" ); cl->tv.numclients = s ? atoi( s ) : 0; s = Info_ValueForKey( userinfo, "chan" ); cl->tv.channel = s ? atoi( s ) : 0; } if( !G_ISGHOSTING( ent ) && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) G_Client_AssignTeamSkin( ent, userinfo ); // save off the userinfo in case we want to check something later Q_strncpyz( cl->userinfo, userinfo, sizeof( cl->userinfo ) ); G_UpdatePlayerInfoString( PLAYERNUM( ent ) ); G_Gametype_ScoreEvent( cl, "userinfochanged", oldname ); }
/** * @brief Prepares the particle rendering, calculate new position, velocity and all the * other particle values that are needed to display it * @sa CL_ParticleRun * @param[in,out] p The particle to handle */ static void CL_ParticleRun2 (ptl_t* p) { /* advance time */ p->dt = cls.frametime; p->t = (cl.time - p->startTime) * 0.001f; p->lastThink += p->dt; p->lastFrame += p->dt; if (p->rounds && !p->roundsCnt) p->roundsCnt = p->rounds; /* test for end of life */ if (p->life && p->t >= p->life && !p->parent) { CL_ParticleFree(p); return; /* don't play the weather particles if a user don't want them there can * be a lot of weather particles - which might slow the computer down */ } else if (p->weather && !cl_particleweather->integer) { CL_ParticleFree(p); return; } /* kinematics */ if (p->style != STYLE_LINE) { VectorMA(p->s, 0.5 * p->dt * p->dt, p->a, p->s); VectorMA(p->s, p->dt, p->v, p->s); VectorMA(p->v, p->dt, p->a, p->v); VectorMA(p->angles, p->dt, p->omega, p->angles); } /* basic 'physics' for particles */ if (p->physics) { const float size = std::max(p->size[0], p->size[1]); if (p->hitSolid && p->bounce) { VectorCopy(p->oldV, p->v); VectorNegate(p->a, p->a); p->hitSolid = false; } /* if the particle hit a solid already and is sticking to the surface, no further * traces are needed */ if (p->hitSolid && p->stick) return; AABB ptlbox(-size, -size, -size, size, size, size); const trace_t tr = PTL_Trace(p, ptlbox); /* hit something solid */ if (tr.fraction < 1.0 || tr.startsolid) { p->hitSolid = true; /* now execute the physics handler */ if (p->ctrl->physics) CL_ParticleFunction(p, p->ctrl->physics); /* let them stay on the ground until they fade out or die */ if (!p->stayalive) { CL_ParticleFree(p); return; } else if (p->bounce) { /* bounce */ vec3_t temp; VectorCopy(p->v, p->oldV); VectorScale(tr.plane.normal, -DotProduct(tr.plane.normal, p->v), temp); VectorAdd(temp, p->v, temp); VectorAdd(temp, temp, p->v); VectorNegate(p->a, p->a); } else { VectorClear(p->v); } VectorCopy(tr.endpos, p->s); } } /* run */ CL_ParticleFunction(p, p->ctrl->run); /* think */ while (p->tps && p->lastThink * p->tps >= 1) { CL_ParticleFunction(p, p->ctrl->think); p->lastThink -= 1.0 / p->tps; } /* animate */ while (p->fps && p->lastFrame * p->fps >= 1) { /* advance frame */ p->frame++; if (p->frame > p->endFrame) p->frame = 0; p->lastFrame -= 1.0 / p->fps; /* load next frame */ assert(p->pic); p->pic = CL_ParticleGetArt(p->pic->name, p->frame, ART_PIC); } /* fading */ if (p->thinkFade || p->frameFade) { const bool onlyAlpha = (p->blend == BLEND_BLEND); if (!onlyAlpha) Vector4Set(p->color, 1.0f, 1.0f, 1.0f, 1.0f); else p->color[3] = 1.0; if (p->thinkFade) CL_Fading(p->color, p->thinkFade, p->lastThink * p->tps, onlyAlpha); if (p->frameFade) CL_Fading(p->color, p->frameFade, p->lastFrame * p->fps, onlyAlpha); } /* this is useful for particles like weather effects that are on top of * some other brushes in higher level but should be visible in lower ones */ if (p->autohide) { const int z = (int)p->s[2] / UNIT_HEIGHT; if (z > cl_worldlevel->integer) { p->invis = true; return; } else if (z < 0) { CL_ParticleFree(p); return; } } /* add light to the scene */ if (VectorNotEmpty(p->lightColor)) { const float intensity = 0.5 + p->lightIntensity; if (p->lightSustain) R_AddSustainedLight(p->s, intensity * PTL_INTENSITY_TO_RADIUS, p->lightColor, p->lightSustain); else R_AddLight(p->s, intensity * PTL_INTENSITY_TO_RADIUS, p->lightColor); } /* set the new origin */ VectorCopy(p->s, p->origin); p->invis = false; }
/* * R_DrawPortalSurface * * Renders the portal view and captures the results from framebuffer if * we need to do a $portalmap stage. Note that for $portalmaps we must * use a different viewport. */ static void R_DrawPortalSurface( portalSurface_t *portalSurface ) { unsigned int i; int x, y, w, h; float dist, d, best_d; vec3_t viewerOrigin; vec3_t origin; mat3_t axis; entity_t *ent, *best; cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane; const shader_t *shader = portalSurface->shader; vec_t *portal_centre = portalSurface->centre; bool mirror, refraction = false; image_t *captureTexture; int captureTextureId = -1; int prevRenderFlags = 0; bool prevFlipped; bool doReflection, doRefraction; image_t *portalTexures[2] = { NULL, NULL }; doReflection = doRefraction = true; if( shader->flags & SHADER_PORTAL_CAPTURE ) { shaderpass_t *pass; captureTexture = NULL; captureTextureId = 0; for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) { if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) { if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) { doRefraction = false; } else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) { doReflection = false; } break; } } } else { captureTexture = NULL; captureTextureId = -1; } x = y = 0; w = rn.refdef.width; h = rn.refdef.height; dist = PlaneDiff( rn.viewOrigin, portal_plane ); if( dist <= BACKFACE_EPSILON || !doReflection ) { if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) { return; } // even if we're behind the portal, we still need to capture // the second portal image for refraction refraction = true; captureTexture = NULL; captureTextureId = 1; if( dist < 0 ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; } } mirror = true; // default to mirror view // it is stupid IMO that mirrors require a RT_PORTALSURFACE entity best = NULL; best_d = 100000000; for( i = 0; i < rn.numEntities; i++ ) { ent = R_NUM2ENT( rn.entities[i] ); if( ent->rtype != RT_PORTALSURFACE ) { continue; } d = PlaneDiff( ent->origin, untransformed_plane ); if( ( d >= -64 ) && ( d <= 64 ) ) { d = Distance( ent->origin, portal_centre ); if( d < best_d ) { best = ent; best_d = d; } } } if( best == NULL ) { if( captureTextureId < 0 ) { // still do a push&pop because to ensure the clean state if( R_PushRefInst() ) { R_PopRefInst(); } return; } } else { if( !VectorCompare( best->origin, best->origin2 ) ) { // portal mirror = false; } best->rtype = NUM_RTYPES; } prevRenderFlags = rn.renderFlags; prevFlipped = ( rn.refdef.rdflags & RDF_FLIPPED ) != 0; if( !R_PushRefInst() ) { return; } VectorCopy( rn.viewOrigin, viewerOrigin ); if( prevFlipped ) { VectorInverse( &rn.viewAxis[AXIS_RIGHT] ); } setup_and_render: if( refraction ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; CategorizePlane( portal_plane ); VectorCopy( rn.viewOrigin, origin ); Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags |= RF_PORTALVIEW; if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } else if( mirror ) { VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin ); VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] ); VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] ); VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] ); Matrix3_Normalize( axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = ( prevRenderFlags ^ RF_FLIPFRONTFACE ) | RF_MIRRORVIEW; } else { vec3_t tvec; mat3_t A, B, C, rot; // build world-to-portal rotation matrix VectorNegate( portal_plane->normal, tvec ); NormalVectorToAxis( tvec, A ); // build portal_dest-to-world rotation matrix ByteToDir( best->frame, tvec ); NormalVectorToAxis( tvec, B ); Matrix3_Transpose( B, C ); // multiply to get world-to-world rotation matrix Matrix3_Multiply( C, A, rot ); // translate view origin VectorSubtract( rn.viewOrigin, best->origin, tvec ); Matrix3_TransformVector( rot, tvec, origin ); VectorAdd( origin, best->origin2, origin ); Matrix3_Transpose( A, B ); Matrix3_Multiply( rn.viewAxis, B, rot ); Matrix3_Multiply( best->axis, rot, B ); Matrix3_Transpose( C, A ); Matrix3_Multiply( B, A, axis ); // set up portal_plane VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal ); portal_plane->dist = DotProduct( best->origin2, portal_plane->normal ); CategorizePlane( portal_plane ); // for portals, vis data is taken from portal origin, not // view origin, because the view point moves around and // might fly into (or behind) a wall VectorCopy( best->origin2, rn.pvsOrigin ); VectorCopy( best->origin2, rn.lodOrigin ); rn.renderFlags |= RF_PORTALVIEW; // ignore entities, if asked politely if( best->renderfx & RF_NOPORTALENTS ) { rn.renderFlags |= RF_ENVVIEW; } if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_FLIPPED ); rn.meshlist = &r_portallist; rn.portalmasklist = NULL; rn.renderFlags |= RF_CLIPPLANE; rn.renderFlags &= ~RF_SOFT_PARTICLES; rn.clipPlane = *portal_plane; rn.nearClip = Z_NEAR; rn.farClip = R_DefaultFarClip(); rn.polygonFactor = POLYOFFSET_FACTOR; rn.polygonUnits = POLYOFFSET_UNITS; rn.clipFlags |= 16; rn.frustum[4] = *portal_plane; // nearclip CategorizePlane( &rn.frustum[4] ); // if we want to render to a texture, initialize texture // but do not try to render to it more than once if( captureTextureId >= 0 ) { int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0; captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags, rsc.frameCount ); portalTexures[captureTextureId] = captureTexture; if( !captureTexture ) { // couldn't register a slot for this plane goto done; } x = y = 0; w = captureTexture->upload_width; h = captureTexture->upload_height; rn.refdef.width = w; rn.refdef.height = h; rn.refdef.x = 0; rn.refdef.y = 0; rn.renderTarget = captureTexture->fbo; rn.renderFlags |= RF_PORTAL_CAPTURE; Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h ); Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } else { rn.renderFlags &= ~RF_PORTAL_CAPTURE; } VectorCopy( origin, rn.refdef.vieworg ); Matrix3_Copy( axis, rn.refdef.viewaxis ); R_SetupViewMatrices( &rn.refdef ); R_SetupFrustum( &rn.refdef, rn.nearClip, rn.farClip, rn.frustum, rn.frustumCorners ); R_SetupPVS( &rn.refdef ); R_RenderView( &rn.refdef ); if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { rn.renderFlags = prevRenderFlags; refraction = true; captureTexture = NULL; captureTextureId = 1; goto setup_and_render; } done: portalSurface->texures[0] = portalTexures[0]; portalSurface->texures[1] = portalTexures[1]; R_PopRefInst(); }
static int WM_TeamScoreboard( int x, int y, team_t team, float fade, int maxrows ) { vec4_t hcolor; float tempx, tempy; int height, width; int i; int count = 0; vec4_t tclr = { 0.6f, 0.6f, 0.6f, 1.0f }; height = SMALLCHAR_HEIGHT * maxrows; width = INFO_PLAYER_WIDTH + INFO_CLASS_WIDTH + INFO_SCORE_WIDTH + INFO_LATENCY_WIDTH; CG_FillRect( x-5, y-2, width+5, 21, clrUiBack ); CG_FillRect( x-5, y-2, width+5, 21, clrUiBar ); Vector4Set( hcolor, 0, 0, 0, fade ); CG_DrawRect_FixedBorder( x-5, y-2, width+5, 21, 1, colorBlack ); // draw header if( cg_gameType.integer == GT_WOLF_LMS ) { char *s; if ( team == TEAM_AXIS ) { s = va( "%s [%d] (%d %s)", CG_TranslateString( "AXIS" ), cg.teamScores[0], cg.teamPlayers[team], CG_TranslateString("PLAYERS") ); s = va( "%s ^3%s", s, cg.teamFirstBlood == TEAM_AXIS ? CG_TranslateString("FIRST BLOOD") : "" ); CG_Text_Paint_Ext( x, y + 13, 0.25f, 0.25f, tclr, s, 0, 0, 0, &cgs.media.limboFont1 ); } else if ( team == TEAM_ALLIES ) { s = va( "%s [%d] (%d %s)", CG_TranslateString( "ALLIES" ), cg.teamScores[1], cg.teamPlayers[team], CG_TranslateString("PLAYERS") ); s = va( "%s ^3%s", s, cg.teamFirstBlood == TEAM_ALLIES ? CG_TranslateString("FIRST BLOOD") : "" ); CG_Text_Paint_Ext( x, y + 13, 0.25f, 0.25f, tclr, s, 0, 0, 0, &cgs.media.limboFont1 ); } } else { if ( team == TEAM_AXIS ) { CG_Text_Paint_Ext( x, y + 13, 0.25f, 0.25f, tclr, va( "%s [%d] (%d %s)", CG_TranslateString( "AXIS" ), cg.teamScores[0], cg.teamPlayers[team], CG_TranslateString("PLAYERS") ), 0, 0, 0, &cgs.media.limboFont1 ); } else if ( team == TEAM_ALLIES ) { CG_Text_Paint_Ext( x, y + 13, 0.25f, 0.25f, tclr, va( "%s [%d] (%d %s)", CG_TranslateString( "ALLIES" ), cg.teamScores[1], cg.teamPlayers[team], CG_TranslateString("PLAYERS") ), 0, 0, 0, &cgs.media.limboFont1 ); } } y += SMALLCHAR_HEIGHT + 3; // save off y val tempy = y; // draw color bands for ( i = 0; i <= maxrows; i++ ) { if ( i % 2 == 0 ) VectorSet( hcolor, (80.f/255.f), (80.f/255.f), (80.f/255.f) ); // LIGHT BLUE else VectorSet( hcolor, (0.f/255.f), (0.f/255.f), (0.f/255.f) ); // DARK BLUE hcolor[3] = fade * 0.3; CG_FillRect( x-5, y, width+5, SMALLCHAR_HEIGHT+1, hcolor ); trap_R_SetColor( colorBlack ); CG_DrawTopBottom( x-5, y, width+5, SMALLCHAR_HEIGHT+1, 1 ); trap_R_SetColor( NULL ); y += SMALLCHAR_HEIGHT; } hcolor[3] = 1; y = tempy; tempx = x; CG_FillRect( x-5, y-1, width+5, 18, clrUiBack ); //CG_FillRect( x-5, y-1, width+5, 18, clrUiBar ); trap_R_SetColor( colorBlack ); CG_DrawTopBottom( x-5, y-1, width+5, 18, 1 ); trap_R_SetColor( NULL ); // draw player info headings CG_DrawSmallString( tempx, y, CG_TranslateString( "Name" ), fade ); tempx += INFO_PLAYER_WIDTH; CG_DrawSmallString( tempx, y, CG_TranslateString( "Class" ), fade ); tempx += INFO_CLASS_WIDTH; if( cgs.gametype == GT_WOLF_LMS ) { CG_DrawSmallString( tempx, y, CG_TranslateString( "Score" ), fade ); tempx += INFO_SCORE_WIDTH; } else { CG_DrawSmallString( tempx + 1 * SMALLCHAR_WIDTH, y, CG_TranslateString( "XP" ), fade ); tempx += INFO_XP_WIDTH; } CG_DrawSmallString( tempx, y, CG_TranslateString( "Ping" ), fade ); tempx += INFO_LATENCY_WIDTH; if( cgs.gametype != GT_WOLF_LMS ) { CG_DrawPicST( tempx + 2, y, INFO_LIVES_WIDTH - 4, 16, 0.f, 0.f, 0.5f, 1.f, team == TEAM_ALLIES ? cgs.media.hudAlliedHelmet : cgs.media.hudAxisHelmet ); tempx += INFO_LIVES_WIDTH; } y += SMALLCHAR_HEIGHT; // draw player info VectorSet( hcolor, 1, 1, 1 ); hcolor[3] = fade; cg.teamPlayers[team] = 0; // JPW NERVE for ( i = 0; i < cg.numScores; i++ ) { if ( team != cgs.clientinfo[ cg.scores[i].client ].team ) continue; cg.teamPlayers[team]++; } count = 0; for( i = 0; i < cg.numScores && count < maxrows; i++ ) { if( team != cgs.clientinfo[ cg.scores[i].client ].team ) { continue; } if( cg.teamPlayers[team] > maxrows ) { WM_DrawClientScore_Small( x, y, &cg.scores[i], hcolor, fade ); y += MINICHAR_HEIGHT; } else { WM_DrawClientScore( x, y, &cg.scores[i], hcolor, fade ); y += SMALLCHAR_HEIGHT; } count++; } // draw spectators y += SMALLCHAR_HEIGHT; for ( i = 0; i < cg.numScores; i++ ) { if ( cgs.clientinfo[ cg.scores[i].client ].team != TEAM_SPECTATOR ) continue; if ( team == TEAM_AXIS && ( i % 2 ) ) continue; if ( team == TEAM_ALLIES && ( ( i + 1 ) % 2 ) ) continue; WM_DrawClientScore( x, y, &cg.scores[i], hcolor, fade ); y += SMALLCHAR_HEIGHT; } return y; }
/** * @brief Draws shadow and highlight effects for the entities (actors) * @note The origins are already transformed */ void R_DrawEntityEffects (void) { int i; const int mask = r_stencilshadows->integer ? RF_BLOOD : (RF_SHADOW | RF_BLOOD); GLint oldDepthFunc; glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunc); R_EnableBlend(qtrue); if (actorIndicator == NULL) { selectedActorIndicator = R_FindImage("pics/sfx/actor_selected", it_effect); actorIndicator = R_FindImage("pics/sfx/actor", it_effect); } for (i = 0; i < refdef.numEntities; i++) { const entity_t *e = &r_entities[i]; if (e->flags <= RF_BOX) continue; glPushMatrix(); glMultMatrixf(e->transform.matrix); if (e->flags & mask) { const vec3_t points[] = { { -18.0, 14.0, -28.5 }, { 10.0, 14.0, -28.5 }, { 10.0, -14.0, -28.5 }, { -18.0, -14.0, -28.5 } }; /** @todo use default_texcoords */ const vec2_t texcoords[] = { { 0.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 0.0 }, { 0.0, 0.0 } }; if (e->flags & RF_SHADOW) { R_BindTexture(shadow->texnum); } else { assert(e->deathTexture); R_BindTexture(e->deathTexture->texnum); } R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoords); R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, points); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); refdef.batchCount++; } if (e->flags & RF_ACTOR) { const float size = 15.0; int texnum; /* draw the circles for team-members and allied troops */ vec4_t color = {1, 1, 1, 1}; const vec3_t points[] = { { -size, size, -GROUND_DELTA }, { size, size, -GROUND_DELTA }, { size, -size, -GROUND_DELTA }, { -size, -size, -GROUND_DELTA } }; /** @todo use default_texcoords */ const vec2_t texcoords[] = { { 0.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 0.0 }, { 0.0, 0.0 } }; if (e->flags & RF_MEMBER) Vector4Set(color, 0, 1, 0, 0.5); else if (e->flags & RF_ALLIED) Vector4Set(color, 0, 1, 0.5, 0.5); else if (e->flags & RF_NEUTRAL) Vector4Set(color, 1, 1, 0, 0.5); else if (e->flags & RF_OPPONENT) Vector4Set(color, 1, 0, 0, 0.5); else Vector4Set(color, 0.4, 0.4, 0.4, 0.5); if (e->flags & RF_SELECTED) texnum = selectedActorIndicator->texnum; else texnum = actorIndicator->texnum; R_BindTexture(texnum); R_Color(color); R_EnableDrawAsGlow(qtrue); /* circle points */ R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, texcoords); R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, points); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); refdef.batchCount++; /* add transparency when something is other the circle */ color[3] *= 0.25; R_Color(color); glDepthFunc(GL_GREATER); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDepthFunc(oldDepthFunc); refdef.batchCount++; R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); R_Color(NULL); R_EnableDrawAsGlow(qfalse); } glPopMatrix(); } }
/* * R_DrawShadowmaps */ void R_DrawShadowmaps( void ) { unsigned int i; image_t *shadowmap; int textureWidth, textureHeight; float lodScale; vec3_t lodOrigin; vec3_t viewerOrigin; shadowGroup_t *group; int shadowBits = rn.shadowBits; refdef_t refdef; int lod; float farClip; if( !rsc.numShadowGroups ) return; if( rn.renderFlags & RF_SHADOWMAPVIEW ) return; if( rn.refdef.rdflags & RDF_NOWORLDMODEL ) return; if( !shadowBits ) return; if( !R_PushRefInst() ) { return; } lodScale = rn.lod_dist_scale_for_fov; VectorCopy( rn.lodOrigin, lodOrigin ); VectorCopy( rn.viewOrigin, viewerOrigin ); refdef = rn.refdef; // find lighting group containing entities with same lightingOrigin as ours for( i = 0; i < rsc.numShadowGroups; i++ ) { if( !shadowBits ) { break; } group = rsc.shadowGroups + i; if( !( shadowBits & group->bit ) ) { continue; } shadowBits &= ~group->bit; // make sure we don't render the same shadowmap twice in the same scene frame if( rsc.renderedShadowBits & group->bit ) { continue; } rsc.renderedShadowBits |= group->bit; // calculate LOD for shadowmap lod = (int)((DistanceFast( group->origin, lodOrigin ) * lodScale) / group->projDist); if( lod < 0 ) { lod = 0; } // allocate/resize the texture if needed shadowmap = R_GetShadowmapTexture( i, rsc.refdef.width, rsc.refdef.height, 0 ); assert( shadowmap && shadowmap->upload_width && shadowmap->upload_height ); group->shadowmap = shadowmap; textureWidth = shadowmap->upload_width; textureHeight = shadowmap->upload_height; if( !shadowmap->fbo ) { continue; } farClip = R_SetupShadowmapView( group, &refdef, lod ); // ignore shadowmaps of very low detail level if( refdef.width < SHADOWMAP_MIN_VIEWPORT_SIZE || refdef.height < SHADOWMAP_MIN_VIEWPORT_SIZE ) { continue; } if( shadowmap->flags & IT_DEPTH ) { rn.fbColorAttachment = NULL; rn.fbDepthAttachment = shadowmap; } else { rn.fbColorAttachment = shadowmap; rn.fbDepthAttachment = NULL; } rn.farClip = farClip; rn.renderFlags = RF_SHADOWMAPVIEW|RF_FLIPFRONTFACE; rn.clipFlags |= 16; // clip by far plane too rn.meshlist = &r_shadowlist; rn.shadowGroup = group; rn.lod_dist_scale_for_fov = lodScale; VectorCopy( viewerOrigin, rn.pvsOrigin ); VectorCopy( lodOrigin, rn.lodOrigin ); // 3 pixels border on each side to prevent nasty stretching/bleeding of shadows, // also accounting for smoothing done in the fragment shader Vector4Set( rn.viewport, refdef.x + 3,refdef.y + textureHeight - refdef.height + 3, refdef.width - 6, refdef.height - 6 ); Vector4Set( rn.scissor, refdef.x, refdef.y, textureWidth, textureHeight ); R_RenderView( &refdef ); Matrix4_Copy( rn.cameraProjectionMatrix, group->cameraProjectionMatrix ); } R_PopRefInst( 0 ); }
/* * CG_CalcViewWeapon */ void CG_CalcViewWeapon( cg_viewweapon_t *viewweapon ) { orientation_t tag; weaponinfo_t *weaponInfo; vec3_t gunAngles; vec3_t gunOffset; float fallfrac, fallkick; CG_ViewWeapon_RefreshAnimation( viewweapon ); //if( cg.view.thirdperson ) // return; weaponInfo = CG_GetWeaponInfo( viewweapon->weapon ); viewweapon->ent.model = weaponInfo->model[HAND]; viewweapon->ent.renderfx = RF_MINLIGHT|RF_WEAPONMODEL|RF_FORCENOLOD|(cg_shadows->integer < 2 ? RF_NOSHADOW : 0); viewweapon->ent.scale = 1.0f; viewweapon->ent.customShader = NULL; viewweapon->ent.customSkin = NULL; viewweapon->ent.rtype = RT_MODEL; Vector4Set( viewweapon->ent.shaderRGBA, 255, 255, 255, 255 ); // calculate the entity position #if 1 VectorCopy( cg.view.origin, viewweapon->ent.origin ); #else VectorCopy( cg.predictedPlayerState.pmove.origin, viewweapon->ent.origin ); viewweapon->ent.origin[2] += cg.predictedPlayerState.viewheight; #endif // weapon config offsets VectorAdd( weaponInfo->handpositionAngles, cg.predictedPlayerState.viewangles, gunAngles ); gunOffset[FORWARD] = cg_gunz->value + weaponInfo->handpositionOrigin[FORWARD]; gunOffset[RIGHT] = cg_gunx->value + weaponInfo->handpositionOrigin[RIGHT]; gunOffset[UP] = cg_guny->value + weaponInfo->handpositionOrigin[UP]; // hand cvar offset if( cgs.demoPlaying ) { if( hand->integer == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( hand->integer == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } else { if( cgs.clientInfo[cg.view.POVent-1].hand == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( cgs.clientInfo[cg.view.POVent-1].hand == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } // fallkick offset if( cg.weapon.fallEff_Time > cg.time ) { fallfrac = (float)( cg.time - cg.weapon.fallEff_rebTime ) / (float)( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ); fallkick = sin( DEG2RAD( fallfrac*180 ) ) * ( ( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ) * 0.01f ); } else { cg.weapon.fallEff_Time = cg.weapon.fallEff_rebTime = 0; fallkick = fallfrac = 0; } gunOffset[UP] -= fallkick; // apply the offsets #if 1 VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &cg.view.axis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &cg.view.axis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &cg.view.axis[AXIS_UP], viewweapon->ent.origin ); #else Matrix3_FromAngles( cg.predictedPlayerState.viewangles, offsetAxis ); VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &offsetAxis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &offsetAxis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &offsetAxis[AXIS_UP], viewweapon->ent.origin ); #endif // add angles effects CG_ViewWeapon_AddAngleEffects( gunAngles ); // finish AnglesToAxis( gunAngles, viewweapon->ent.axis ); if( cg_gun_fov->integer && !cg.predictedPlayerState.pmove.stats[PM_STAT_ZOOMTIME] ) { float gun_fov = bound( 20, cg_gun_fov->value, 160 ); float fracWeapFOV = ( 1.0f / cg.view.fracDistFOV ) * tan( gun_fov * ( M_PI/180 ) * 0.5f ); VectorScale( &viewweapon->ent.axis[AXIS_FORWARD], fracWeapFOV, &viewweapon->ent.axis[AXIS_FORWARD] ); } // if the player doesn't want to view the weapon we still have to build the projection source if( CG_GrabTag( &tag, &viewweapon->ent, "tag_weapon" ) ) CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, tag.origin, tag.axis ); else CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, vec3_origin, axis_identity ); }
void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t * points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime) { int i; float radius, iDist; vec3_t xyz; vec4_t omniProjection; decalVert_t dv[4]; decalProjector_t *dp, temp; /* first frame rendered does not have a valid decals list */ if(tr.refdef.decalProjectors == NULL) { return; } /* dummy check */ if(numPoints != 1 && numPoints != 3 && numPoints != 4) { ri.Printf(PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints); return; } /* early outs */ if(lifeTime == 0) { return; } if(projection[3] <= 0.0f) { return; } /* set times properly */ if(lifeTime < 0 || fadeTime < 0) { lifeTime = 0; fadeTime = 0; } /* basic setup */ temp.shader = R_GetShaderByHandle(hShader); /* debug code */ temp.numPlanes = temp.shader->entityMergable; temp.color[0] = color[0] * 255; temp.color[1] = color[1] * 255; temp.color[2] = color[2] * 255; temp.color[3] = color[3] * 255; temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; temp.fadeEndTime = temp.fadeStartTime + fadeTime; /* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */ dv[0].st[0] = 0.0f; dv[0].st[1] = 0.0f; dv[1].st[0] = 0.0f; dv[1].st[1] = 1.0f; dv[2].st[0] = 1.0f; dv[2].st[1] = 1.0f; dv[3].st[0] = 1.0f; dv[3].st[1] = 0.0f; /* omnidirectional? */ if(numPoints == 1) { /* set up omnidirectional */ numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[3]; Vector4Set(omniProjection, 0.0f, 0.0f, -1.0f, radius * 2.0f); projection = omniProjection; iDist = 1.0f / (radius * 2.0f); /* set corner */ VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); /* make x axis texture matrix (yz) */ VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f); temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz); VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist); temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz); /* make y axis texture matrix (xz) */ VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f); temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz); VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist); temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz); /* make z axis texture matrix (xy) */ VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f); temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz); VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f); temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz); /* setup decal points */ VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius); } else { /* set up unidirectional */ temp.omnidirectional = qfalse; /* set up decal points */ VectorCopy(points[0], dv[0].xyz); VectorCopy(points[1], dv[1].xyz); VectorCopy(points[2], dv[2].xyz); VectorCopy(points[3], dv[3].xyz); /* make texture matrix */ if(!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2])) { return; } } /* bound the projector */ ClearBounds(temp.mins, temp.maxs); for(i = 0; i < numPoints; i++) { AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs); VectorMA(dv[i].xyz, projection[3], projection, xyz); AddPointToBounds(xyz, temp.mins, temp.maxs); } /* make bounding sphere */ VectorAdd(temp.mins, temp.maxs, temp.center); VectorScale(temp.center, 0.5f, temp.center); VectorSubtract(temp.maxs, temp.center, xyz); temp.radius = VectorLength(xyz); temp.radius2 = temp.radius * temp.radius; /* frustum cull the projector (fixme: this uses a stale frustum!) */ if(R_CullPointAndRadius(temp.center, temp.radius) == CULL_OUT) { return; } /* make the front plane */ if(!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz)) { return; } /* make the back plane */ VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]); VectorMA(dv[0].xyz, projection[3], projection, xyz); temp.planes[1][3] = DotProduct(xyz, temp.planes[1]); /* make the side planes */ for(i = 0; i < numPoints; i++) { VectorMA(dv[i].xyz, projection[3], projection, xyz); if(!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz)) { return; } } /* create a new projector */ dp = &tr.refdef.decalProjectors[r_numDecalProjectors & DECAL_PROJECTOR_MASK]; Com_Memcpy(dp, &temp, sizeof(*dp)); /* we have a winner */ r_numDecalProjectors++; }
/* ================= RE_AddDecal Adds a single decal to the decal list ================= */ void RE_GL_AddDecal (vec3_t origin, vec3_t dir, vec4_t color, float size, int type, int flags, float angle) { int i, j, numfragments; vec3_t verts[MAX_DECAL_VERTS], shade, temp; markFragment_t *fr, fragments[MAX_FRAGMENTS_PER_DECAL]; vec3_t axis[3]; cdecal_t *d; float lightspot[3]; if (!gl_decals->value) return; // invalid decal size if (size <= 0) return; // a hack to produce decals from explosions etc if (VectorCompare(dir, vec3_origin)) { float scale = 1.5 * size; trace_t trace; vec3_t end, dirs[6] = { { 1.0, 0.0, 0.0 }, { -1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 } }; for (i = 0; i < 6; i++) { VectorMA(origin, scale, dirs[i], end); trace = CL_Trace(origin, end, 0, MASK_SOLID); if (trace.fraction != 1.0) RE_GL_AddDecal(origin, trace.plane.normal, color, size, type, flags, angle); } return; } // calculate orientation matrix VectorNormalize2(dir, axis[0]); PerpendicularVector(axis[1], axis[0]); RotatePointAroundVector(axis[2], axis[0], axis[1], angle); CrossProduct(axis[0], axis[2], axis[1]); // clip it against the world numfragments = R_GetClippedFragments(origin, axis, size, MAX_DECAL_VERTS, verts, MAX_FRAGMENTS_PER_DECAL, fragments); if (!numfragments) return; // no valid fragments // store out vertex data size = 0.5f / size; VectorScale(axis[1], size, axis[1]); VectorScale(axis[2], size, axis[2]); for (i = 0, fr = fragments; i < numfragments; i++, fr++) { // check if we have hit the max if (fr->numPoints > MAX_DECAL_VERTS) fr->numPoints = MAX_DECAL_VERTS; else if (fr->numPoints <= 0) continue; d = R_AllocDecal(); d->time = r_newrefdef.time; d->node = fr->node; VectorCopy(fr->surf->plane->normal, d->direction); if (!(fr->surf->flags & SURF_PLANEBACK)) VectorNegate(d->direction, d->direction); // reverse direction Vector4Set(d->color, color[0], color[1], color[2], color[3]); VectorCopy(origin, d->org); //if (flags & DF_SHADE) { R_LightPoint(origin, shade, lightspot); for (j = 0; j < 3; j++) d->color[j] = (d->color[j] * shade[j] * 0.6) + (d->color[j] * 0.4); } d->type = type; d->flags = flags; // make the decal vert d->numverts = fr->numPoints; for (j = 0; j < fr->numPoints && j < MAX_VERTS_PER_FRAGMENT; j++) { // xyz VectorCopy(verts[fr->firstPoint + j], d->verts[j]); // st VectorSubtract(d->verts[j], origin, temp); d->stcoords[j][0] = DotProduct(temp, axis[1]) + 0.5f; d->stcoords[j][1] = DotProduct(temp, axis[2]) + 0.5f; } } }
/** * @brief Draw a model from the battlescape entity list * @sa R_GetEntityLists */ void R_DrawAliasModel (entity_t *e) { mAliasModel_t *mod = &e->model->alias; /* the values are sane here already - see R_GetEntityLists */ const image_t *skin = mod->meshes[e->as.mesh].skins[e->skinnum].skin; int i; float g; vec4_t color = {0.8, 0.8, 0.8, 1.0}; mAliasMesh_t *mesh; /* IR goggles override color for entities that are affected */ if ((refdef.rendererFlags & RDF_IRGOGGLES) && (e->flags & RF_IRGOGGLES)) Vector4Set(e->shell, 1.0, 0.3, 0.3, 1.0); if (e->flags & RF_PULSE) { /* and then adding in a pulse */ const float f = 1.0 + sin((refdef.time + (e->model->alias.meshes[0].num_tris)) * 6.0) * 0.33; VectorScale(color, 1.0 + f, color); } g = 0.0; /* find brightest component */ for (i = 0; i < 3; i++) { if (color[i] > g) /* keep it */ g = color[i]; } /* scale it back to 1.0 */ if (g > 1.0) VectorScale(color, 1.0 / g, color); R_Color(color); assert(skin->texnum > 0); R_BindTexture(skin->texnum); R_EnableGlowMap(skin->glowmap); R_UpdateLightList(e); R_EnableModelLights(e->lights, e->numLights, qtrue); /** @todo this breaks the encapsulation - don't call CL_* functions from within the renderer code */ if (r_debug_lights->integer) { for (i = 0; i < e->numLights && i < r_dynamic_lights->integer; i++) CL_ParticleSpawn("lightTracerDebug", 0, e->transform.matrix + 12, e->lights[i]->origin, NULL); } if (skin->normalmap) R_EnableBumpmap(skin->normalmap); if (skin->specularmap) R_EnableSpecularMap(skin->specularmap, qtrue); if (skin->roughnessmap) R_EnableRoughnessMap(skin->roughnessmap, qtrue); glPushMatrix(); glMultMatrixf(e->transform.matrix); if (VectorNotEmpty(e->scale)) glScalef(e->scale[0], e->scale[1], e->scale[2]); mesh = R_DrawAliasModelBuffer(e); if (r_state.specularmap_enabled) R_EnableSpecularMap(NULL, qfalse); if (r_state.roughnessmap_enabled) R_EnableRoughnessMap(NULL, qfalse); R_EnableModelLights(NULL, 0, qfalse); R_EnableGlowMap(NULL); if (r_state.active_normalmap) R_EnableBumpmap(NULL); R_DrawMeshShadow(e, mesh); if (mod->num_frames == 1) R_ResetArraysAfterStaticMeshRender(); glPopMatrix(); /* show model bounding box */ if (r_showbox->integer) R_DrawBoundingBox(mod->frames[e->as.frame].mins, mod->frames[e->as.frame].maxs); R_Color(NULL); }
void RF_SetScissor( int x, int y, int w, int h ) { rrf.frame->SetScissor( rrf.frame, x, y, w, h ); Vector4Set( rrf.scissor, x, y, w, h ); }