Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //TODO: redo all of the angles, vectors, and math code, and look into quaternions!
- typedef struct splatterPatternData_s
- {
- const splatterAttributes_t *splatter;
- int seed;
- const int *fragment_num;
- float (*distribution)( struct splatterPatternData_s *data, angleIndex_t angle_index );
- void (*pattern)( struct splatterPatternData_s *data, vec3_t out );
- } splatterPatternData_t;
- /*
- ==============
- BG_SplatterRandom
- ==============
- */
- static float BG_SplatterRandom( splatterPatternData_t *data, angleIndex_t angle_index ) {
- Com_Assert( data &&
- "BG_SplatterRandom: data is NULL" );
- return Q_random( &data->seed );
- }
- /*
- ==============
- BG_SplatterUniform
- ==============
- */
- static float BG_SplatterUniform( splatterPatternData_t *data, angleIndex_t angle_index ) {
- const int yaw_layers = data->splatter->number / data->splatter->pitchLayers;
- Com_Assert( data &&
- "BG_SplatterUniform: data is NULL" );
- Com_Assert( data->fragment_num &&
- "BG_SplatterUniform: data->fragment_num is NULL" );
- if( angle_index == YAW ) {
- const int yaw_layer_num = *data->fragment_num % yaw_layers;
- float yaw_position = ( ( data->seed & 0xffff ) / (float)0x10000 ); // start the overall pattern at a random YAW
- yaw_position += ( (float)yaw_layer_num ) / ( (float)( yaw_layers ) );
- return yaw_position - ( (int)yaw_position );
- }
- //at this point angle_index must be PITCH
- Com_Assert( ( angle_index == PITCH ) &&
- "BG_SplatterUniform: angle_index is invalid" );
- {
- const int pitch_layer_num = *data->fragment_num / yaw_layers;
- return ( (float)pitch_layer_num ) / ( (float)data->splatter->pitchLayers - 1 );
- }
- }
- /*
- ==============
- BG_SplatterUniformAlternating
- ==============
- */
- static float BG_SplatterUniformAlternating( splatterPatternData_t *data, angleIndex_t angle_index ) {
- const int yaw_layers = data->splatter->number / data->splatter->pitchLayers;
- Com_Assert( data &&
- "BG_SplatterUniform: data is NULL" );
- Com_Assert( data->fragment_num &&
- "BG_SplatterUniform: data->fragment_num is NULL" );
- if( angle_index == YAW ) {
- const int pitch_layer_num = *data->fragment_num / yaw_layers;
- const int yaw_layer_num = *data->fragment_num % yaw_layers;
- float yaw_position = ( ( data->seed & 0xffff ) / (float)0x10000 ); // start the overall pattern at a random YAW
- //alternate by a half yaw position between pitch layers
- yaw_position += 0.5 * ( ( (float)pitch_layer_num ) / ( (float)yaw_layers ) );
- yaw_position += ( (float)yaw_layer_num ) / ( (float)( yaw_layers - 1 ) );
- return yaw_position - ( (int)yaw_position );
- }
- //at this point angle_index must be PITCH
- Com_Assert( ( angle_index == PITCH ) &&
- "BG_SplatterUniform: angle_index is invalid" );
- {
- const int pitch_layer_num = *data->fragment_num / yaw_layers;
- return ( (float)pitch_layer_num ) / ( (float)( data->splatter->pitchLayers - 1 ) );
- }
- }
- /*
- ==============
- BG_SplatterSphericalCone
- ==============
- */
- static void BG_SplatterSphericalCone( splatterPatternData_t *data, vec3_t out ) {
- vec3_t splatter_angles;
- Com_Assert( data &&
- "BG_SplatterSphericalCone: data is NULL" );
- Com_Assert( data->distribution &&
- "BG_SplatterSphericalCone: distribution function is NULL" );
- Com_Assert( out &&
- "BG_SplatterSphericalCone: out is NULL" );
- splatter_angles[PITCH] = data->distribution( data, PITCH ) * data->splatter->spread;
- AngleNormalize180( splatter_angles[PITCH] );
- splatter_angles[PITCH] -= 90; //the spread angle is in relation to pointing straight up
- splatter_angles[YAW] = data->distribution( data, YAW ) * 360;
- AngleNormalize360( splatter_angles[YAW] );
- splatter_angles[ROLL] = 0;
- AngleVectors( splatter_angles, out, NULL, NULL );
- VectorNormalize( out );
- }
- /*
- ==============
- BG_SplatterMirroredInverseSphericalCone
- ==============
- */
- static void BG_SplatterMirroredInverseSphericalCone( splatterPatternData_t *data, vec3_t out ) {
- vec3_t splatter_angles;
- Com_Assert( data &&
- "BG_SplatterSphericalCone: data is NULL" );
- Com_Assert( data->distribution &&
- "BG_SplatterSphericalCone: distribution function is NULL" );
- Com_Assert( out &&
- "BG_SplatterSphericalCone: out is NULL" );
- splatter_angles[PITCH] = data->distribution( data, PITCH ) * data->splatter->spread;
- AngleNormalize180( splatter_angles[PITCH] );
- splatter_angles[PITCH] -= ( data->splatter->spread * 0.5f ); //the spread angle is centered at the horizontal
- splatter_angles[YAW] = data->distribution( data, YAW ) * 360;
- AngleNormalize360( splatter_angles[YAW] );
- splatter_angles[ROLL] = 0;
- AngleVectors( splatter_angles, out, NULL, NULL );
- VectorNormalize( out );
- }
- /*
- ==============
- BG_SplatterPattern
- For the shotgun, frag nade, acidtubes, flamer, etc...
- ==============
- */
- void BG_SplatterPattern( vec3_t origin2, int seed, int passEntNum,
- splatterData_t *data, void (*func)( splatterData_t *data ),
- void (*trace)( trace_t *, const vec3_t,
- const vec3_t, const vec3_t,
- const vec3_t, int, int ) ) {
- int i;
- const int modeIndex = data->weaponMode - 1;
- weapon_t weapon = data->weapon;
- vec3_t origin, forward, cross;
- const vec3_t up_absolute = { 0.0f, 0.0f, 1.0f };
- float rotation_angle, cross_length, dot;
- trace_t tr;
- splatterPatternData_t splatterData;
- memset( &splatterData, 0, sizeof( splatterData ) );
- splatterData.splatter = &BG_Weapon( weapon )->splatter[modeIndex];
- Com_Assert( modeIndex >= 0 &&
- modeIndex < 3 &&
- "BG_SplatterPattern: invalid weaponMode" );
- Com_Assert( trace &&
- "BG_SplatterPattern: trace is NULL" );
- Com_Assert( func &&
- "BG_SplatterPattern: func is NULL" );
- Com_Assert( splatterData.splatter &&
- "BG_SplatterPattern: splatterData.splatter is NULL" );
- Com_Assert( splatterData.splatter->spread >= 0 &&
- splatterData.splatter->spread <= 180 &&
- "BG_SplatterPattern: spread is out of range" );
- Com_Assert( ( splatterData.distribution == SPLATD_RANDOM ||
- splatterData.splatter->pitchLayers > 0 ) &&
- "BG_SplatterPattern: pitch layers must be greater than 0" );
- Com_Assert( ( splatterData.distribution == SPLATD_RANDOM ||
- splatterData.splatter->pitchLayers < splatterData.splatter->number ) &&
- "BG_SplatterPattern: pitch layers must be less than the total number of fragments" );
- Com_Assert( ( splatterData.distribution == SPLATD_RANDOM ||
- !( splatterData.splatter->number % splatterData.splatter->pitchLayers ) ) &&
- "BG_SplatterPattern: pitch layers must be a factor of the number of fragments for even yaw layers" );
- splatterData.seed = seed;
- VectorCopy( data->origin, origin );
- //select the pattern type
- switch ( splatterData.splatter->pattern ) {
- case SPLATP_SPHERICAL_CONE:
- splatterData.pattern = BG_SplatterSphericalCone;
- break;
- case SPLATP_MIRRORED_INVERSE_SPHERICAL_CONE:
- splatterData.pattern = BG_SplatterMirroredInverseSphericalCone;
- break;
- }
- Com_Assert( splatterData.pattern &&
- "BG_SplatterPattern: pattern function not selected" );
- switch( splatterData.splatter->distribution ) {
- case SPLATD_RANDOM:
- splatterData.distribution = BG_SplatterRandom;
- break;
- case SPLATD_UNIFORM:
- splatterData.distribution = BG_SplatterUniform;
- break;
- case SPLATD_UNIFORM_ALTERNATING:
- splatterData.distribution = BG_SplatterUniformAlternating;
- break;
- }
- Com_Assert( splatterData.distribution &&
- "BG_SplatterPattern: distribution function not selected" );
- //prepare for rotation to the facing direction
- VectorCopy( origin2, forward );
- CrossProduct( up_absolute, forward, cross );
- cross_length = VectorLength( cross );
- dot = DotProduct( up_absolute, forward );
- if( cross_length > 0 ) {
- VectorNormalize( cross );
- rotation_angle = RAD2DEG( atan2( cross_length, dot) );
- } else if( dot > 0.0f ) {
- rotation_angle = 0;
- } else {
- rotation_angle = 180;
- }
- // generate the pattern
- for( i = 0; i < splatterData.splatter->number; i++ ) {
- vec3_t dir, temp, end;
- splatterData.fragment_num = &i;
- //get the next pattern vector
- splatterData.pattern( &splatterData, temp );
- //rotate toward the facing direction
- if( cross_length > 0 ) {
- RotatePointAroundVector( dir, cross, temp, rotation_angle );
- } else if( dot > 0.0f ){
- VectorCopy( temp, dir );
- } else {
- VectorScale( temp, -1.0f, dir );
- }
- VectorMA( origin, splatterData.splatter->range, dir, end );
- //apply the impact
- trace( &tr, origin, NULL, NULL, end, passEntNum, MASK_SHOT );
- data->tr = &tr;
- func( data );
- }
- }
Add Comment
Please, Sign In to add comment