#include "Raster_Image_p.h" #include "../Axis/Abs_Axis_p.h" #include "../base/Memory.h" #include "../render/Canvas.h" namespace renderive { struct Raster_Image_Input_Data : Latest_Input_Data { Image image; void push(const Image& value) { image = value; mark_latest_pushed(); } template void read_all(Handler handler) { if (pending) handler(image); } void clear() override { image = Image(); clear_latest(); } }; struct Raster_Image_Render_State : Render_State, Raster_Image_Prop {}; struct Raster_Image_Private : Typed_Render_Data { Image image; void prepare_data(const Render_Frame_Snapshot&, const Renderable_Frame_View& frame_view) override { Raster_Image_Input_Data* input = render_input_data(frame_view); if (!input) return; input->read_all([this](const Image& value) { image = value; }); frame_view.consume_input(); } void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) override { Raster_Image_Render_State* s = render_state(frame_view); if (!s) return; auto domain_axis = s->domain_axis.lock(); auto value_axis = s->value_axis.lock(); if (!domain_axis || !value_axis || image.empty()) return; if (s->domain_range.length() == 0.0 || s->value_range.length() == 0.0) return; Axis_Mapping_2D mapping = Axis_Render_Access::mapping(domain_axis.get(), value_axis.get(), snapshot); Axis_Basis_2D basis = Axis_Basis_2D::from_ranges(mapping, s->domain_range, s->value_range); RectF source_rect = s->source_rect.empty() ? RectF{0.0, 0.0, (double)image.width(), (double)image.height()} : s->source_rect; if (source_rect.width == 0.0 || source_rect.height == 0.0) return; canvas.save(); canvas.set_image_interpolation(s->interpolation_mode); canvas.transform( basis.domain_vector.x / source_rect.width, basis.domain_vector.y / source_rect.width, basis.value_vector.x / source_rect.height, basis.value_vector.y / source_rect.height, basis.origin.x, basis.origin.y); canvas.draw_image(RectF{0.0, 0.0, source_rect.width, source_rect.height}, image, source_rect); canvas.restore(); } }; RENDERIVE_DEFINE_RENDERABLE_BINDING(Raster_Image, Raster_Image_Private, Raster_Image_Render_State, Raster_Image_Input_Data, "RasterImage") void Raster_Image::update_image(const Image& image) { if (!ok()) return; Render_Input_Lease input(d()); input->push(image); } void Raster_Image::update_image_frame(const Image& image, Range domain_range, Range value_range, RectF source_rect, Image_Interpolation_Mode interpolation_mode) { if (domain_range.length() == 0.0 || value_range.length() == 0.0) return; if (!ok()) return; Raster_Image_Private* pd = d(); Render_Edit_Lease edit(pd); if (!edit) return; edit->domain_range = domain_range; edit->value_range = value_range; edit->source_rect = source_rect; edit->interpolation_mode = interpolation_mode; Render_Input_Lease input(pd); input->push(image); } RENDERIVE_DEFINE_WEAK_STATE_PROP(Raster_Image, Raster_Image_Render_State, Abs_Axis, domain_axis) RENDERIVE_DEFINE_WEAK_STATE_PROP(Raster_Image, Raster_Image_Render_State, Abs_Axis, value_axis) Range Raster_Image::domain_range() { return d()->edit_state_value(&Raster_Image_Render_State::domain_range); } void Raster_Image::set_domain_range(Range value) { if (value.length() == 0.0) return; d()->set_state_value(&Raster_Image_Render_State::domain_range, value); } Range Raster_Image::value_range() { return d()->edit_state_value(&Raster_Image_Render_State::value_range); } void Raster_Image::set_value_range(Range value) { if (value.length() == 0.0) return; d()->set_state_value(&Raster_Image_Render_State::value_range, value); } RENDERIVE_DEFINE_STATE_PROP(Raster_Image, Raster_Image_Render_State, RectF, source_rect) RENDERIVE_DEFINE_STATE_PROP(Raster_Image, Raster_Image_Render_State, Image_Interpolation_Mode, interpolation_mode) Raster_Image::Builder::Builder(std::shared_ptr parent, std::shared_ptr domain_axis, std::shared_ptr value_axis) { ASSERT(parent, "Raster_Image build error! parent == nullptr"); ASSERT(domain_axis && value_axis, "Raster_Image build error! axis == nullptr"); ASSERT(domain_axis->attached_to_plot(), "Raster_Image build error! domain_axis->plot == nullptr"); ASSERT(domain_axis->shares_plot_with(*value_axis), "Raster_Image build error! domain_axis->plot != value_axis->plot"); ASSERT(parent->shares_plot_with(*domain_axis), "Raster_Image build error! parent->plot != axis->plot"); ASSERT(domain_axis->orientation() != value_axis->orientation(), "Raster_Image build error! axes must be orthogonal"); this->parent = parent; this->domain_axis = domain_axis; this->value_axis = value_axis; } std::shared_ptr Raster_Image::Builder::build() { auto ret = renderive::make_shared(); ret->init(parent); Raster_Image_Private* pd = ret->d(); Render_Edit_Lease edit(pd); Raster_Image_Render_State* sc = edit.operator->(); PROP_R(std::weak_ptr, domain_axis) PROP_R(std::weak_ptr, value_axis) PROP_R(Range, domain_range) PROP_R(Range, value_range) PROP_R(RectF, source_rect) PROP_R(Image_Interpolation_Mode, interpolation_mode) if (sc->domain_range.length() == 0.0) sc->domain_range = {0.0, 1.0}; if (sc->value_range.length() == 0.0) sc->value_range = {0.0, 1.0}; return ret; } } // namespace renderive