void CG_DoGlass( vec3_t verts[4], vec3_t normal, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius ) { int i, t; int mxHeight, mxWidth; float height, width; float stepWidth, stepHeight; float timeDecay; float x, z; float xx, zz; int time = 0; bool stick = true; vec3_t subVerts[4]; vec2_t biPoints[4]; // To do a smarter tesselation, we should figure out the relative height and width of the brush face, // then use this to pick a lod value from 1-3 in each axis. This will give us 1-9 lod levels, which will // hopefully be sufficient. CG_CalcHeightWidth( verts, &height, &width ); cgi_S_StartSound( dmgPt, -1, CHAN_AUTO, cgi_S_RegisterSound("sound/effects/glassbreak1.wav")); // Pick "LOD" for height if ( height < 100 ) { stepHeight = 0.2f; mxHeight = 5; timeDecay = TIME_DECAY_SLOW; } /* else if ( height > 220 ) // was originally mxHeight = 20....but removing this whole section because it causes huge number of chunks...which is bad { stepHeight = 0.075f; mxHeight = 15; timeDecay = TIME_DECAY_FAST; }*/ else { stepHeight = 0.1f; mxHeight = 10; timeDecay = TIME_DECAY_MED; } // Pick "LOD" for width if ( width < 100 ) { stepWidth = 0.2f; mxWidth = 5; timeDecay = ( timeDecay + TIME_DECAY_SLOW ) * 0.5f; } /* else if ( width > 220 ) // don't do this because it causes too much chug with large glass panes...especially when more than one pane can be broken at a time { stepWidth = 0.075f; mxWidth = 15; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; }*/ else { stepWidth = 0.1f; mxWidth = 10; timeDecay = ( timeDecay + TIME_DECAY_MED ) * 0.5f; } for ( z = 0.0f, i = 0; z < 1.0f; z += stepHeight, i++ ) { for ( x = 0.0f, t = 0; x < 1.0f; x += stepWidth, t++ ) { // This is nasty..we do this because we don't want to add a random offset on the edge of the glass brush // ...but we do in the center, otherwise the breaking scheme looks way too orderly if ( t > 0 && t < mxWidth ) { xx = x - offX[i][t]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t][i]; } else { zz = z; } Vector2Set( biPoints[0], xx, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i][t + 1]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t + 1][i]; } else { zz = z; } Vector2Set( biPoints[1], xx + stepWidth, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i + 1][t + 1]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t + 1][i + 1]; } else { zz = z; } Vector2Set( biPoints[2], xx + stepWidth, zz + stepHeight); if ( t > 0 && t < mxWidth ) { xx = x - offX[i + 1][t]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t][i + 1]; } else { zz = z; } Vector2Set( biPoints[3], xx, zz + stepHeight ); CG_CalcBiLerp( verts, subVerts, biPoints ); float dif = DistanceSquared( subVerts[0], dmgPt ) * timeDecay - Q_flrand(0.0f, 1.0f) * 32; // If we decrease dif, we are increasing the impact area, making it more likely to blow out large holes dif -= dmgRadius * dmgRadius; if ( dif > 1 ) { stick = true; time = dif + Q_flrand(0.0f, 1.0f) * 200; } else { stick = false; time = 0; } CG_DoGlassQuad( subVerts, biPoints, stick, time, dmgDir ); } } }
void CG_DoGlass( vec3_t verts[4], vec3_t normal, vec3_t dmgPt, vec3_t dmgDir, float dmgRadius, int maxShards ) { int i, t; int mxHeight, mxWidth; float height, width; float stepWidth, stepHeight; float timeDecay; float x, z; float xx, zz; float dif; int time = 0; int glassShards = 0; qboolean stick = qtrue; vec3_t subVerts[4]; vec2_t biPoints[4]; // To do a smarter tesselation, we should figure out the relative height and width of the brush face, // then use this to pick a lod value from 1-3 in each axis. This will give us 1-9 lod levels, which will // hopefully be sufficient. CG_CalcHeightWidth( verts, &height, &width ); trap->S_StartSound( dmgPt, -1, CHAN_AUTO, trap->S_RegisterSound("sound/effects/glassbreak1.wav")); // Pick "LOD" for height if ( height < 100 ) { stepHeight = 0.2f; mxHeight = 5; timeDecay = TIME_DECAY_SLOW; } else if ( height > 220 ) { stepHeight = 0.05f; mxHeight = 20; timeDecay = TIME_DECAY_FAST; } else { stepHeight = 0.1f; mxHeight = 10; timeDecay = TIME_DECAY_MED; } // Pick "LOD" for width /* if ( width < 100 ) { stepWidth = 0.2f; mxWidth = 5; timeDecay = ( timeDecay + TIME_DECAY_SLOW ) * 0.5f; } else if ( width > 220 ) { stepWidth = 0.05f; mxWidth = 20; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; } else { stepWidth = 0.1f; mxWidth = 10; timeDecay = ( timeDecay + TIME_DECAY_MED ) * 0.5f; } */ //Attempt to scale the glass directly to the size of the window stepWidth = (0.25f - (width*0.0002)); //(width*0.0005)); mxWidth = width*0.2; timeDecay = ( timeDecay + TIME_DECAY_FAST ) * 0.5f; if (stepWidth < 0.01f) { stepWidth = 0.01f; } if (mxWidth < 5) { mxWidth = 5; } for ( z = 0.0f, i = 0; z < 1.0f; z += stepHeight, i++ ) { for ( x = 0.0f, t = 0; x < 1.0f; x += stepWidth, t++ ) { // This is nasty.. if ( t > 0 && t < mxWidth ) { xx = x - offX[i][t]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t][i]; } else { zz = z; } Vector2Set( biPoints[0], xx, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i][t + 1]; } else { xx = x; } if ( i > 0 && i < mxHeight ) { zz = z - offZ[t + 1][i]; } else { zz = z; } Vector2Set( biPoints[1], xx + stepWidth, zz ); if ( t + 1 > 0 && t + 1 < mxWidth ) { xx = x - offX[i + 1][t + 1]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t + 1][i + 1]; } else { zz = z; } Vector2Set( biPoints[2], xx + stepWidth, zz + stepHeight); if ( t > 0 && t < mxWidth ) { xx = x - offX[i + 1][t]; } else { xx = x; } if ( i + 1 > 0 && i + 1 < mxHeight ) { zz = z - offZ[t][i + 1]; } else { zz = z; } Vector2Set( biPoints[3], xx, zz + stepHeight ); CG_CalcBiLerp( verts, subVerts, biPoints ); dif = DistanceSquared( subVerts[0], dmgPt ) * timeDecay - random() * 32; // If we decrease dif, we are increasing the impact area, making it more likely to blow out large holes dif -= dmgRadius * dmgRadius; if ( dif > 1 ) { stick = qtrue; time = dif + random() * 200; } else { stick = qfalse; time = 0; } CG_DoGlassQuad( subVerts, biPoints, stick, time, dmgDir ); glassShards++; if (maxShards && glassShards >= maxShards) { return; } } } }