/* static */ double WeightMatrix::DotProduct(const double* u, const double* v, int n) { // Note: because the order of addition is different among the 3 DotProduct // functions, the results can (and do) vary slightly (although they agree // to within about 4e-15). This produces different results when running // training, despite all random inputs being precisely equal. // To get consistent results, use just one of these DotProduct functions. // On a test multi-layer network, serial is 57% slower than sse, and avx // is about 8% faster than sse. This suggests that the time is memory // bandwidth constrained and could benefit from holding the reused vector // in AVX registers. if (SIMDDetect::IsAVXAvailable()) return DotProductAVX(u, v, n); if (SIMDDetect::IsSSEAvailable()) return DotProductSSE(u, v, n); double total = 0.0; for (int k = 0; k < n; ++k) total += u[k] * v[k]; return total; }
/* ==================== UpdateParticle ==================== */ bool CParticleEngine::UpdateParticle( cl_particle_t *pParticle ) { pmtrace_t pmtrace; bool bColWater = false; float flTime = gEngfuncs.GetClientTime(); vec3_t vFinalVelocity = pParticle->velocity; particle_system_t *pSystem = pParticle->pSystem; // // Check if the particle is ready to die // if(pParticle->life != -1) { if(pParticle->life <= flTime) { if(pSystem->deathcreate[0] != 0) CreateSystem(pSystem->deathcreate, pParticle->origin, pParticle->velocity.Normalize(), 0); return false; // remove } } // // Damp velocity // if(pSystem->velocitydamp && (pParticle->spawntime + pSystem->veldampdelay) < flTime) VectorScale(vFinalVelocity, (1.0 - pSystem->velocitydamp*m_flFrameTime), vFinalVelocity); // // Add gravity before collision test // vFinalVelocity.z -= m_pCvarGravity->value*pSystem->gravity*m_flFrameTime; // // Add in wind on either axes // if(pSystem->windtype) { if(pParticle->windxvel) { if(pSystem->windtype == PARTICLE_WIND_LINEAR) vFinalVelocity.x += pParticle->windxvel*m_flFrameTime; else vFinalVelocity.x += sin((flTime*pParticle->windmult))*pParticle->windxvel*m_flFrameTime; } if(pParticle->windyvel) { if(pSystem->windtype == PARTICLE_WIND_LINEAR) vFinalVelocity.y += pParticle->windyvel*m_flFrameTime; else vFinalVelocity.y += sin((flTime*pParticle->windmult))*pParticle->windyvel*m_flFrameTime; } } // // Calculate rotation on all axes // if(pSystem->rotationvel) { if(pSystem->rotationdamp && pParticle->rotationvel) { if((pSystem->rotationdampdelay + pParticle->spawntime) < flTime) pParticle->rotationvel = pParticle->rotationvel*(1.0 - pSystem->rotationdamp); } pParticle->rotation += pParticle->rotationvel*m_flFrameTime; if(pParticle->rotation < 0) pParticle->rotation += 360; if(pParticle->rotation > 360) pParticle->rotation -= 360; } if(pSystem->rotxvel) { if(pSystem->rotxdamp && pParticle->rotxvel) { if((pSystem->rotxdampdelay + pParticle->spawntime) < flTime) pParticle->rotxvel = pParticle->rotxvel*(1.0 - pSystem->rotxdamp); } pParticle->rotx += pParticle->rotxvel*m_flFrameTime; if(pParticle->rotx < 0) pParticle->rotx += 360; if(pParticle->rotx > 360) pParticle->rotx -= 360; } if(pSystem->rotyvel) { if(pSystem->rotydamp && pParticle->rotyvel) { if((pSystem->rotydampdelay + pParticle->spawntime) < flTime) pParticle->rotyvel = pParticle->rotyvel*(1.0 - pSystem->rotydamp); } pParticle->roty += pParticle->rotyvel*m_flFrameTime; if(pParticle->roty < 0) pParticle->roty += 360; if(pParticle->roty > 360) pParticle->roty -= 360; } // // Collision detection // if(pSystem->collision) { gEngfuncs.pEventAPI->EV_SetTraceHull(2); gEngfuncs.pEventAPI->EV_PlayerTrace(pParticle->origin, (pParticle->origin+vFinalVelocity*m_flFrameTime), PM_WORLD_ONLY, -1, &pmtrace); if(pmtrace.allsolid) return false; // Probably spawned inside a solid if(pSystem->colwater) { if(gEngfuncs.PM_PointContents(pParticle->origin + vFinalVelocity*m_flFrameTime, 0) == CONTENTS_WATER) { pmtrace.endpos = pParticle->origin + vFinalVelocity*m_flFrameTime; int iEntity = gEngfuncs.PM_WaterEntity(pParticle->origin + vFinalVelocity*m_flFrameTime); if(iEntity) { cl_entity_t *pEntity = gEngfuncs.GetEntityByIndex(iEntity); pmtrace.endpos.z = pEntity->model->maxs.z + 0.001; } pmtrace.plane.normal = Vector(0, 0, 1); pmtrace.fraction = 0; bColWater = true; } } if(pmtrace.fraction != 1.0) { if(pSystem->collision == PARTICLE_COLLISION_STUCK) { if(gEngfuncs.PM_PointContents(pmtrace.endpos, NULL) == CONTENTS_SKY) return false; if(pParticle->life == -1 && pSystem->stuckdie) { pParticle->life = gEngfuncs.GetClientTime() + pSystem->stuckdie; pParticle->fadeoutdelay = gEngfuncs.GetClientTime() - pParticle->spawntime; } VectorMASSE( pParticle->origin, pmtrace.fraction*m_flFrameTime, vFinalVelocity, pParticle->origin ); pParticle->rotationvel = NULL; pParticle->rotxvel = NULL; pParticle->rotyvel = NULL; VectorClear(pParticle->velocity); VectorClear(vFinalVelocity); } else if(pSystem->collision == PARTICLE_COLLISION_BOUNCE) { float fProj/* = DotProduct(vFinalVelocity, pmtrace.plane.normal)*/; DotProductSSE(&fProj, vFinalVelocity, pmtrace.plane.normal); VectorMASSE(vFinalVelocity, -fProj*2, pmtrace.plane.normal, pParticle->velocity); VectorScale(pParticle->velocity, pSystem->impactdamp, pParticle->velocity); VectorScale(vFinalVelocity, pmtrace.fraction, vFinalVelocity); if(pParticle->rotationvel) pParticle->rotationvel *= -fProj*2*pSystem->impactdamp*m_flFrameTime; if(pParticle->rotxvel) pParticle->rotxvel *= -fProj*2*pSystem->impactdamp*m_flFrameTime; if(pParticle->rotyvel) pParticle->rotyvel *= -fProj*2*pSystem->impactdamp*m_flFrameTime; } else if(pSystem->collision == PARTICLE_COLLISION_DECAL) { gBSPRenderer.CreateDecal(pmtrace.endpos, pmtrace.plane.normal, pSystem->create); return false; } else if(pSystem->collision == PARTICLE_COLLISION_NEW_SYSTEM) { if(bColWater && pSystem->watercreate[0] != 0) { for(int i = 0; i < pSystem->watersystem->startparticles; i++) CreateParticle(pSystem->watersystem, pmtrace.endpos, pmtrace.plane.normal); } if(gEngfuncs.PM_PointContents(pmtrace.endpos, NULL) != CONTENTS_SKY && pSystem->create[0] != 0) { for(int i = 0; i < pSystem->createsystem->startparticles; i++) CreateParticle(pSystem->createsystem, pmtrace.endpos, pmtrace.plane.normal); } return false; } else { // kill it return false; } } else { VectorCopy(vFinalVelocity, pParticle->velocity); } } else { VectorCopy(vFinalVelocity, pParticle->velocity); } // // Add in the final velocity // VectorMASSE(pParticle->origin, m_flFrameTime, vFinalVelocity, pParticle->origin); // // Always reset to 1.0 // pParticle->alpha = 1.0; // // Fading in // if(pSystem->fadeintime) { if((pParticle->spawntime + pSystem->fadeintime) > flTime) { float flFadeTime = pParticle->spawntime + pSystem->fadeintime; float flTimeToFade = flFadeTime - flTime; pParticle->alpha = 1.0 - (flTimeToFade/pSystem->fadeintime); } } // // Fade out // if(pParticle->fadeoutdelay) { if((pParticle->fadeoutdelay + pParticle->spawntime) < flTime) { float flTimeToDeath = pParticle->life - flTime; float flFadeTime = pParticle->fadeoutdelay + pParticle->spawntime; float flFadeFrac = pParticle->life - flFadeTime; pParticle->alpha = flTimeToDeath/flFadeFrac; } } // // Minimum and maximum distance fading // if(pSystem->fadedistfar && pSystem->fadedistnear) { float flDist = (pParticle->origin - gBSPRenderer.m_vRenderOrigin).Length(); float flAlpha = 1.0-((pSystem->fadedistfar - flDist)/(pSystem->fadedistfar-pSystem->fadedistnear)); if( flAlpha < 0 ) flAlpha = 0; if( flAlpha > 1 ) flAlpha = 1; pParticle->alpha *= flAlpha; } // // Dampen scale // if(pSystem->scaledampfactor && (pParticle->scaledampdelay < flTime)) pParticle->scale = pParticle->scale - m_flFrameTime*pSystem->scaledampfactor; if(pParticle->scale <= 0) return false; // // Check if lighting is required // if(pSystem->lightcheck != PARTICLE_LIGHTCHECK_NONE) { if(pSystem->lightcheck == PARTICLE_LIGHTCHECK_NORMAL) { pParticle->color = LightForParticle(pParticle); } else if(pSystem->lightcheck == PARTICLE_LIGHTCHECK_SCOLOR) { pParticle->scolor = LightForParticle(pParticle); } else if(pSystem->lightcheck == PARTICLE_LIGHTCHECK_MIXP) { pParticle->color = LightForParticle(pParticle); pParticle->color.x = pParticle->color.x*pSystem->primarycolor.x; pParticle->color.y = pParticle->color.y*pSystem->primarycolor.y; pParticle->color.z = pParticle->color.z*pSystem->primarycolor.z; } } // // See if we need to blend colors // if(pSystem->lightcheck != PARTICLE_LIGHTCHECK_NORMAL) { if((pParticle->secondarydelay < flTime) && (flTime < (pParticle->secondarydelay + pParticle->secondarytime))) { float flTimeFull = (pParticle->secondarydelay+pParticle->secondarytime) - flTime; float flColFrac = flTimeFull/pParticle->secondarytime; pParticle->color[0] = pParticle->scolor[0]*(1.0 - flColFrac) + pSystem->primarycolor[0]*flColFrac; pParticle->color[1] = pParticle->scolor[1]*(1.0 - flColFrac) + pSystem->primarycolor[1]*flColFrac; pParticle->color[2] = pParticle->scolor[2]*(1.0 - flColFrac) + pSystem->primarycolor[2]*flColFrac; } } // // Spawn tracer particles // if(pSystem->tracerdist) { vec3_t vDistance; VectorSubtract(pParticle->origin, pParticle->lastspawn, vDistance); if(vDistance.Length() > pSystem->tracerdist) { vec3_t vDirection = pParticle->origin - pParticle->lastspawn; int iNumTraces = vDistance.Length()/pSystem->tracerdist; for(int i = 0; i < iNumTraces; i++) { float flFraction = (i+1)/(float)iNumTraces; vec3_t vOrigin = pParticle->lastspawn + vDirection*flFraction; CreateParticle(pSystem->createsystem, vOrigin, pParticle->velocity.Normalize()); } VectorCopy(pParticle->origin, pParticle->lastspawn); } } // // Calculate texcoords // if(pSystem->numframes) { // Get desired frame int iFrame = ((int)((flTime - pParticle->spawntime)*pSystem->framerate)); iFrame = iFrame % pSystem->numframes; // Check if we actually have to set the frame if(iFrame != pParticle->frame) { cl_texture_t *pTexture = pSystem->texture; int iNumFramesX = pTexture->iWidth/pSystem->framesizex; int iNumFramesY = pTexture->iHeight/pSystem->framesizey; int iColumn = iFrame%iNumFramesX; int iRow = (iFrame/iNumFramesX)%iNumFramesY; // Calculate these only once float flFractionWidth = (float)pSystem->framesizex/(float)pTexture->iWidth; float flFractionHeight = (float)pSystem->framesizey/(float)pTexture->iHeight; // Calculate top left coordinate pParticle->texcoords[0][0] = (iColumn+1)*flFractionWidth; pParticle->texcoords[0][1] = iRow*flFractionHeight; // Calculate top right coordinate pParticle->texcoords[1][0] = iColumn*flFractionWidth; pParticle->texcoords[1][1] = iRow*flFractionHeight; // Calculate bottom right coordinate pParticle->texcoords[2][0] = iColumn*flFractionWidth; pParticle->texcoords[2][1] = (iRow+1)*flFractionHeight; // Calculate bottom left coordinate pParticle->texcoords[3][0] = (iColumn+1)*flFractionWidth; pParticle->texcoords[3][1] = (iRow+1)*flFractionHeight; // Fill in current frame pParticle->frame = iFrame; } } // All went well, particle is still active return true; }
/* ==================== LightForParticle ==================== */ vec3_t CParticleEngine::LightForParticle( cl_particle_t *pParticle ) { float flRad; float flDist; float flAtten; float flCos; vec3_t vDir; vec3_t vNorm; vec3_t vForward; float flTime = gEngfuncs.GetClientTime(); model_t *pWorld = IEngineStudio.GetModelByIndex(1); vec3_t vEndPos = pParticle->origin - Vector(0, 0, 8964); vec3_t vColor = Vector(0, 0, 0); g_StudioRenderer.StudioRecursiveLightPoint(NULL, pWorld->nodes, pParticle->origin, vEndPos, vColor); cl_dlight_t *pLight = gBSPRenderer.m_pDynLights; for(int i = 0; i < MAX_DYNLIGHTS; i++, pLight++) { if(pLight->die < flTime || !pLight->radius) continue; if(pLight->cone_size) { if(pLight->frustum.CullBox(pParticle->origin, pParticle->origin)) continue; vec3_t vAngles = pLight->angles; FixVectorForSpotlight(vAngles); AngleVectors(vAngles, vForward, NULL, NULL); } else { if(CheckLightBBox(pParticle, pLight)) continue; } flRad = pLight->radius*pLight->radius; VectorSubtract(pParticle->origin, pLight->origin, vDir); DotProductSSE(&flDist, vDir, vDir); flAtten = (flDist/flRad - 1)* -1; if(pLight->cone_size) { VectorNormalizeFast(vDir); flCos = cos((pLight->cone_size*2)*0.3*(M_PI*2/360)); DotProductSSE(&flDist, vForward, vDir); if(flDist < 0 || flDist < flCos) continue; flAtten *= (flDist - flCos)/(1.0 - flCos); } if(flAtten <= 0) continue; VectorMASSE(vColor, flAtten, pLight->color, vColor); } return vColor; }
/* ==================== RenderParticle ==================== */ void CParticleEngine::RenderParticle( cl_particle_t *pParticle, float flUp, float flRight ) { float flDot; vec3_t vTemp; vec3_t vPoint; vec3_t vDir; vec3_t vAngles; if(pParticle->alpha == 0) return; VectorSubtract(pParticle->origin, gBSPRenderer.m_vRenderOrigin, vDir); if(gHUD.m_pFogSettings.active) { if(vDir.Length() > gHUD.m_pFogSettings.end) return; } VectorNormalizeFast(vDir); DotProductSSE(&flDot, vDir, m_vForward); // z clipped if(flDot < 0) return; cl_texture_t *pTexture = pParticle->pSystem->texture; if(pParticle->pSystem->rendermode == SYSTEM_RENDERMODE_ADDITIVE) { glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4f(pParticle->color[0], pParticle->color[1], pParticle->color[2], pParticle->alpha*pParticle->pSystem->mainalpha); glFogfv(GL_FOG_COLOR, g_vecZero); } else if(pParticle->pSystem->rendermode == SYSTEM_RENDERMODE_ALPHABLEND) { glBlendFunc(GL_ONE, GL_ONE); glColor3f(pParticle->alpha*pParticle->pSystem->mainalpha, pParticle->alpha*pParticle->pSystem->mainalpha, pParticle->alpha*pParticle->pSystem->mainalpha); glFogfv(GL_FOG_COLOR, g_vecZero); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(pParticle->color[0], pParticle->color[1], pParticle->color[2], pParticle->alpha*pParticle->pSystem->mainalpha); glFogfv(GL_FOG_COLOR, gHUD.m_pFogSettings.color); } if(pParticle->pSystem->displaytype == SYSTEM_DISPLAY_PLANAR) { gBSPRenderer.GetUpRight(pParticle->normal, m_vRUp, m_vRRight); } else if(pParticle->rotation || pParticle->rotx || pParticle->roty) { VectorCopy(gBSPRenderer.m_vViewAngles, vAngles); if(pParticle->rotx) vAngles[0] = pParticle->rotx; if(pParticle->roty) vAngles[1] = pParticle->roty; if(pParticle->rotation) vAngles[2] = pParticle->rotation; AngleVectors(vAngles, NULL, m_vRRight, m_vRUp); } if(pParticle->pSystem->displaytype == SYSTEM_DISPLAY_PARALELL) { glBegin(GL_TRIANGLE_FAN); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale * 2; vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glTexCoord2f(pParticle->texcoords[0][0], pParticle->texcoords[0][1]); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale * 2; vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glTexCoord2f(pParticle->texcoords[1][0], pParticle->texcoords[1][1]); glVertex3fv (vPoint); vPoint = pParticle->origin + m_vRRight * flRight * pParticle->scale; glTexCoord2f(pParticle->texcoords[2][0], pParticle->texcoords[2][1]); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRRight * flRight * (-pParticle->scale); glTexCoord2f(pParticle->texcoords[3][0], pParticle->texcoords[3][1]); glVertex3fv (vPoint); glEnd(); } else { glBegin(GL_TRIANGLE_FAN); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale; vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glTexCoord2f(pParticle->texcoords[0][0], pParticle->texcoords[0][1]); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale; vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glTexCoord2f(pParticle->texcoords[1][0], pParticle->texcoords[1][1]); glVertex3fv (vPoint); vPoint = pParticle->origin + m_vRUp * flUp * (-pParticle->scale); vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glTexCoord2f(pParticle->texcoords[2][0], pParticle->texcoords[2][1]); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * (-pParticle->scale); vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glTexCoord2f(pParticle->texcoords[3][0], pParticle->texcoords[3][1]); glVertex3fv (vPoint); glEnd(); } if(gBSPRenderer.m_pCvarWireFrame->value > 0) { glDisable(GL_BLEND); glDepthMask(GL_TRUE); glDisable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(1.0, 0.0, 0.0); glLineWidth(1); if(gBSPRenderer.m_pCvarWireFrame->value > 1) glDisable(GL_DEPTH_TEST); if(pParticle->pSystem->displaytype == SYSTEM_DISPLAY_PARALELL) { glBegin(GL_TRIANGLE_FAN); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale * 2; vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale * 2; vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glVertex3fv (vPoint); vPoint = pParticle->origin + m_vRRight * flRight * pParticle->scale; glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRRight * flRight * (-pParticle->scale); glVertex3fv (vPoint); glEnd(); } else { glBegin(GL_TRIANGLE_FAN); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale; vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * pParticle->scale; vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glVertex3fv (vPoint); vPoint = pParticle->origin + m_vRUp * flUp * (-pParticle->scale); vPoint = vPoint + m_vRRight * flRight * pParticle->scale; glVertex3fv(vPoint); vPoint = pParticle->origin + m_vRUp * flUp * (-pParticle->scale); vPoint = vPoint + m_vRRight * flRight * (-pParticle->scale); glVertex3fv (vPoint); glEnd(); } if(gBSPRenderer.m_pCvarWireFrame->value > 1) glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glEnable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } m_iNumParticles++; }