void CG_RunTestEmitter() { if ( cg_testEmitter.getStr()[0] == 0 || cg_testEmitter.getStr()[0] == '0' ) { CG_FreeTestEmitter(); return; } class particleDeclAPI_i* pDecl = g_declMgr->registerParticleDecl( cg_testEmitter.getStr() ); if ( pDecl == 0 ) { CG_FreeTestEmitter(); return; } if ( cg_testEmitterInstance == 0 ) { cg_testEmitterInstance = new emitterD3_c; rf->addCustomRenderObject( cg_testEmitterInstance ); cg_testEmitterInstance->setOrigin( cg.refdefViewOrigin + cg.refdefViewAxis.getForward()*cg_testEmitter_cameraDistance.getFloat() ); } else { if ( cg_testEmitter_attachToCamera.getInt() ) { cg_testEmitterInstance->setOrigin( cg.refdefViewOrigin + cg.refdefViewAxis.getForward()*cg_testEmitter_cameraDistance.getFloat() ); } } cg_testEmitterInstance->setParticleDecl( pDecl ); }
void procTree_c::addDrawCalls() { visCount++; if ( nodes.size() == 0 ) { for ( u32 i = 0; i < models.size(); i++ ) { models[i]->addDrawCalls(); } return; } camArea = pointArea( rf_camera.getPVSOrigin() ); if ( rf_proc_printCamArea.getInt() ) { g_core->Print( "camera is in area %i of %i\n", camArea, areas.size() ); } // if camera is outside world or if we're debug-drawing all areas if ( camArea == -1 || rf_proc_ignorePortals.getInt() ) { addDrawCallsForAllAreas(); return; } frustumExt_c baseFrustum( rf_camera.getFrustum() ); addAreaDrawCalls_r( camArea, baseFrustum, 0 ); }
void rIndexedShadowVolume_c::createDirectionalShadowVolumeForEntity( class rEntityImpl_c* ent, const vec3_c& lightDirection, float lightInfinity ) { clear(); // save the last light position //this->lightPos = light; if ( ent == 0 ) return; if ( ent->getModel() == 0 ) return; if ( ent->isAnimated() && rf_skipAnimatedObjectsShadows.getInt() ) return; const r_model_c* m = ent->getCurrentRModelInstance(); if ( m ) { fromDirectionalRModel( m, lightDirection, lightInfinity ); } else { rModelAPI_i* modAPI = ent->getModel(); if ( modAPI ) { if ( modAPI->isInlineBSPModel() ) { r_model_c tmp; modAPI->getModelData( &tmp ); //tmp.transform(ent->getMatrix()); fromRModel( &tmp, lightDirection, lightInfinity ); } else if ( modAPI->isStatic() ) { class model_c* m = dynamic_cast<model_c*>( modAPI ); if ( m ) { fromDirectionalRModel( m->getRModel(), lightDirection, lightInfinity ); } else { g_core->RedWarning( "rIndexedShadowVolume_c::createDirectionalShadowVolumeForEntity: dynamic_cast to model_c failed for model %s.\n", modAPI->getName() ); } } } } if ( rf_printShadowVolumesStats.getInt() ) { g_core->Print( "rIndexedShadowVolume_c::createDirectionalShadowVolumeForEntity: (time %i) %i points, %i tris for model %s (%i edge quads, %i cap pairs)\n", rf_curTimeMsec, points.size(), indices.getNumIndices() / 3, ent->getModelName(), this->c_edgeQuadsAdded, this->c_capTriPairsAdded ); } }
virtual void setupProjection3D( const projDef_s* pd ) { if ( pd == 0 ) { projDef.setDefaults(); } else { projDef = *pd; } if ( rf_forceZFar.getFloat() >= 0.f ) { projDef.zFar = rf_forceZFar.getFloat(); } }
bool tsOctTreeHeader_s::logBoxTri( const class aabb& bounds, class boxTrianglesCallback_i* callback, u32 triangleNum ) { // see if the triangle was already checked if ( cms_tsOctTree_useCheckCounts.getInt() && this->triCheckCounts[triangleNum] == this->checkCount ) { return false; } // mark as already checked this->triCheckCounts[triangleNum] = this->checkCount; const u32* indices = this->getTriIndexes(); u32 i0 = indices[triangleNum * 3 + 0]; u32 i1 = indices[triangleNum * 3 + 1]; u32 i2 = indices[triangleNum * 3 + 2]; const vec3_c& p0 = this->getTriPoints()[i0]; const vec3_c& p1 = this->getTriPoints()[i1]; const vec3_c& p2 = this->getTriPoints()[i2]; aabb tmpBB; tmpBB.fromThreePoints( p0, p1, p2 ); if ( tmpBB.intersect( bounds ) == false ) return false; callback->onBoxTriangle( p0, p1, p2 ); return true; }
void rSunLight_c::addSunLightShadowVolumes() { if ( mainVolume == 0 ) { mainVolume = new rIndexedShadowVolume_c; const r_model_c* m = RF_GetWorldModel(); if ( m ) { for ( u32 i = 0; i < m->getNumSurfs(); i++ ) { if ( m->getSurf( i )->findSunMaterial() ) continue; if ( rf_usePointLightForSun.getInt() ) { mainVolume->addRSurface( m->getSurf( i ), getFakePointLightPosition(), 0, getFakePointLightRadius() ); } else { mainVolume->addDirectionalRSurface( m->getSurf( i ), RF_GetSunDirection(), 5000 ); } } } } for ( u32 i = 0; i < entityInteractions.size(); i++ ) { entityInteractions[i]->updateSunLightInteraction(); } mainVolume->addDrawCall(); }
void updateSunLightInteraction() { if ( ent->hasStageWithoutBlendFunc() == false ) { if ( shadowVolume ) { delete shadowVolume; shadowVolume = 0; } return; } if ( shadowVolume == 0 ) { shadowVolume = new rIndexedShadowVolume_c; } else { if ( ent->isAnimated() == false ) { if ( absSilChangeCount == ent->getSilChangeCount() ) { if ( rf_sunLight_printUnchangedInteractions.getInt() ) { g_core->Print( "sunLightEntityInteraction_c::updateSunLightInteraction: %s didnt change\n", ent->getModelName() ); } addDrawCall(); return; } } } ent->updateAnimatedEntity(); absSilChangeCount = ent->getSilChangeCount(); if ( rf_usePointLightForSun.getInt() ) { vec3_c pos = rf_sunLight->getFakePointLightPosition(); ent->getMatrix().getInversed().transformPoint( pos ); shadowVolume->createShadowVolumeForEntity( ent, pos, rf_sunLight->getFakePointLightRadius() ); } else { vec3_c dir = RF_GetSunDirection(); ent->getMatrix().getInversed().transformNormal( dir ); shadowVolume->createDirectionalShadowVolumeForEntity( ent, dir, 5000 ); } addDrawCall(); }
bool procTree_c::cullBoundsByPortals( const aabb& absBB ) { if ( rf_proc_ignoreCullBounds.getInt() ) return false; // didnt cull arraySTD_c<u32> areaNums; boxAreas( absBB, areaNums ); return cullBoundsByPortals( absBB, areaNums ); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_s* ps; // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; cg.refdefViewOrigin = ps->origin; cg.refdefViewAngles = ps->viewangles; // add first person / third person view offset if ( cg_thirdPerson.integer ) { // back away from character CG_OffsetThirdPersonView(); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); } cg.refdefViewAxis.fromAngles( cg.refdefViewAngles ); if ( cg_printCurCamPos.getInt() ) { CG_Printf( "CG_CalcViewValues: camera eye is at %f %f %f\n", cg.refdefViewOrigin[0], cg.refdefViewOrigin[1], cg.refdefViewOrigin[2] ); } if ( cg_printCurFarPlane.getInt() ) { CG_Printf( "CG_CalcViewValues: cg.farPlane is %f\n", cg.farPlane ); } projDef_s projDef; projDef.setDefaults(); if ( cg.farPlane >= 8.f ) { projDef.zFar = cg.farPlane; } rf->setupProjection3D( &projDef ); rf->setup3DView( cg.refdefViewOrigin, cg.refdefViewAngles, cg_thirdPerson.integer ); return 0; }
u32 rIndexedShadowVolume_c::registerPoint( const vec3_c& p ) { bounds.addPoint( p ); if ( rf_ssv_hashVertices.getInt() ) { return points.registerVec3( p ); } return points.addPoint( p ); }
static void CG_DoRailgunEffect() { // va("doRailgunEffect railCore railDisc railExplosion gfx/damage/plasma_mrk %f %f %f %f %f %f %i",muzzle.x,muzzle.y,muzzle.z, vec3_c p, d; str coreMaterialName = CG_Argv( 1 ); str discMaterialName = CG_Argv( 2 ); str explosionMaterialName = CG_Argv( 3 ); str decalMaterialName = CG_Argv( 4 ); p.x = atof( CG_Argv( 5 ) ); p.y = atof( CG_Argv( 6 ) ); p.z = atof( CG_Argv( 7 ) ); d.x = atof( CG_Argv( 8 ) ); d.y = atof( CG_Argv( 9 ) ); d.z = atof( CG_Argv( 10 ) ); int skipEntityNum = atoi( CG_Argv( 11 ) ); CG_Printf( "CG_DoRailgunEffect: from %f %f %f, dir %f %f %f\n", p.x, p.y, p.z, d.x, d.y, d.z ); trace_c tr; tr.setupRay( p, d * 100000.f ); if ( CG_RayTrace( tr, skipEntityNum ) == false ) { CG_Printf( "CG_DoRailgunEffect: no hit\n" ); return; // no hit } mtrAPI_i* coreMaterial = g_ms->registerMaterial( coreMaterialName ); mtrAPI_i* diskMaterial = g_ms->registerMaterial( discMaterialName ); CG_AddBulletTracer( tr.getStartPos() - vec3_c( 0, 0, 12 ), tr.getHitPos(), 32.f, coreMaterial, 1000 ); mtrAPI_i* decalMaterial = g_ms->registerMaterial( decalMaterialName ); float radius = 32.f; centity_s* hit = tr.getHitCGEntity(); if ( hit == 0 || hit == &cg_entities[ENTITYNUM_WORLD] ) { CG_Printf( "CG_DoRailgunEffect: hit Worldspawn\n" ); if ( cg_debugDrawBulletAttack.getInt() ) { rf->addDebugLine( tr.getHitPos(), tr.getHitPos() + radius * tr.getHitPlaneNormal(), vec3_c( 1, 0, 0 ), 5.f ); } rf->addWorldMapDecal( tr.getHitPos(), tr.getHitPlaneNormal(), radius, decalMaterial ); } else { CG_Printf( "CG_DoRailgunEffect: hit entity\n" ); if ( hit->rEnt ) { hit->rEnt->addDecalWorldSpace( tr.getHitPos(), tr.getHitPlaneNormal(), radius, decalMaterial ); } else { CG_Printf( "CG_DoRailgunEffect: hit centity has NULL rEnt\n" ); } } }
static void CG_OnEntityOrientationChange( centity_t* cent ) { // NOTE: some centities might have both rEnt and rLight present if ( cent->rEnt ) { cent->rEnt->setOrigin( cent->lerpOrigin ); cent->rEnt->setAngles( cent->lerpAngles ); } if ( cent->rLight ) { if ( cg_printLightFlags.getInt() ) { g_core->Print( "Light entity %i lightFlags %i\n", cent->currentState.number, cent->currentState.lightFlags ); } cent->rLight->setOrigin( cent->lerpOrigin ); // TODO: lerp light radius? cent->rLight->setRadius( cent->currentState.lightRadius ); cent->rLight->setBNoShadows( cent->currentState.lightFlags & LF_NOSHADOWS ); if ( cent->currentState.lightFlags & LF_SPOTLIGHT ) { // see if the spotlight can find it's target const centity_t* target = &cg_entities[cent->currentState.lightTarget]; cent->rLight->setSpotRadius( cent->currentState.spotLightRadius ); cent->rLight->setLightType( LT_SPOTLIGHT ); if ( target->currentValid == false ) { vec3_c targetPos = cent->lerpOrigin + cent->lerpAngles.getForward() * 64.f; cent->rLight->setSpotLightTarget( targetPos ); } else { cent->rLight->setSpotLightTarget( target->lerpOrigin ); } } else { cent->rLight->setLightType( LT_POINT ); } if ( cent->currentState.lightFlags & LF_COLOURED ) { cent->rLight->setBColoured( true ); cent->rLight->setColor( cent->currentState.lightColor ); } else { cent->rLight->setBColoured( false ); } } }
void FuncRotating::runFrame() { float rotateSpeed = 10; float delta = rotateSpeed * level.frameTime; vec3_c a = this->getAngles(); // rotationAxis == 1 -> rotate around Z axis // rotationAxis == 0 -> rotate around Y axis a[rotationAxis] += delta; this->setAngles( a ); if ( g_funcRotating_printOrientation.getInt() ) { g_core->Print( "FuncRotating::runFrame(): pos %f %f %f rot %f %f %f\n", getOrigin().x, getOrigin().y, getOrigin().z, a.x, a.y, a.z ); } }
static void CG_TestBulletAttack() { vec3_c p, d; str decalMaterialName = CG_Argv( 1 ); p.x = atof( CG_Argv( 2 ) ); p.y = atof( CG_Argv( 3 ) ); p.z = atof( CG_Argv( 4 ) ); d.x = atof( CG_Argv( 5 ) ); d.y = atof( CG_Argv( 6 ) ); d.z = atof( CG_Argv( 7 ) ); int skipEntityNum = atoi( CG_Argv( 8 ) ); CG_Printf( "CG_TestBulletAttack: from %f %f %f, dir %f %f %f\n", p.x, p.y, p.z, d.x, d.y, d.z ); trace_c tr; tr.setupRay( p, d * 100000.f ); if ( CG_RayTrace( tr, skipEntityNum ) == false ) { CG_Printf( "CG_TestBulletAttack: no hit\n" ); return; // no hit } //mtrAPI_i *decalMaterial = g_ms->registerMaterial("qiotests/testdecalmaterial"); mtrAPI_i* decalMaterial = g_ms->registerMaterial( decalMaterialName ); float radius = 8.f; centity_s* hit = tr.getHitCGEntity(); if ( hit == &cg_entities[ENTITYNUM_WORLD] ) { CG_Printf( "CG_TestBulletAttack: hit Worldspawn\n" ); if ( cg_debugDrawBulletAttack.getInt() ) { rf->addDebugLine( tr.getHitPos(), tr.getHitPos() + radius * tr.getHitPlaneNormal(), vec3_c( 1, 0, 0 ), 5.f ); } rf->addWorldMapDecal( tr.getHitPos(), tr.getHitPlaneNormal(), radius, decalMaterial ); return; } else { CG_Printf( "CG_TestBulletAttack: hit entity\n" ); if ( hit->rEnt ) { hit->rEnt->addDecalWorldSpace( tr.getHitPos(), tr.getHitPlaneNormal(), radius, decalMaterial ); } else { CG_Printf( "CG_TestBulletAttack: hit centity has NULL rEnt\n" ); } } }
void procTree_c::doDebugDrawing() { if ( rf_proc_showAreaPortals.getInt() ) { for ( u32 i = 0; i < portals.size(); i++ ) { procPortal_c* p = portals[i]; const cmWinding_c& w = p->points; float col[4]; col[0] = ( i % 39 ) / 39.f; col[1] = ( ( i + 10 ) % 47 ) / 47.f; col[2] = ( i % 33 ) / 33.f; col[3] = 1.f; rb->setColor4( col ); rb->drawWinding( w.getArray(), w.size() ); } } }
bool tsOctTreeHeader_s::traceRay( class trace_c& tr ) { this->checkCount++; if ( cms_tsOctTree_checkAllTris.getInt() ) { bool hit = false; u32 numTris = this->numIndexes / 3; for ( u32 i = 0; i < numTris; i++ ) { if ( traceTriangleRay( i, tr ) ) { hit = true; } } return hit; } return traceNodeRay_r( 0, tr ); }
static void CG_CalcEntityLerpPositions( centity_t* cent ) { if ( cent->currentState.parentNum != ENTITYNUM_NONE ) { centity_t* parent = &cg_entities[cent->currentState.parentNum]; if ( parent->rEnt == 0 ) return; if ( cg_printAttachedEntities.getInt() ) { g_core->Print( "Entity %i is attached to %i\n", cent->currentState.number, cent->currentState.parentNum ); } // first we have to update parent orientation (pos + rot), // then we can attach current entity to it CG_RunCEntity( parent ); matrix_c mat; parent->rEnt->getBoneWorldOrientation( cent->currentState.parentTagNum, mat ); cent->lerpAngles = mat.getAngles(); cent->lerpOrigin = mat.getOrigin(); if ( cent->currentState.parentOffset.isAlmostZero() == false ) { matrix_c matAngles = mat; matAngles.setOrigin( vec3_c( 0, 0, 0 ) ); vec3_c ofs; matAngles.transformPoint( cent->currentState.parentOffset, ofs ); cent->lerpOrigin += ofs; } if ( cent->currentState.localAttachmentAngles.isAlmostZero() == false ) { cent->lerpAngles += cent->currentState.localAttachmentAngles; } // NOTE: some centities might have both rEnt and rLight present // update render entity and/or render light CG_OnEntityOrientationChange( cent ); return; } if ( cent->interpolate ) { CG_InterpolateEntityPosition( cent ); return; } }
void rIndexedShadowVolume_c::addRSurface( const class r_surface_c* sf, const vec3_c& light, const struct extraSurfEdgesData_s* edges, float lightRadius ) { const rVertexBuffer_c& verts = sf->getVerts(); const rIndexBuffer_c& indices = sf->getIndices(); const planeArray_c& triPlanes = sf->getTriPlanes(); // see if we have plane equations of triangles if ( triPlanes.size() ) { // see if we have extra edges data if ( edges && ( rf_dontUseExtraEdgeArrays.getInt() == 0 ) ) { addIndexedVertexListWithEdges( indices, verts, light, &triPlanes, edges ); } else { addIndexedVertexList( indices, verts, light, &triPlanes, lightRadius, &sf->getBB() ); } } else { addIndexedVertexList( indices, verts, light, 0, lightRadius, &sf->getBB() ); } }
void rIndexedShadowVolume_c::fromRModel( const class r_model_c* m, const vec3_c& light, float lightRadius ) { clear(); if ( m == 0 ) { g_core->RedWarning( "rIndexedShadowVolume_c::fromRModel: NULL model pointer.\n" ); return; } this->points.setEqualVertexEpsilon( 0.f ); #if 0 ( ( r_model_c* )m )->precalculateStencilShadowCaster(); #endif if ( m->getStencilShadowCaster() && rf_dontUsePrecomputedSSVCasters.getInt() == 0 ) { this->fromPrecalculatedStencilShadowCaster( m->getStencilShadowCaster(), light ); return; } for ( u32 i = 0; i < m->getNumSurfs(); i++ ) { const r_surface_c* sf = m->getSurf( i ); addRSurface( sf, light, sf->getExtraSurfEdgesData(), lightRadius ); } }
// ====================================== // // tsOctTreeHeader_s collision detection // // ====================================== bool tsOctTreeHeader_s::traceTriangleRay( u32 triangleNum, class trace_c& tr ) { // see if the triangle was already checked if ( cms_tsOctTree_useCheckCounts.getInt() && this->triCheckCounts[triangleNum] == this->checkCount ) { return false; } // mark as already checked this->triCheckCounts[triangleNum] = this->checkCount; const u32* indices = this->getTriIndexes(); u32 i0 = indices[triangleNum * 3 + 0]; u32 i1 = indices[triangleNum * 3 + 1]; u32 i2 = indices[triangleNum * 3 + 2]; const vec3_c& p0 = this->getTriPoints()[i0]; const vec3_c& p1 = this->getTriPoints()[i1]; const vec3_c& p2 = this->getTriPoints()[i2]; if ( tr.clipByTriangle( p0, p1, p2, true ) ) { tr.setHitTriangleIndex( triangleNum ); return true; } return false; }
/* ============= SV_EmitPacketEntities Writes a delta update of an entityState_s list to the message. ============= */ static void SV_EmitPacketEntities( clientSnapshot_t* from, clientSnapshot_t* to, msg_s* msg ) { entityState_s* oldent, *newent; int oldindex, newindex; int oldnum, newnum; int from_num_entities; // generate the delta update if ( !from ) { from_num_entities = 0; } else { from_num_entities = from->num_entities; } newent = NULL; oldent = NULL; newindex = 0; oldindex = 0; while ( newindex < to->num_entities || oldindex < from_num_entities ) { if ( newindex >= to->num_entities ) { newnum = 9999; } else { newent = &svs.snapshotEntities[( to->first_entity + newindex ) % svs.numSnapshotEntities]; newnum = newent->number; } if ( oldindex >= from_num_entities ) { oldnum = 9999; } else { oldent = &svs.snapshotEntities[( from->first_entity + oldindex ) % svs.numSnapshotEntities]; oldnum = oldent->number; } if ( newnum == oldnum ) { if ( sv_debugPlayerSnapshotEntities.getInt() == to->ps.number ) { //Com_Printf("SV_EmitPacketEntities: delting entity %i from player %i view\n", // oldnum,from->ps.number); } // delta update from old position // because the force parm is false, this will not result // in any bytes being emited if the entity has not changed at all MSG_WriteDeltaEntity( msg, oldent, newent, false ); oldindex++; newindex++; continue; } if ( newnum < oldnum ) { if ( sv_debugPlayerSnapshotEntities.getInt() == to->ps.number ) { Com_Printf( "SV_EmitPacketEntities: adding entity %i from player %i view\n", newnum, to->ps.number ); } // this is a new entity, send it from the baseline MSG_WriteDeltaEntity( msg, &sv.svEntities[newnum].baseline, newent, true ); newindex++; continue; } if ( newnum > oldnum ) { if ( sv_debugPlayerSnapshotEntities.getInt() == to->ps.number ) { Com_Printf( "SV_EmitPacketEntities: removing entity %i from player %i view\n", oldnum, to->ps.number ); } // the old entity isn't present in the new message MSG_WriteDeltaEntity( msg, oldent, NULL, true ); oldindex++; continue; } } MSG_WriteBits( msg, ( MAX_GENTITIES - 1 ), GENTITYNUM_BITS ); // end of packetentities }
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t* frame, snapshotEntityNumbers_t* eNums, bool portal, bitSet_c& areaBits ) { int e;//, i; edict_s* ent; svEntity_t* svEnt; //int l; // during an error shutdown message we may need to transmit // the shutdown message after the server has shutdown, so // specfically check for it if ( !sv.state ) { return; } bspPointDesc_s eyeDesc; // for .bsp PVS pvsHandle_t procVisHandle; // for .proc vis if ( sv_bsp ) { sv_bsp->filterPoint( origin, eyeDesc ); sv_bsp->appendCurrentAreaBits( eyeDesc.area, areaBits ); } else if ( sv_procVis ) { procVisHandle = sv_procVis->SetupCurrentPVS( origin ); } for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum( e ); // never send entities that aren't active if ( ent->s == 0 ) { continue; } if ( ent->s->number != e ) { Com_DPrintf( "FIXING ENT->S.NUMBER!!!\n" ); ent->s->number = e; } // never send entities that aren't visible if ( ent->s->isHidden() ) { continue; } // never send ai waypoints (pathnodes) if ( ent->s->eType == ET_PATHNODE ) { continue; } edict_s* visEnt = ent; while ( visEnt->s->parentNum != ENTITYNUM_NONE ) { visEnt = SV_GentityNum( visEnt->s->parentNum ); } if ( visEnt->bspBoxDesc == 0 ) { continue; // not linked } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } if ( sv_cullEntities.getInt() ) { if ( sv_bsp && sv_bsp->checkVisibility( eyeDesc, *visEnt->bspBoxDesc ) == false ) { continue; // culled by .bsp PVS } if ( sv_procVis && sv_procVis->InCurrentPVS( procVisHandle, visEnt->bspBoxDesc->areas.getArray(), visEnt->bspBoxDesc->areas.size() ) == false ) { continue; // culled by Doom3 .proc vis } } SV_AddEntToSnapshot( svEnt, ent, eNums ); } if ( sv_procVis ) { sv_procVis->FreeCurrentPVS( procVisHandle ); } }
void rIndexedShadowVolume_c::addIndexedVertexList( const rIndexBuffer_c& oIndices, const rVertexBuffer_c& oVerts, const vec3_c& light, const class planeArray_c* extraPlanesArray, float lightRadius, const class aabb* bounds ) { #if 1 // for a single triangle, in worst case we might need to create: // front cap + end cap + 3 edge quads // 1 + 1 + 3 * 2 = 2 + 6 = 8 triangles indices.ensureAllocated_indices( indices.getNumIndices() + oIndices.getNumTriangles() * 8 * 3 ); points.ensureAllocated( points.size() + oVerts.size() * 2 ); #endif #ifdef OPTIMIZE_SLOW_ADDTRIANGLE if ( indices.getU16Ptr() == 0 ) return; u16* pFirstIndex = ( ( u16* )indices.getU16Ptr() ) + indices.getNumIndices(); u16* pNextIndex = pFirstIndex; #endif if ( rf_ssv_algorithm.getInt() == 0 ) { for ( u32 i = 0; i < oIndices.getNumIndices(); i += 3 ) { u32 i0 = oIndices[i + 0]; u32 i1 = oIndices[i + 1]; u32 i2 = oIndices[i + 2]; const vec3_c& v0 = oVerts[i0].xyz; const vec3_c& v1 = oVerts[i1].xyz; const vec3_c& v2 = oVerts[i2].xyz; addTriangle( v0, v1, v2, light ); } } else { bool bMeshFullyInsideLight; if ( bounds ) { bMeshFullyInsideLight = IsAABBInsideSphere( *bounds, light, lightRadius ); } else { bMeshFullyInsideLight = false; } // do the same thing as above, but a little faster way static arraySTD_c<byte> bPointTransformed; if ( bPointTransformed.size() < oVerts.size() ) { bPointTransformed.resize( oVerts.size() ); } bPointTransformed.nullMemory(); static arraySTD_c<vec3_c> pointsTransformed; if ( pointsTransformed.size() < oVerts.size() ) { pointsTransformed.resize( oVerts.size() ); } u32 tri = 0; for ( u32 i = 0; i < oIndices.getNumIndices(); i += 3, tri++ ) { u32 vi0 = oIndices[i + 0]; u32 vi1 = oIndices[i + 1]; u32 vi2 = oIndices[i + 2]; const vec3_c& p0 = oVerts[vi0].xyz; const vec3_c& p1 = oVerts[vi1].xyz; const vec3_c& p2 = oVerts[vi2].xyz; // cull triangles that are outside light radius // This is a good optimisation for very large models intersecting very small lights if ( rf_ssv_cullTrianglesOutSideLightSpheres.getInt() ) { // we can't cull that way any triangles if mesh bounds are entirely inside light sphere if ( bMeshFullyInsideLight == false ) { if ( CU_IntersectSphereTriangle( light, lightRadius, p0, p1, p2 ) == false ) { continue; } } } float d; if ( extraPlanesArray == 0 ) { plane_c triPlane; triPlane.fromThreePoints( p2, p1, p0 ); d = triPlane.distance( light ); } else { d = extraPlanesArray->getArray()[tri].distance( light ); } if ( d > 0 ) { continue; } vec3_c& p0Projected = pointsTransformed[vi0]; if ( bPointTransformed[vi0] == 0 ) { bPointTransformed[vi0] = 1; p0Projected = p0 - light; p0Projected.normalizeFast(); p0Projected *= getShadowVolumeInf(); p0Projected += p0; } vec3_c& p1Projected = pointsTransformed[vi1]; if ( bPointTransformed[vi1] == 0 ) { bPointTransformed[vi1] = 1; p1Projected = p1 - light; p1Projected.normalizeFast(); p1Projected *= getShadowVolumeInf(); p1Projected += p1; } vec3_c& p2Projected = pointsTransformed[vi2]; if ( bPointTransformed[vi2] == 0 ) { bPointTransformed[vi2] = 1; p2Projected = p2 - light; p2Projected.normalizeFast(); p2Projected *= getShadowVolumeInf(); p2Projected += p2; } u32 i0 = this->registerPoint( p0 ); u32 i1 = this->registerPoint( p1 ); u32 i2 = this->registerPoint( p2 ); u32 pi0 = this->registerPoint( p0Projected ); u32 pi1 = this->registerPoint( p1Projected ); u32 pi2 = this->registerPoint( p2Projected ); #ifdef OPTIMIZE_SLOW_ADDTRIANGLE ADD_TRIANGLE( pNextIndex, i2, i1, i0 ); ADD_TRIANGLE( pNextIndex, pi0, pi1, pi2 ); ADD_QUAD( pNextIndex, i0, i1, pi0, pi1 ); ADD_QUAD( pNextIndex, i1, i2, pi1, pi2 ); ADD_QUAD( pNextIndex, i2, i0, pi2, pi0 ); #else indices.addTriangle( i2, i1, i0 ); indices.addTriangle( pi0, pi1, pi2 ); c_capTriPairsAdded++; indices.addQuad( i0, i1, pi0, pi1 ); c_edgeQuadsAdded++; indices.addQuad( i1, i2, pi1, pi2 ); c_edgeQuadsAdded++; indices.addQuad( i2, i0, pi2, pi0 ); c_edgeQuadsAdded++; #endif } } #ifdef OPTIMIZE_SLOW_ADDTRIANGLE u32 numAddedIndices = pNextIndex - pFirstIndex; indices.forceSetIndexCount( indices.getNumIndices() + numAddedIndices ); #endif }
void procTree_c::cacheLightWorldInteractions( class rLightImpl_c* l ) { if ( rf_proc_useProcDataToOptimizeLighting.getInt() == 0 ) { // get all .proc surfaces withing light bounds and cache'em arraySTD_c<const r_surface_c*> sfs; boxAreaSurfaces( l->getABSBounds(), sfs ); for ( u32 i = 0; i < sfs.size(); i++ ) { l->addStaticModelSurfaceInteraction( ( r_surface_c* )sfs[i] ); } } else { // get shadow-only interactions // It seems we need to render all the surfaces within light bounds, // even if they are not visible for light trough portals arraySTD_c<u32> list; boxAreas( l->getABSBounds(), list ); for ( u32 i = 0; i < list.size(); i++ ) { int areaNum = list[i]; procArea_c* a = areas[areaNum]; r_model_c* m = a->areaModel; for ( u32 j = 0; j < m->getNumSurfs(); j++ ) { l->addProcAreaSurfaceInteraction( areaNum, m->getSurf( j ), SIFT_ONLY_SHADOW ); } } // flood through portals (for lighting interactions) // draw only surfaces that are inside light "view" (affected by portals) litCount++; int lightArea = this->pointArea( l->getOrigin() ); if ( lightArea < 0 ) return; const procArea_c* ar = areas[lightArea]; addSingleAreaSurfacesInteractions( lightArea, l ); for ( u32 i = 0; i < ar->portals.size(); i++ ) { procPortal_c* portal = ar->portals[i]; frustumExt_c fr; // create light->portal frustum fr.fromPointAndWinding( l->getOrigin(), portal->points, portal->plane ); // add far plane //vec3_c center = portal->points.getCenter(); //vec3_c normal = center - l->getOrigin(); //normal.normalize(); //plane_c farPlane; //farPlane.fromPointAndNormal(center,normal); //fr.addPlane(farPlane); /* if(fr.cull(portal->points.getCenter() != CULL_IN) { g_core->RedWarning("bad frustum for portal %i\n",i); }*/ //g_core->Print("procTree_c::cacheLightWorldInteractions: area %i to portal %i frustum has %i planes\n",lightArea,i,fr.size()); int otherArea; if ( lightArea == portal->areas[0] ) { otherArea = portal->areas[1]; } else { otherArea = portal->areas[0]; } cacheLightWorldInteractions_r( l, otherArea, fr, portal ); } } }
void CG_RunViewModel() { if ( cg_printViewWeaponClipSize.getInt() ) { if ( cg.snap ) { g_core->Print( "ViewWeapon clip %i/%i\n", cg.snap->ps.viewWeaponCurClipSize, cg.snap->ps.viewWeaponMaxClipSize ); } } int viewModelEntity = cg.snap->ps.curWeaponEntNum; if ( cg_thirdPerson.integer ) { CG_FreeViewModelEntity(); if ( viewModelEntity != ENTITYNUM_NONE && cg_entities[viewModelEntity].rEnt ) { cg_entities[viewModelEntity].rEnt->showModel(); } return; } if ( viewModelEntity == ENTITYNUM_NONE ) { CG_FreeViewModelEntity(); return; } if ( cg_entities[viewModelEntity].rEnt ) { //cg_entities[viewModelEntity].rEnt->hideModel(); cg_entities[viewModelEntity].rEnt->setThirdPersonOnly( true ); } // local weapons offset (affected by cg_gunX/Y/Z cvars) vec3_c localOfs( 0, 0, 0 ); // local weapon rotation (affected by cg_gunRotX/Y/Z cvars) vec3_c localRot( 0, 0, 0 ); rModelAPI_i* viewModel; if ( cg.snap->ps.customViewRModelIndex ) { viewModel = cgs.gameModels[cg.snap->ps.customViewRModelIndex]; } else { if ( cg_entities[viewModelEntity].rEnt ) { viewModel = cg_entities[viewModelEntity].rEnt->getModel(); } else { viewModel = 0; } } if ( viewModel == 0 ) { CG_FreeViewModelEntity(); return; } // add hardcoded gun offset if ( !stricmp( viewModel->getName(), "models/weapons2/plasma/plasma.md3" ) || !stricmp( viewModel->getName(), "models/weapons2/railgun/railgun.md3" ) || !stricmp( viewModel->getName(), "models/weapons2/rocketl/rocketl.md3" ) || !stricmp( viewModel->getName(), "models/weapons2/shotgun/shotgun.md3" ) // it could be better for grenade launcher || !stricmp( viewModel->getName(), "models/weapons2/grenadel/grenadel.md3" ) ) { localOfs.set( 5, -5, -10 ); } else if ( !stricmp( viewModel->getName(), "models/weapons/w_physics.mdl" ) ) { // Half Life2 physgun (for weapon_physgun) // "w_*" is a worldmodel // set 90 yaw rotation (around Z axis) localRot.set( 0, 0, 90 ); localOfs.set( 5, -5, -10 ); } else if ( !stricmp( viewModel->getName(), "models/weapons/v_physcannon.mdl" ) ) { // "v_*" is a viewmodel #if 0 localRot.set( 0, 15, 90 ); localOfs.set( -35, 0, -50 ); #else localRot.set( 0, 0, 90 ); localOfs.set( -15, 0, -65 ); #endif } else { localRot = cg.snap->ps.viewModelAngles; localOfs = cg.snap->ps.viewModelOffset; if ( viewModel->isDeclModel() ) { localOfs += viewModel->getDeclModelAPI()->getOffset(); } } //g_core->Print("Player velocity: %f %f %f\n",cg.snap->ps.velocity.x,cg.snap->ps.velocity.y,cg.snap->ps.velocity.z); // calculate viewmodel bobbing offset based on player velocity viewModelMovement.setConfig( viewModelMovementConfig ); viewModelMovement.calcViewModelOffset( cg.snap->ps.isOnGround(), cg.snap->ps.velocity, cg.refdefViewAngles, cg.frametime * 0.001f ); const vec3_c& currentMovement = viewModelMovement.getCurrentMovement(); localOfs += currentMovement; if ( cg_printViewModelBobbingOffset.getInt() ) { g_core->Print( "Viewmodel bobbing movement: %f %f %f\n", currentMovement.x, currentMovement.y, currentMovement.z ); } if ( cg_printCurViewModelName.getInt() ) { g_core->Print( "Current viewmodel name: %s\n", viewModel->getName() ); } if ( cg_printCurViewModelAnimationCount.getInt() ) { g_core->Print( "Current viewmodel animation count: %i\n", viewModel->getNumAnims() ); } if ( cg_printCurViewModelBoneNames.getInt() ) { g_core->Print( "Current viewmodel %s bonenames:\n", viewModel->getName() ); viewModel->printBoneNames(); } CG_AllocViewModelEntity(); vec3_c origin = cg.refdefViewOrigin; vec3_c angles = cg.refdefViewAngles; // apply extra gun offset localOfs.x += cg_gunX.getFloat(); localOfs.y += cg_gunY.getFloat(); localOfs.z += cg_gunZ.getFloat(); // apply extra gun rotation localRot.x += cg_gunRotX.getFloat(); localRot.y += cg_gunRotY.getFloat(); localRot.z += cg_gunRotZ.getFloat(); if ( localRot.isNull() == false ) { matrix_c m; m.fromAngles( angles ); m.rotateX( localRot.x ); m.rotateY( localRot.y ); m.rotateZ( localRot.z ); angles = m.getAngles(); } // add local offset to hand origin origin.vectorMA( origin, cg.refdefViewAxis[0], localOfs.x ); origin.vectorMA( origin, cg.refdefViewAxis[1], localOfs.y ); origin.vectorMA( origin, cg.refdefViewAxis[2], localOfs.z ); // always update viewmodel position cg_viewModelEntity->setOrigin( origin ); cg_viewModelEntity->setAngles( angles ); cg_viewModelEntity->setFirstPersonOnly( true ); // set viewmodel model //rModelAPI_i *viewModel = rf->registerModel("models/testweapons/xrealMachinegun/machinegun_view.md5mesh"); cg_viewModelEntity->setModel( viewModel ); int viewModelAnimFlags; if ( stricmp( cg_forceViewModelAnimationFlags.getStr(), "none" ) ) { viewModelAnimFlags = cg_forceViewModelAnimationFlags.getInt(); } else { viewModelAnimFlags = cg.snap->ps.viewModelAnimFlags; } if ( stricmp( cg_forceViewModelAnimationIndex.getStr(), "none" ) ) { int index = cg_forceViewModelAnimationIndex.getInt(); cg_viewModelEntity->setDeclModelAnimLocalIndex( index, viewModelAnimFlags ); } else if ( stricmp( cg_forceViewModelAnimationName.getStr(), "none" ) ) { const char* animName = cg_forceViewModelAnimationName.getStr(); cg_viewModelEntity->setAnim( animName, viewModelAnimFlags ); } else { const char* animName = CG_ConfigString( CS_ANIMATIONS + cg.snap->ps.viewModelAnim ); if ( cg_printViewModelAnimName.getInt() ) { g_core->Print( "ViewModelAnim: %s, flags %i\n", animName, viewModelAnimFlags ); } if ( cg_viewModelEntity->hasAnim( animName ) ) { cg_viewModelEntity->setAnim( animName, viewModelAnimFlags ); } else { g_core->RedWarning( "ViewModel has no animation %s\n", animName ); } } }
void procTree_c::addAreaDrawCalls_r( int areaNum, const frustumExt_c& fr, procPortal_c* prevPortal ) { if ( areaNum >= areas.size() || areaNum < 0 ) return; procArea_c* ar = areas[areaNum]; if ( ar == 0 ) return; if ( ar->visCount != this->visCount ) { //drawAreaDrawCalls(ar); ar->areaModel->addDrawCalls(); ar->visCount = this->visCount; } for ( u32 i = 0; i < ar->portals.size(); i++ ) { procPortal_c* p = ar->portals[i]; if ( p == prevPortal ) { continue; } // first check if the portal is in the frustum if ( fr.cull( p->bounds ) == CULL_OUT ) continue; // then check if the portal side facing camera // belong to current area. If not, portal is occluded // by the wall and is not really visible float d = p->plane.distance( rf_camera.getOrigin() ); if ( p->areas[0] == areaNum ) { if ( d > 0 ) continue; } else { if ( d < 0 ) continue; } // adjust the frustum, so addAreaDrawCalls_r will never loop and cause a stack overflow... frustumExt_c adjusted; adjusted.adjustFrustum( fr, rf_camera.getOrigin(), p->points, p->plane ); if ( adjusted.size() == 0 ) { // it happend very often and doesn't seem to cause any visible errors if ( rf_proc_printChoppedFrustums.getInt() ) { g_core->RedWarning( "procTree_c::addAreaDrawCalls_r: frustum chopped away (dist %f)\n", d ); } continue; } if ( p->visCount != this->visCount ) { p->visCount = this->visCount; p->visitCount = 0; } else { if ( p->visitCount >= MAX_PORTAL_VISIT_COUNT ) { g_core->RedWarning( "MAX_PORTAL_VISIT_COUNT!!!\n" ); continue; } } p->lastFrustum[p->visitCount] = adjusted; p->visitCount++; if ( p->areas[0] == areaNum ) { addAreaDrawCalls_r( p->areas[1], adjusted, p ); } else { addAreaDrawCalls_r( p->areas[0], adjusted, p ); } } }