void CRenderingContext::RenderBillboard(const CMaterialHandle& hMaterial, float flRadius, Vector vecUp, Vector vecRight) { TAssert(hMaterial.IsValid()); if (!hMaterial.IsValid()) return; vecUp *= flRadius; vecRight *= flRadius; // Clear out any existing rotation so that they don't interfere with the billboarding below. GetContext().m_mTransformations.SetAngles(EAngle(0, 0, 0)); GetContext().m_bTransformUpdated = false; if (GetContext().m_hMaterial != hMaterial) UseMaterial(hMaterial); BeginRenderTriFan(); TexCoord(0.0f, 1.0f); Vertex(-vecRight + vecUp); TexCoord(0.0f, 0.0f); Vertex(-vecRight - vecUp); TexCoord(1.0f, 0.0f); Vertex(vecRight - vecUp); TexCoord(1.0f, 1.0f); Vertex(vecRight + vecUp); EndRender(); }
void CParticle::Reset() { m_vecOrigin = m_vecVelocity = Vector(); m_angAngles = EAngle(); m_flAlpha = 1; m_flRadius = 1; m_bActive = true; m_flSpawnTime = GameServer()->GetGameTime(); }
EAngle Matrix4x4::GetAngles() const { #ifdef _DEBUG // If any of the below is not true then you have a matrix that has been scaled or reflected or something and it won't work to try to pull its Eulers bool b = fabs(GetForwardVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = fabs(GetUpVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = fabs(GetLeftVector().LengthSqr() - 1) < 0.001f; if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } b = GetForwardVector().Cross(GetLeftVector()).Equals(GetUpVector(), 0.001f); if (!b) { TAssertNoMsg(b); return EAngle(0, 0, 0); } #endif if (m[0][2] > 0.999999f) return EAngle(asin(Clamp(m[0][2], -1.0f, 1.0f)) * 180/M_PI, -atan2(m[1][0], m[1][1]) * 180/M_PI, 0); else if (m[0][2] < -0.999999f) return EAngle(asin(Clamp(m[0][2], -1.0f, 1.0f)) * 180/M_PI, -atan2(m[1][0], m[1][1]) * 180/M_PI, 0); // Clamp to [-1, 1] looping float flPitch = fmod(m[0][2], 2.0f); if (flPitch > 1) flPitch -= 2; else if (flPitch < -1) flPitch += 2; return EAngle(asin(flPitch) * 180/M_PI, -atan2(-m[0][1], m[0][0]) * 180/M_PI, atan2(-m[1][2], m[2][2]) * 180/M_PI); }
CToyEditor::CToyEditor() { s_pToyEditor = this; m_pCreateToySourcePanel = new CCreateToySourcePanel(); m_pCreateToySourcePanel->Layout(); m_pCreateToySourcePanel->Center(); m_pCreateToySourcePanel->SetVisible(false); m_pSourcePanel = new CSourcePanel(); m_pSourcePanel->SetVisible(false); glgui::CRootPanel::Get()->AddControl(m_pSourcePanel); m_iMeshPreview = ~0; m_iPhysPreview = ~0; m_bRotatingPreview = false; m_angPreview = EAngle(-20, 20, 0); m_bSaved = false; }
void CSystemInstance::SpawnParticle() { m_iNumParticlesAlive++; m_iTotalEmitted++; CParticle* pNewParticle = NULL; for (size_t i = 0; i < m_aParticles.size(); i++) { CParticle* pParticle = &m_aParticles[i]; if (pParticle->m_bActive) continue; pNewParticle = pParticle; break; } if (!pNewParticle) { m_aParticles.push_back(CParticle()); pNewParticle = &m_aParticles[m_aParticles.size()-1]; } Vector vecDistance = Vector(0,0,0); if (m_pSystem->GetEmissionMaxDistance() > 0) { float flYaw = RandomFloat(-180, 180); float flDistance = cos(RandomFloat(0, M_PI/2)) * m_pSystem->GetEmissionMaxDistance(); float flPitch = sin(RandomFloat(-M_PI/2, M_PI/2)) * 90; vecDistance = AngleVector(EAngle(flPitch, flYaw, 0)) * flDistance; } pNewParticle->Reset(); pNewParticle->m_vecOrigin = m_vecOrigin + m_pSystem->GetSpawnOffset() + vecDistance; pNewParticle->m_vecVelocity = m_vecInheritedVelocity * m_pSystem->GetInheritedVelocity(); if (m_pSystem->GetRandomVelocity().Size().LengthSqr() > 0) { Vector vecMins = m_pSystem->GetRandomVelocity().m_vecMins; Vector vecMaxs = m_pSystem->GetRandomVelocity().m_vecMaxs; pNewParticle->m_vecVelocity.x += RandomFloat(vecMins.x, vecMaxs.x); pNewParticle->m_vecVelocity.y += RandomFloat(vecMins.y, vecMaxs.y); pNewParticle->m_vecVelocity.z += RandomFloat(vecMins.z, vecMaxs.z); } pNewParticle->m_angAngles = m_angAngles; if (m_pSystem->GetRandomModelYaw()) pNewParticle->m_angAngles.y = RandomFloat(0, 360); if (m_pSystem->GetRandomModelRoll()) pNewParticle->m_angAngles.r = RandomFloat(-180, 180); if (m_pSystem->GetRandomAngleVelocity()) pNewParticle->m_angAngleVelocity = EAngle(RandomFloat(-90, 90), RandomFloat(-180, 180), RandomFloat(-90, 90)); if (m_pSystem->GetFadeIn()) pNewParticle->m_flAlpha = 0; else pNewParticle->m_flAlpha = m_pSystem->GetAlpha(); pNewParticle->m_flRadius = m_pSystem->GetStartRadius(); if (m_pSystem->GetRandomBillboardYaw()) pNewParticle->m_flBillboardYaw = RandomFloat(0, 360); else pNewParticle->m_flBillboardYaw = 0; }
void CTexelAOMethod::GenerateTexel(size_t iTexel, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, raytrace::CTraceResult* tr, const Vector& vecUVPosition, raytrace::CRaytracer* pTracer) { CConversionFace* pHitFace = tr->m_pMeshInstance->GetMesh()->GetFace(tr->m_iFace); Vector vecHitNormal = pHitFace->GetNormal(tr->m_vecHit, tr->m_pMeshInstance); // Build rotation matrix Matrix4x4 m; m.SetOrientation(vecHitNormal); // Turn it sideways so that pitch 90 is up Matrix4x4 m2; m2.SetAngles(EAngle(-90, 0, 0)); m *= m2; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecNormal*0.5f, Color(0, 0, 255)); float flHits = 0; float flTotalHits = 0; for (size_t x = 0; x < m_iSamples/2; x++) { float flRandom = 0; if (m_bRandomize) flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5f, 0.5f); float flPitch = RemapVal(cos(RemapVal((float)x+flRandom, 0, (float)m_iSamples/2, 0, (float)M_PI/2)), 0, 1, 90, 0); float flWeight = sin(flPitch * M_PI/180); for (size_t y = 0; y <= m_iSamples; y++) { flRandom = 0; if (m_bRandomize) flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5f, 0.5f); float flYaw = RemapVal((float)y+flRandom, 0, (float)m_iSamples, -180, 180); Vector vecDir = AngleVector(EAngle(flPitch, flYaw, 0)); // Transform relative to the triangle's normal Vector vecRay = m * vecDir; flTotalHits += flWeight; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecRay.Normalized()*0.1f, vecDir); raytrace::CTraceResult tr2; if (pTracer->Raytrace(Ray(tr->m_vecHit + vecHitNormal*0.01f, vecRay), &tr2)) { float flDistance = (tr2.m_vecHit - tr->m_vecHit).Length(); if (m_flRayFalloff < 0) flHits += flWeight; else flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff)); } else if (m_bGroundOcclusion && vecRay.y < 0) { // The following math is basically a plane-ray intersection algorithm, // with shortcuts made for the assumption of an infinite plane facing straight up. Vector n = Vector(0,1,0); float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y); float b = vecRay.y; float flDistance = a/b; if (flDistance < 1e-4f || m_flRayFalloff < 0) flHits += flWeight; else flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff)); } } } // One last ray directly up, it is skipped in the above loop so it's not done 10 times. Vector vecDir = AngleVector(EAngle(90, 0, 0)); // Transform relative to the triangle's normal Vector vecRay = m * vecDir; //RenderSceneFromPosition(vecUVPosition, vecRay, pFace); flTotalHits++; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecRay.Normalized()*0.2f, vecDir); raytrace::CTraceResult tr2; if (pTracer->Raytrace(Ray(tr->m_vecHit + vecHitNormal*0.01f, vecRay), &tr2)) { float flDistance = (tr2.m_vecHit - tr->m_vecHit).Length(); if (m_flRayFalloff < 0) flHits += 1; else flHits += (1/pow(2, flDistance/m_flRayFalloff)); } else if (m_bGroundOcclusion && vecRay.y < 0) { // The following math is basically a plane-ray intersection algorithm, // with shortcuts made for the assumption of an infinite plane facing straight up. float a = -(tr->m_vecHit.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y); float b = vecRay.y; float flDistance = a/b; if (flDistance < 1e-4f || m_flRayFalloff < 0) flHits += 1; else flHits += (1/pow(2, flDistance/m_flRayFalloff)); } float flShadowValue = 1 - ((float)flHits / (float)flTotalHits); // Mutex may be dead, try to bail before. if (m_pGenerator->IsStopped()) return; m_pGenerator->GetParallelizer()->LockData(); m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue); m_aiShadowReads[iTexel]++; m_pGenerator->MarkTexelUsed(iTexel); m_pGenerator->GetParallelizer()->UnlockData(); }
void CSupplier::UpdateTendrils() { if (IsConstructing()) return; TStubbed("Tendrils"); #if 0 if (!GetPlayerOwner()) { if (m_iTendrilsCallList) glDeleteLists((GLuint)m_iTendrilsCallList, 1); m_iTendrilsCallList = 0; DigitanksGame()->GetTerrain()->DirtyChunkTexturesWithinDistance(GetGlobalOrigin(), GetDataFlowRadius() + GetBoundingRadius()); return; } if (GameServer()->IsLoading()) return; bool bUpdateTerrain = false; size_t iRadius = (size_t)GetDataFlowRadius(); while (m_aTendrils.size() < iRadius) { m_aTendrils.push_back(CTendril()); CTendril* pTendril = &m_aTendrils[m_aTendrils.size()-1]; pTendril->m_flLength = (float)m_aTendrils.size() + GetBoundingRadius(); pTendril->m_vecEndPoint = DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin() + AngleVector(EAngle(0, RandomFloat(0, 360), 0)) * pTendril->m_flLength); pTendril->m_flScale = RandomFloat(3, 7); pTendril->m_flOffset = RandomFloat(0, 1); pTendril->m_flSpeed = RandomFloat(0.5f, 2); bUpdateTerrain = true; } if (bUpdateTerrain) DigitanksGame()->GetTerrain()->DirtyChunkTexturesWithinDistance(GetGlobalOrigin(), GetDataFlowRadius() + GetBoundingRadius()); if (m_iTendrilsCallList) glDeleteLists((GLuint)m_iTendrilsCallList, 1); m_iTendrilsCallList = glGenLists(1); Color clrTeam = GetPlayerOwner()->GetColor(); clrTeam = (Vector(clrTeam) + Vector(1,1,1))/2; glNewList((GLuint)m_iTendrilsCallList, GL_COMPILE); for (size_t i = 0; i < m_aTendrils.size(); i++) { // Only show the longest tendrils, for perf reasons. if (i < iRadius - 15) continue; CTendril* pTendril = &m_aTendrils[i]; Vector vecDestination = pTendril->m_vecEndPoint; Vector vecPath = vecDestination - GetGlobalOrigin(); vecPath.y = 0; float flDistance = vecPath.Length2D(); Vector vecDirection = vecPath.Normalized(); size_t iSegments = (size_t)(flDistance/3); GLuint iScrollingTextureProgram = (GLuint)CShaderLibrary::GetScrollingTextureProgram(); GLuint flSpeed = glGetUniformLocation(iScrollingTextureProgram, "flSpeed"); glUniform1f(flSpeed, pTendril->m_flSpeed); clrTeam.SetAlpha(105); CRopeRenderer oRope(GameServer()->GetRenderer(), s_iTendrilBeam, DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin()) + Vector(0, 0, 1), 1.0f); oRope.SetColor(clrTeam); oRope.SetTextureScale(pTendril->m_flScale); oRope.SetTextureOffset(pTendril->m_flOffset); oRope.SetForward(Vector(0, 0, -1)); for (size_t i = 1; i < iSegments; i++) { clrTeam.SetAlpha((int)RemapVal((float)i, 1, (float)iSegments, 100, 30)); oRope.SetColor(clrTeam); float flCurrentDistance = ((float)i*flDistance)/iSegments; oRope.AddLink(DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin() + vecDirection*flCurrentDistance) + Vector(0, 0, 1)); } oRope.Finish(DigitanksGame()->GetTerrain()->GetPointHeight(vecDestination) + Vector(0, 0, 1)); } glEndList(); #endif }
void CAOGenerator::GenerateShadowMaps() { double flProcessSceneRead = 0; double flProgress = 0; size_t iShadowMapSize = 1024; // A frame buffer for holding the depth buffer shadow render CFrameBuffer oDepthFB = SMAKRenderer()->CreateFrameBuffer(iShadowMapSize, iShadowMapSize, (fb_options_e)(FB_DEPTH_TEXTURE|FB_RENDERBUFFER)); // RB unused // A frame buffer for holding the UV layout once it is rendered flat with the shadow CFrameBuffer oUVFB = SMAKRenderer()->CreateFrameBuffer(m_iWidth, m_iHeight, (fb_options_e)(FB_TEXTURE|FB_LINEAR|FB_DEPTH)); // Depth unused // A frame buffer for holding the completed AO map m_oAOFB = SMAKRenderer()->CreateFrameBuffer(m_iWidth, m_iHeight, (fb_options_e)(FB_TEXTURE|FB_TEXTURE_HALF_FLOAT|FB_LINEAR|FB_DEPTH)); // Depth unused CRenderingContext c(SMAKRenderer()); c.UseFrameBuffer(&m_oAOFB); c.ClearColor(Color(0, 0, 0, 0)); c.SetDepthFunction(DF_LEQUAL); c.SetDepthTest(true); c.SetBackCulling(false); Matrix4x4 mBias( 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f); // Bias from [-1, 1] to [0, 1] AABB oBox = m_pScene->m_oExtends; Vector vecCenter = oBox.Center(); float flSize = oBox.Size().Length(); // Length of the box's diagonal Matrix4x4 mLightProjection = Matrix4x4::ProjectOrthographic(-flSize/2, flSize/2, -flSize/2, flSize/2, 1, flSize*2); size_t iSamples = (size_t)sqrt((float)m_iSamples); m_pWorkListener->SetAction("Taking exposures", m_iSamples); for (size_t x = 0; x <= iSamples; x++) { float flPitch = -asin(RemapVal((float)x, 0, (float)iSamples, -1, 1)) * 90 / (M_PI/2); for (size_t y = 0; y < iSamples; y++) { if (x == 0 || x == iSamples) { // Don't do a bunch of samples from the same spot on the poles. if (y != 0) continue; } float flYaw = RemapVal((float)y, 0, (float)iSamples, -180, 180); // Randomize the direction a tad to help fight moire Vector vecDir = AngleVector(EAngle(flPitch+RandomFloat(-1, 1)/2, flYaw+RandomFloat(-1, 1)/2, 0)); Vector vecLightPosition = vecDir*flSize + vecCenter; // Puts us twice as far from the closest vertex if (ao_debug.GetInt() > 1) SMAKWindow()->AddDebugLine(vecLightPosition, vecLightPosition-vecDir); Matrix4x4 mLightView = Matrix4x4::ConstructCameraView(vecLightPosition, (vecCenter-vecLightPosition).Normalized(), Vector(0, 1, 0)); c.SetProjection(mLightProjection); c.SetView(mLightView); // If we're looking from below and ground occlusion is on, don't bother with this render. if (!(flPitch < -10 && m_bGroundOcclusion)) { c.UseProgram("model"); c.UseFrameBuffer(&oDepthFB); c.SetViewport(Rect(0, 0, iShadowMapSize, iShadowMapSize)); c.SetBackCulling(false); c.ClearDepth(); c.BeginRenderVertexArray(m_iSceneDepth); c.SetPositionBuffer((size_t)0, 8*sizeof(float)); c.SetNormalsBuffer((size_t)3*sizeof(float), 8*sizeof(float)); c.SetTexCoordBuffer((size_t)6*sizeof(float), 8*sizeof(float)); c.EndRenderVertexArray(m_iSceneDepthVerts); c.UseFrameBuffer(nullptr); if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.SetViewport(Rect(0, 0, iShadowMapSize/2, iShadowMapSize/2)); DrawTexture(oDepthFB.m_iDepthTexture, 1, c); } } Matrix4x4 mTextureMatrix = mBias*mLightProjection*mLightView; { CRenderingContext c(SMAKRenderer(), true); c.UseFrameBuffer(&oUVFB); c.SetViewport(Rect(0, 0, m_iWidth, m_iHeight)); c.ClearColor(Color(0, 0, 0, 0)); c.ClearDepth(); c.UseProgram("flat_shadow"); c.SetUniform("mBiasedLightMatrix", mTextureMatrix); c.SetUniform("iShadowMap", 0); c.SetUniform("vecLightNormal", -vecDir); c.SetUniform("bOccludeAll", (flPitch < -10 && m_bGroundOcclusion)); c.SetUniform("flTime", (float)Application()->GetTime()); c.BindTexture(oDepthFB.m_iDepthTexture); c.BeginRenderVertexArray(m_iScene); c.SetPositionBuffer((size_t)0, 8*sizeof(float)); c.SetNormalsBuffer((size_t)3*sizeof(float), 8*sizeof(float)); c.SetTexCoordBuffer((size_t)6*sizeof(float), 8*sizeof(float)); c.EndRenderVertexArray(m_iSceneVerts); } if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.SetViewport(Rect(iShadowMapSize/2, 0, m_iWidth, m_iHeight)); DrawTexture(oUVFB.m_iMap, 1, c); } double flTimeBefore = SMAKWindow()->GetTime(); c.SetViewport(Rect(0, 0, m_iWidth, m_iHeight)); c.UseFrameBuffer(&m_oAOFB); AccumulateTexture(oUVFB.m_iMap); c.UseFrameBuffer(nullptr); if (ao_debug.GetBool()) { CRenderingContext c(SMAKRenderer()); c.UseProgram("ao"); c.SetViewport(Rect(iShadowMapSize/2+m_iWidth, 0, m_iWidth, m_iHeight)); c.SetUniform("iAOMap", 0); c.SetBlend(BLEND_ALPHA); DrawTexture(m_oAOFB.m_iMap, 1, c); } flProcessSceneRead += (SMAKWindow()->GetTime() - flTimeBefore); flTimeBefore = SMAKWindow()->GetTime(); m_pWorkListener->WorkProgress(x*iSamples + y); flProgress += (SMAKWindow()->GetTime() - flTimeBefore); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } c.UseFrameBuffer(&m_oAOFB); c.ReadPixels(0, 0, m_iWidth, m_iHeight, m_pvecPixels); c.UseFrameBuffer(nullptr); if (!m_bStopGenerating) { size_t iBufferSize = m_iWidth*m_iHeight; m_pWorkListener->SetAction("Reading pixels", iBufferSize); for (size_t p = 0; p < iBufferSize; p++) { Vector4D& vecPixel = m_pvecPixels[p]; if (vecPixel.w == 0.0f) continue; m_avecShadowValues[p].x = vecPixel.x; m_aiShadowReads[p] = (size_t)vecPixel.w; m_bPixelMask[p] = true; m_pWorkListener->WorkProgress(p); } } oDepthFB.Destroy(); oUVFB.Destroy(); // Don't destroy m_oAOFB yet, we need it in a bit. It gets destroyed later. }