180 lines
7.5 KiB
C++
180 lines
7.5 KiB
C++
#include <utility>
|
|
#include "Afterglow_p.h"
|
|
#include "../base/Frame_Memory.h"
|
|
#include "../base/Memory.h"
|
|
namespace renderive {
|
|
RENDERIVE_DEFINE_RENDERABLE_BINDING(Afterglow, Afterglow_Private, Afterglow_Render_State, Afterglow_Input_Data, "Afterglow")
|
|
std::shared_ptr<Frequency_Axis> Afterglow::frequency_axis() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::frequency_axis).lock();
|
|
}
|
|
void Afterglow::set_frequency_axis(std::shared_ptr<Frequency_Axis> value) {
|
|
d()->set_state_value(&Afterglow_Render_State::frequency_axis, std::weak_ptr<Frequency_Axis>(value));
|
|
}
|
|
std::shared_ptr<Axis> Afterglow::power_axis() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::power_axis).lock();
|
|
}
|
|
void Afterglow::set_power_axis(std::shared_ptr<Axis> value) {
|
|
d()->set_state_value(&Afterglow_Render_State::power_axis, std::weak_ptr<Axis>(value));
|
|
}
|
|
Range Afterglow::frequency_range() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::frequency_range);
|
|
}
|
|
void Afterglow::set_frequency_range(Range value) {
|
|
if (value.length() == 0.0)
|
|
return;
|
|
d()->set_state_value(&Afterglow_Render_State::frequency_range, std::move(value));
|
|
}
|
|
Range Afterglow::power_range() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::color_scale).range();
|
|
}
|
|
void Afterglow::set_power_range(Range value) {
|
|
if (value.size() == 0.0)
|
|
return;
|
|
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(d());
|
|
edit->color_scale.set_range(value);
|
|
}
|
|
int Afterglow::frequency_point_size() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::frequency_bin_count);
|
|
}
|
|
int Afterglow::power_point_size() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::power_bin_count);
|
|
}
|
|
bool Afterglow::interpolate() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::interpolate_power_bins);
|
|
}
|
|
void Afterglow::set_interpolate(bool value) {
|
|
d()->set_state_value(&Afterglow_Render_State::interpolate_power_bins, value);
|
|
}
|
|
double Afterglow::attenuation_rate() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::decay_rate);
|
|
}
|
|
void Afterglow::set_attenuation_rate(double value) {
|
|
d()->set_state_value(&Afterglow_Render_State::decay_rate, std::clamp(value, 0.0, 1.0));
|
|
}
|
|
int Afterglow::init_strong_value() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::initial_intensity_threshold);
|
|
}
|
|
void Afterglow::set_init_strong_value(int value) {
|
|
d()->set_state_value(&Afterglow_Render_State::initial_intensity_threshold, std::max(1, value));
|
|
}
|
|
Color_Map Afterglow::color_map() {
|
|
return d()->edit_state_value(&Afterglow_Render_State::color_scale).color_map();
|
|
}
|
|
void Afterglow::set_color_map(Color_Map value) {
|
|
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(d());
|
|
edit->color_scale.set_color_map(std::move(value));
|
|
}
|
|
std::shared_ptr<Color_Bar> Afterglow::color_bar() const {
|
|
return const_cast<Afterglow*>(this)->d()->color_bar.lock();
|
|
}
|
|
void Afterglow::set_frequency_point_size(int t) {
|
|
Afterglow_Private* pd = d();
|
|
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(pd);
|
|
edit->frequency_bin_count = std::max(1, t);
|
|
edit->power_bin_count = std::max(1, edit->power_bin_count);
|
|
}
|
|
void Afterglow::set_power_point_size(int t) {
|
|
Afterglow_Private* pd = d();
|
|
Render_Edit_Lease<Afterglow_Private, Afterglow_Render_State> edit(pd);
|
|
edit->frequency_bin_count = std::max(1, edit->frequency_bin_count);
|
|
edit->power_bin_count = std::max(1, t);
|
|
}
|
|
Afterglow::Builder::Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Frequency_Axis> frequency_axis, std::shared_ptr<Axis> power_axis) {
|
|
init(parent, frequency_axis, power_axis);
|
|
}
|
|
std::shared_ptr<Afterglow> Afterglow::Builder::build() {
|
|
auto ret = renderive::make_shared<Afterglow>();
|
|
set(ret.get());
|
|
return ret;
|
|
}
|
|
void Afterglow::append_spectrum(std::span<const double> power_range_data) {
|
|
if (!ok())
|
|
return;
|
|
Afterglow_Private* pd = d();
|
|
int frequency_point_size{};
|
|
{
|
|
Render_State_Lease<Afterglow_Private, Afterglow_Render_State> state(pd);
|
|
frequency_point_size = state->frequency_bin_count;
|
|
}
|
|
if (power_range_data.size() != frequency_point_size)
|
|
return;
|
|
Render_Input_Lease<Afterglow_Private, Afterglow_Input_Data> input(pd);
|
|
input->pending_spectra.push(power_range_data, Afterglow_Input_Data::Max_Pending_Frame_Count);
|
|
}
|
|
void Afterglow::append_spectrum(std::pmr::vector<double>&& power_range_data) {
|
|
if (!ok())
|
|
return;
|
|
Afterglow_Private* pd = d();
|
|
int frequency_point_size{};
|
|
{
|
|
Render_State_Lease<Afterglow_Private, Afterglow_Render_State> state(pd);
|
|
frequency_point_size = state->frequency_bin_count;
|
|
}
|
|
if (power_range_data.size() != frequency_point_size)
|
|
return;
|
|
Render_Input_Lease<Afterglow_Private, Afterglow_Input_Data> input(pd);
|
|
input->pending_spectra.push(std::move(power_range_data), Afterglow_Input_Data::Max_Pending_Frame_Count);
|
|
}
|
|
void Afterglow_Private::push_data(std::span<const double> power_range_data, const Afterglow_Render_State* s, const Color_Scale_Snapshot& color_scale) {
|
|
if (power_range_data.size() != s->frequency_bin_count ||
|
|
s->initial_intensity_threshold <= 0 ||
|
|
color_scale.range.size() == 0.0 ||
|
|
s->frequency_bin_count <= 0 ||
|
|
s->power_bin_count <= 0)
|
|
return;
|
|
std::pmr::vector<int> index_list(s->frequency_bin_count, frame_memory_resource());
|
|
double rate = (double)s->power_bin_count / color_scale.range.size();
|
|
for (int i = 0; i < s->frequency_bin_count; ++i) {
|
|
int line_index = (int)((power_range_data[i] - color_scale.range.origin) * rate);
|
|
if (line_index < 0)
|
|
line_index = 0;
|
|
if (line_index > s->power_bin_count - 1)
|
|
line_index = s->power_bin_count - 1;
|
|
index_list[i] = line_index;
|
|
}
|
|
if (!s->interpolate_power_bins) {
|
|
for (int i = 0; i < s->frequency_bin_count; ++i) {
|
|
int index = index_list[i] * s->frequency_bin_count + i;
|
|
current_intensity_grid[index]++;
|
|
}
|
|
}
|
|
else {
|
|
int last_lower = -1, last_upper = -1;
|
|
for (int i = 0; i < s->frequency_bin_count; ++i) {
|
|
int y = index_list[i];
|
|
current_intensity_grid[y * s->frequency_bin_count + i]++;
|
|
if (y - last_upper >= 2) {
|
|
for (int cur_y = last_upper + 1; cur_y < y; ++cur_y) {
|
|
current_intensity_grid[cur_y * s->frequency_bin_count + i]++;
|
|
}
|
|
last_upper = y;
|
|
last_lower = last_lower + 1;
|
|
continue;
|
|
}
|
|
if (last_lower - y >= 2) {
|
|
for (int cur_y = y + 1; cur_y < last_lower; ++cur_y) {
|
|
current_intensity_grid[cur_y * s->frequency_bin_count + i]++;
|
|
}
|
|
last_upper = last_lower - 1;
|
|
last_lower = y;
|
|
continue;
|
|
}
|
|
last_upper = y;
|
|
last_lower = y;
|
|
}
|
|
}
|
|
current_history_index++;
|
|
if (current_history_index < s->initial_intensity_threshold)
|
|
return;
|
|
current_history_index = 0;
|
|
double old_remain = s->decay_rate == 1.0 ? 1.0 : 1.0 - s->decay_rate;
|
|
double cache_remain = s->decay_rate / (double)s->initial_intensity_threshold;
|
|
for (int i = 0; i < cached_cell_count; ++i) {
|
|
merged_intensity_grid[i] = old_remain * previous_intensity_grid[i] + cache_remain * current_intensity_grid[i];
|
|
current_intensity_grid[i] = 0;
|
|
}
|
|
previous_intensity_grid = merged_intensity_grid;
|
|
image_dirty = true;
|
|
}
|
|
} // namespace renderive
|