@@ -181,66 +181,52 @@ void parse_decals_table(const char* filename) {
181181 }
182182}
183183
184- struct Decal {
185- int definition_handle = -1 ;
186- object_h object;
187- int orig_obj_type = OBJ_NONE;
188- int submodel = -1 ;
189-
190- float creation_time = -1 .0f ; // !< The mission time at which this decal was created
191- float lifetime = -1 .0f ; // !< The time this decal is active. When negative it never expires
192-
193- vec3d position = vmd_zero_vector;
194- vec3d scale;
195- matrix orientation = vmd_identity_matrix;
184+ Decal::Decal () {
185+ vm_vec_make (&scale, 1 .f , 1 .f , 1 .f );
186+ }
196187
197- Decal () {
198- vm_vec_make (&scale, 1 .f , 1 .f , 1 .f );
188+ bool Decal::isValid () const {
189+ if (!object.isValid ()) {
190+ return false ;
191+ }
192+ if (object.objp ()->flags [Object::Object_Flags::Should_be_dead]) {
193+ return false ;
199194 }
200195
201- bool isValid () const {
202- if (!object.isValid ()) {
203- return false ;
204- }
205- if (object.objp ()->flags [Object::Object_Flags::Should_be_dead]) {
206- return false ;
207- }
196+ if (orig_obj_type != object.objp ()->type ) {
197+ mprintf ((" Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n " ,
198+ object.objnum , Object_type_names[orig_obj_type], Object_type_names[object.objp ()->type ]));
199+ return false ;
200+ }
208201
209- if (orig_obj_type != object. objp ()-> type ) {
210- mprintf (( " Decal object type for object %d has changed from %s to %s. Please let m!m know about this \n " ,
211- object. objnum , Object_type_names[orig_obj_type], Object_type_names[object. objp ()-> type ]));
202+ if (lifetime > 0 . 0f ) {
203+ if ( f2fl (Missiontime) >= creation_time + lifetime) {
204+ // Decal has expired
212205 return false ;
213206 }
207+ }
214208
215- if (lifetime > 0 .0f ) {
216- if (f2fl (Missiontime) >= creation_time + lifetime) {
217- // Decal has expired
218- return false ;
219- }
220- }
221-
222- auto objp = object.objp ();
223- if (objp->type == OBJ_SHIP) {
224- auto shipp = &Ships[objp->instance ];
225- auto model_instance = model_get_instance (shipp->model_instance_num );
209+ auto objp = object.objp ();
210+ if (objp->type == OBJ_SHIP) {
211+ auto shipp = &Ships[objp->instance ];
212+ auto model_instance = model_get_instance (shipp->model_instance_num );
226213
227- Assertion (submodel >= 0 && submodel < object_get_model (objp)->n_models ,
228- " Invalid submodel number detected!" );
229- auto smi = &model_instance->submodel [submodel];
214+ Assertion (submodel >= 0 && submodel < object_get_model (objp)->n_models ,
215+ " Invalid submodel number detected!" );
216+ auto smi = &model_instance->submodel [submodel];
230217
231- if (smi->blown_off ) {
232- return false ;
233- }
234- } else {
235- Assertion (false , " Only ships are currently supported for decals!" );
218+ if (smi->blown_off ) {
236219 return false ;
237220 }
238-
239- return true ;
221+ } else {
222+ Assertion (false , " Only ships are currently supported for decals!" );
223+ return false ;
240224 }
241- };
242225
243- SCP_vector<Decal> active_decals;
226+ return true ;
227+ }
228+
229+ SCP_vector<Decal> active_decals, active_single_frame_decals;
244230
245231bool required_string_if_new (const char * token, bool new_entry) {
246232 if (!new_entry) {
@@ -374,7 +360,7 @@ void initializeMission() {
374360const float DECAL_ANGLE_CUTOFF = fl_radians(45 .f);
375361const float DECAL_ANGLE_FADE_START = fl_radians(30 .f);
376362
377- static matrix4 getDecalTransform (Decal& decal, float alpha) {
363+ static matrix4 getDecalTransform (const Decal& decal, float alpha) {
378364 Assertion (decal.object .objp ()->type == OBJ_SHIP, " Only ships are currently supported for decals!" );
379365
380366 auto objp = decal.object .objp ();
@@ -418,6 +404,51 @@ static matrix4 getDecalTransform(Decal& decal, float alpha) {
418404 return mat4;
419405}
420406
407+ inline static void renderDecal (graphics::decal_draw_list& draw_list, const Decal& decal) {
408+ auto mission_time = f2fl (Missiontime);
409+
410+ int diffuse_bm = -1 ;
411+ int glow_bm = -1 ;
412+ int normal_bm = -1 ;
413+
414+ auto decal_time = mission_time - decal.creation_time ;
415+ auto progress = decal_time / decal.lifetime ;
416+
417+ float alpha = 1 .0f ;
418+ if (progress > 0.8 ) {
419+ // Fade the decal out for the last 20% of its lifetime
420+ alpha = 1 .0f - smoothstep (0 .8f , 1 .0f , progress);
421+ }
422+
423+ if (std::holds_alternative<int >(decal.definition_handle )) {
424+ int definition_handle = std::get<int >(decal.definition_handle );
425+ Assertion (definition_handle >= 0 && definition_handle < (int ) DecalDefinitions.size (),
426+ " Invalid decal handle detected!" );
427+ auto &decalDef = DecalDefinitions[definition_handle];
428+
429+ if (decalDef.getDiffuseBitmap () >= 0 ) {
430+ diffuse_bm = decalDef.getDiffuseBitmap ()
431+ +
432+ bm_get_anim_frame (decalDef.getDiffuseBitmap (), decal_time, 0 .0f , decalDef.isDiffuseLooping ());
433+ }
434+
435+ if (decalDef.getGlowBitmap () >= 0 ) {
436+ glow_bm = decalDef.getGlowBitmap ()
437+ + bm_get_anim_frame (decalDef.getGlowBitmap (), decal_time, 0 .0f , decalDef.isGlowLooping ());
438+ }
439+
440+ if (decalDef.getNormalBitmap () >= 0 ) {
441+ normal_bm = decalDef.getNormalBitmap ()
442+ + bm_get_anim_frame (decalDef.getNormalBitmap (), decal_time, 0 .0f , decalDef.isNormalLooping ());
443+ }
444+ }
445+ else {
446+ std::tie (diffuse_bm, glow_bm, normal_bm) = std::get<std::tuple<int , int , int >>(decal.definition_handle );
447+ }
448+
449+ draw_list.add_decal (diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform (decal, alpha));
450+ }
451+
421452void renderAll () {
422453 if (!Decal_system_active || !Decal_option_active || !gr_is_capable (gr_capability::CAPABILITY_INSTANCED_RENDERING)) {
423454 return ;
@@ -442,51 +473,21 @@ void renderAll() {
442473 ++iter;
443474 }
444475
445- if (active_decals.empty ()) {
476+ if (active_decals.empty () && active_single_frame_decals. empty () ) {
446477 return ;
447478 }
448479
449- auto mission_time = f2fl (Missiontime);
450-
451- graphics::decal_draw_list draw_list;
452- for (auto & decal : active_decals) {
453-
454- Assertion (decal.definition_handle >= 0 && decal.definition_handle < (int )DecalDefinitions.size (),
455- " Invalid decal handle detected!" );
456- auto & decalDef = DecalDefinitions[decal.definition_handle ];
457480
458- int diffuse_bm = -1 ;
459- int glow_bm = -1 ;
460- int normal_bm = -1 ;
461481
462- auto decal_time = mission_time - decal.creation_time ;
463- auto progress = decal_time / decal.lifetime ;
464-
465- float alpha = 1 .0f ;
466- if (progress > 0.8 ) {
467- // Fade the decal out for the last 20% of its lifetime
468- alpha = 1 .0f - smoothstep (0 .8f , 1 .0f , progress);
469- }
470-
471- if (decalDef.getDiffuseBitmap () >= 0 ) {
472- diffuse_bm = decalDef.getDiffuseBitmap ()
473- + bm_get_anim_frame (decalDef.getDiffuseBitmap (), decal_time, 0 .0f , decalDef.isDiffuseLooping ());
474- }
475-
476- if (decalDef.getGlowBitmap () >= 0 ) {
477- glow_bm = decalDef.getGlowBitmap ()
478- + bm_get_anim_frame (decalDef.getGlowBitmap (), decal_time, 0 .0f , decalDef.isGlowLooping ());
479- }
480-
481- if (decalDef.getNormalBitmap () >= 0 ) {
482- normal_bm = decalDef.getNormalBitmap ()
483- + bm_get_anim_frame (decalDef.getNormalBitmap (), decal_time, 0 .0f , decalDef.isNormalLooping ());
484- }
485-
486- draw_list.add_decal (diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform (decal, alpha));
487- }
482+ graphics::decal_draw_list draw_list;
483+ for (auto & decal : active_decals)
484+ renderDecal (draw_list, decal);
485+ for (auto & decal : active_single_frame_decals)
486+ renderDecal (draw_list, decal);
488487
489488 draw_list.render ();
489+
490+ active_single_frame_decals.clear ();
490491}
491492
492493void addDecal (creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
@@ -531,4 +532,8 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d
531532 active_decals.push_back (newDecal);
532533}
533534
535+ void addSingleFrameDecal (Decal&& info) {
536+ active_single_frame_decals.push_back (info);
537+ }
538+
534539}
0 commit comments