1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "math/vecmat.h"
#include "object/object.h"
#include "parse/parselo.h"
#include "particle/particle.h"
#include "particle/ParticleEffect.h"
#include "weapon/muzzleflash.h"
#include "model/modelrender.h"
// ---------------------------------------------------------------------------------------------------------------------
// MUZZLE FLASH DEFINES/VARS
//
// muzzle flash info - read from a table
typedef struct mflash_blob_info {
char name[MAX_FILENAME_LEN];
float offset;
float radius;
mflash_blob_info( const mflash_blob_info& mbi )
{
strcpy_s( name, mbi.name );
offset = mbi.offset;
radius = mbi.radius;
}
mflash_blob_info() :
offset( 0.0 ),
radius( 0.0 )
{
name[ 0 ] = '\0';
}
mflash_blob_info& operator=( const mflash_blob_info& r )
{
strcpy_s( name, r.name );
offset = r.offset;
radius = r.radius;
return *this;
}
} mflash_blob_info;
typedef struct mflash_info {
char name[MAX_FILENAME_LEN];
SCP_vector<mflash_blob_info> blobs;
mflash_info()
{
name[ 0 ] = '\0';
}
mflash_info( const mflash_info& mi )
{
strcpy_s( name, mi.name );
blobs = mi.blobs;
}
mflash_info& operator=( const mflash_info& r )
{
strcpy_s( name, r.name );
blobs = r.blobs;
return *this;
}
} mflash_info;
SCP_vector<mflash_info> Mflash_info;
// ---------------------------------------------------------------------------------------------------------------------
// MUZZLE FLASH FUNCTIONS
//
static const SCP_string mflash_particle_prefix = ";MflashParticle;";
void parse_mflash_tbl(const char *filename)
{
uint i;
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// header
required_string("#Muzzle flash types");
while (optional_string("$Mflash:")) {
mflash_info mflash;
bool override_mflash = false;
required_string("+name:");
stuff_string(mflash.name, F_NAME, MAX_FILENAME_LEN);
if (optional_string("+override"))
override_mflash = true;
// read in all blobs
while (optional_string("+blob_name:")) {
mflash_blob_info mblob;
stuff_string(mblob.name, F_NAME, MAX_FILENAME_LEN);
required_string("+blob_offset:");
stuff_float(&mblob.offset);
required_string("+blob_radius:");
stuff_float(&mblob.radius);
mflash.blobs.push_back(mblob);
}
for (i = 0; i < Mflash_info.size(); i++) {
if (!stricmp(mflash.name, Mflash_info[i].name)) {
if (override_mflash) {
Mflash_info[i] = mflash;
}
break;
}
}
// no matching name exists so add as new
if (i == Mflash_info.size()) {
Mflash_info.push_back(mflash);
}
// a mflash of the same name exists, don't add it again
else {
if (!override_mflash) {
Warning(LOCATION, "Muzzle flash \"%s\" already exists! Using existing entry instead.", mflash.name);
}
}
}
// close
required_string("#end");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
static void convert_mflash_to_particle() {
Curve new_curve = Curve(";MuzzleFlashMinSizeScalingCurve");
new_curve.keyframes.emplace_back(curve_keyframe{vec2d{ -0.00001f , 0.f}, CurveInterpFunction::Polynomial, -1.0f, 1.0f}); //just for numerical safety if we ever get an actual size of 0...
new_curve.keyframes.emplace_back(curve_keyframe{vec2d{ Min_pizel_size_muzzleflash, 1.f }, CurveInterpFunction::Constant, 0.0f, 1.0f});
Curves.emplace_back(std::move(new_curve));
modular_curves_entry scaling_curve {(static_cast<int>(Curves.size()) - 1), ::util::UniformFloatRange(1.f), ::util::UniformFloatRange(0.f), false};
for (const auto& mflash : Mflash_info) {
SCP_vector<particle::ParticleEffect> subparticles;
for (const auto& blob : mflash.blobs) {
subparticles.emplace_back(
mflash_particle_prefix + mflash.name, //Name
::util::UniformFloatRange(1.f), //Particle num
particle::ParticleEffect::Duration::ONETIME, //Single Particle Emission
::util::UniformFloatRange(), //No duration
::util::UniformFloatRange (-1.f), //Single particle only
particle::ParticleEffect::ShapeDirection::ALIGNED, //Particle direction
::util::UniformFloatRange(1.f), //Velocity Inherit
false, //Velocity Inherit absolute?
nullptr, //Velocity volume
::util::UniformFloatRange(), //Velocity volume multiplier
particle::ParticleEffect::VelocityScaling::NONE, //Velocity directional scaling
std::nullopt, //Orientation-based velocity
std::nullopt, //Position-based velocity
nullptr, //Position volume
particle::ParticleEffectHandle::invalid(), //Trail
1.f, //Chance
false, //Affected by detail
-1.f, //Culling range multiplier
false, //Disregard Animation Length. Must be true for everything using particle::Anim_bitmap_X
false, //Don't reverse animation
true, //parent local
true, //ignore velocity inherit if parented
false, //position velocity inherit absolute?
std::nullopt, //Local velocity offset
vec3d{{{0, 0, blob.offset}}}, //Local offset
::util::UniformFloatRange(-1.f), //Lifetime
::util::UniformFloatRange(blob.radius), //Radius
bm_load_animation(blob.name));
if (Min_pizel_size_muzzleflash > 0) {
subparticles.back().m_modular_curves.add_curve("Pixel Size At Emitter", particle::ParticleEffect::ParticleCurvesOutput::RADIUS_MULT, scaling_curve);
}
}
particle::ParticleManager::get()->addEffect(std::move(subparticles));
}
//Clean up no longer required data
Mflash_info.clear();
Mflash_info.shrink_to_fit();
}
// initialize muzzle flash stuff for the whole game
void mflash_game_init()
{
// parse main table first
parse_mflash_tbl("mflash.tbl");
// look for any modular tables
parse_modular_table(NOX("*-mfl.tbm"), parse_mflash_tbl);
//This should really happen at parse time, but that requires modular particle effects which aren't yet a thing
convert_mflash_to_particle();
}
particle::ParticleEffectHandle mflash_lookup(const char *name) {
return particle::ParticleManager::get()->getEffectByName(mflash_particle_prefix + name);
}
|