|
26 | 26 | #include <math/fvi.h> |
27 | 27 | #include <graphics/light.h> |
28 | 28 | #include <mod_table/mod_table.h> |
| 29 | +#include <cfile/cfile.h> |
29 | 30 |
|
30 | 31 | #include "mission/object.h" |
31 | 32 | #include "prop/prop.h" |
@@ -263,12 +264,24 @@ FredRenderer::FredRenderer(os::Viewport* targetView) : _targetView(targetView) { |
263 | 264 | init_fred_colors(); |
264 | 265 | } |
265 | 266 | FredRenderer::~FredRenderer() { |
| 267 | + freeVolumetricModel(); |
266 | 268 | } |
267 | 269 | void FredRenderer::setViewport(EditorViewport* viewport) { |
268 | 270 | Assertion(_viewport == nullptr, "Resetting viewport is not supported"); |
269 | 271 | Assertion(viewport != nullptr, "Invalid viewport specified!"); |
270 | 272 |
|
271 | 273 | _viewport = viewport; |
| 274 | + |
| 275 | + connect(_viewport->editor, &Editor::missionLoaded, this, |
| 276 | + [this](const std::string&) { freeVolumetricModel(); }); |
| 277 | +} |
| 278 | + |
| 279 | +void FredRenderer::freeVolumetricModel() { |
| 280 | + if (_volumetric_model_num >= 0) { |
| 281 | + model_unload(_volumetric_model_num); |
| 282 | + _volumetric_model_num = -1; |
| 283 | + } |
| 284 | + _volumetric_cached_pof.clear(); |
272 | 285 | } |
273 | 286 |
|
274 | 287 | void FredRenderer::render_grid(grid* gridp) { |
@@ -867,6 +880,65 @@ void FredRenderer::render_one_model_htl(object* objp, |
867 | 880 | rendering_order.push_back(OBJ_INDEX(objp)); |
868 | 881 | } |
869 | 882 |
|
| 883 | +void FredRenderer::render_volumetric_overlay() { |
| 884 | + if (!The_mission.volumetrics) { |
| 885 | + return; |
| 886 | + } |
| 887 | + |
| 888 | + constexpr float alpha = 0.35f; |
| 889 | + |
| 890 | + const volumetric_nebula& neb = *The_mission.volumetrics; |
| 891 | + if (!neb.get_enabled() || neb.getHullPof().empty()) { |
| 892 | + return; |
| 893 | + } |
| 894 | + |
| 895 | + const SCP_string& pof = neb.getHullPof(); |
| 896 | + if (pof != _volumetric_cached_pof) { |
| 897 | + // Stamp the cache before model_load so a re-entrant paint (e.g. from |
| 898 | + // an Error() dialog pumping events on a missing POF) sees the load |
| 899 | + // as already attempted and bails out instead of re-loading. |
| 900 | + freeVolumetricModel(); |
| 901 | + _volumetric_cached_pof = pof; |
| 902 | + if (cf_exists_full(pof.c_str(), CF_TYPE_MODELS)) { |
| 903 | + _volumetric_model_num = model_load(pof.c_str()); |
| 904 | + } else { |
| 905 | + mprintf(("Volumetric nebula hull POF '%s' not found; skipping editor overlay.\n", pof.c_str())); |
| 906 | + if (_viewport->dialogProvider != nullptr) { |
| 907 | + SCP_string msg = "Volumetric nebula hull POF '"; |
| 908 | + msg += pof; |
| 909 | + msg += "' was not found. The nebula will render without an editor overlay until a valid POF is set in the Volumetric Nebula dialog."; |
| 910 | + _viewport->dialogProvider->showButtonDialog(DialogType::Warning, |
| 911 | + "Volumetric Nebula POF Missing", |
| 912 | + msg, |
| 913 | + { DialogButton::Ok }); |
| 914 | + } |
| 915 | + } |
| 916 | + } |
| 917 | + |
| 918 | + if (_volumetric_model_num < 0) { |
| 919 | + return; |
| 920 | + } |
| 921 | + |
| 922 | + const auto& col = neb.getNebulaColor(); |
| 923 | + // Premultiply by alpha. MR_NO_TEXTURING + MR_ALL_XPARENT lands on |
| 924 | + // ALPHA_BLEND_ADDITIVE (glBlendFunc(GL_ONE, GL_ONE)) which ignores |
| 925 | + // src.alpha, so scaling RGB here is what actually controls intensity. |
| 926 | + const int r = static_cast<int>(std::get<0>(col) * alpha * 255.0f); |
| 927 | + const int g = static_cast<int>(std::get<1>(col) * alpha * 255.0f); |
| 928 | + const int b = static_cast<int>(std::get<2>(col) * alpha * 255.0f); |
| 929 | + const vec3d pos = neb.getPos(); |
| 930 | + |
| 931 | + enable_htl(); |
| 932 | + |
| 933 | + model_render_params fill; |
| 934 | + fill.set_color(r, g, b); |
| 935 | + fill.set_alpha(1.0f); |
| 936 | + fill.set_flags(MR_NO_LIGHTING | MR_NO_TEXTURING | MR_NO_BATCH | MR_ALL_XPARENT); |
| 937 | + model_render_immediate(&fill, _volumetric_model_num, &vmd_identity_matrix, &pos); |
| 938 | + |
| 939 | + disable_htl(); |
| 940 | +} |
| 941 | + |
870 | 942 | void FredRenderer::render_models(int cur_object_index) { |
871 | 943 | gr_set_color_fast(&colour_white); |
872 | 944 |
|
@@ -945,6 +1017,7 @@ void FredRenderer::render_frame(int cur_object_index, |
945 | 1017 |
|
946 | 1018 | gr_set_color(0, 0, 64); |
947 | 1019 | render_models(cur_object_index); |
| 1020 | + render_volumetric_overlay(); |
948 | 1021 |
|
949 | 1022 | if (view().Show_distances) { |
950 | 1023 | display_distances(); |
|
0 commit comments