Visual Computing Library
Loading...
Searching...
No Matches
canvas.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_BGFX_CANVAS_H
24#define VCL_BGFX_CANVAS_H
25
26#include <vclib/bgfx/context.h>
27#include <vclib/bgfx/read_framebuffer_request.h>
28#include <vclib/bgfx/system/native_window_handle.h>
29#include <vclib/io/image.h>
30#include <vclib/render/concepts/render_app.h>
31#include <vclib/render/input.h>
32#include <vclib/render/read_buffer_types.h>
33#include <vclib/types.h>
34
35#include <optional>
36
37namespace vcl {
38
69template<typename DerivedRenderApp>
71{
72 using ReadFramebufferRequest = detail::ReadFramebufferRequest;
73
74protected:
75 using FloatData = ReadBufferTypes::FloatData;
76 using ByteData = ReadBufferTypes::ByteData;
77 using ReadData = ReadBufferTypes::ReadData;
78
79public:
80 using CallbackReadBuffer = ReadBufferTypes::CallbackReadBuffer;
81
82private:
83 void* mWinId = nullptr;
84
85 // frame buffer for drawing the canvas
86 // BGFX_INVALID_HANDLE represents the default frame buffer of the window
87 bgfx::ViewId mViewId = BGFX_INVALID_VIEW;
88 bgfx::FrameBufferHandle mFbh = BGFX_INVALID_HANDLE;
89
90 // size of the canvas
91 Point2<uint> mSize = {0, 0};
92
93 vcl::Color mDefaultClearColor = vcl::Color::Black;
94
95 // current frame
96 uint32_t mCurrFrame = 0;
97
98 // offscreen readback request
99 std::optional<ReadFramebufferRequest> mReadRequest = std::nullopt;
100
101public:
103 void* winId,
104 uint width,
105 uint height,
106 void* displayId = nullptr) : mWinId(winId)
107 {
108 static_assert(
110 "The DerivedRenderApp must satisfy the RenderAppConcept.");
111
112 // on screen framebuffer
113 mViewId = Context::instance(mWinId, displayId).requestViewId();
114
115 // (re)create the framebuffers
116 onResize(width, height);
117 }
118
120 {
121 // deallocate the framebuffers
122 if (bgfx::isValid(mFbh))
123 bgfx::destroy(mFbh);
124
125 // release the view id
126 auto& ctx = Context::instance();
127 if (ctx.isValidViewId(mViewId))
128 ctx.releaseViewId(mViewId);
129 }
130
131 Point2<uint> size() const { return mSize; }
132
133 bgfx::ViewId viewId() const { return mViewId; }
134
135 bgfx::FrameBufferHandle frameBuffer() const { return mFbh; }
136
137 void setDefaultClearColor(const Color& color)
138 {
139 mDefaultClearColor = color;
140 bgfx::setViewClear(
141 mViewId,
143 color.rgba());
144 }
145
153 void onInit() {}
154
161 void onResize(uint width, uint height)
162 {
163 mSize = {width, height};
164
165 // create window backbuffer
166 if (bgfx::isValid(mFbh))
167 bgfx::destroy(mFbh);
168
169 auto& ctx = Context::instance();
170 mFbh = ctx.createFramebufferAndInitView(
171 mWinId, mViewId, width, height, true, mDefaultClearColor.rgba());
172 // the canvas framebuffer is non valid for the default window
173 assert(ctx.isDefaultWindow(mWinId) == !bgfx::isValid(mFbh));
174 }
175
180 void onPaint()
181 {
182 bgfx::setViewFrameBuffer(mViewId, mFbh);
183 bgfx::touch(mViewId);
184
185 // ask the derived frame to draw all the drawer objects:
186 DerivedRenderApp::CNV::draw(derived());
187 DerivedRenderApp::CNV::postDraw(derived());
188
189 const bool newReadRequested =
190 (mReadRequest != std::nullopt && !mReadRequest->isSubmitted());
191
192 if (newReadRequested) {
193 // draw offscreen frame
194 offscreenFrame();
195 mCurrFrame = bgfx::frame();
196 // submit the calls for blitting the offscreen depth buffer
197 if (mReadRequest->submit()) {
198 // solicit new frame
199 derived()->update();
200 }
201 }
202 else {
203 mCurrFrame = bgfx::frame();
204 }
205
206 if (mReadRequest != std::nullopt) {
207 // read depth data if available
208 const bool done = mReadRequest->performRead(mCurrFrame);
209 if (done)
210 mReadRequest = std::nullopt;
211 // solicit new frame
212 derived()->update();
213 }
214
215 // this is required only when using Qt in macOS
216#if defined(__APPLE__)
217 bgfx::frame();
218#endif // __APPLE__
219 }
220
230 const Point2i& point,
231 CallbackReadBuffer callback = nullptr)
232 {
233 if (!Context::instance().supportsReadback() // feature unsupported
234 || mReadRequest != std::nullopt // read already requested
235 || point.x() < 0 || point.y() < 0 // point out of bounds
236 || point.x() >= mSize.x() || point.y() >= mSize.y()) {
237 return false;
238 }
239
240 mReadRequest.emplace(point, mSize, callback);
241 return true;
242 }
243
254 const std::string& filename,
255 uint width = 0,
256 uint height = 0)
257 {
258 if (!Context::instance().supportsReadback() // feature unsupported
259 || mReadRequest != std::nullopt) { // read already requested
260 return false;
261 }
262
263 // get size
264 auto size = mSize;
265 if (width != 0 && height != 0)
266 size = {width, height};
267
268 // color data callback
269 CallbackReadBuffer callback = [=](const ReadData& data) {
270 assert(
271 std::holds_alternative<ReadFramebufferRequest::ByteData>(data));
272 const auto& d = std::get<ReadFramebufferRequest::ByteData>(data);
273
274 // save rgb image data into file using stb depending on file
275 try {
276 vcl::saveImageData(filename, size.x(), size.y(), d.data());
277 }
278 catch (const std::exception& e) {
279 std::cerr << "Error saving image: " << e.what() << std::endl;
280 }
281 };
282
283 mReadRequest.emplace(size, callback, mDefaultClearColor);
284 return true;
285 }
286
287private:
288 // draw offscreen frame
289 void offscreenFrame()
290 {
291 assert(mReadRequest != std::nullopt && !mReadRequest->isSubmitted());
292
293 // render offscren
294 bgfx::setViewFrameBuffer(
295 mReadRequest->viewId(), mReadRequest->frameBuffer());
296 bgfx::touch(mReadRequest->viewId());
297
298 // render changing the view
299 auto tmpId = mViewId;
300 mViewId = mReadRequest->viewId();
301 DerivedRenderApp::CNV::drawContent(derived());
302 mViewId = tmpId;
303 }
304
305 auto* derived() { return static_cast<DerivedRenderApp*>(this); }
306
307 const auto* derived() const
308 {
309 return static_cast<const DerivedRenderApp*>(this);
310 }
311};
312
313} // namespace vcl
314
315#endif // VCL_BGFX_CANVAS_H
The Canvas class describes a canvas on which bgfx can draw.
Definition canvas.h:71
void onInit()
Automatically called by the DerivedRenderApp when the window initializes. Initialization is requires ...
Definition canvas.h:153
bool onReadDepth(const Point2i &point, CallbackReadBuffer callback=nullptr)
Automatically called by the DerivedRenderApp when a drawer asks to read the depth buffer at a specifi...
Definition canvas.h:229
void onPaint()
Automatically called by the DerivedRenderApp when the window asks to repaint.
Definition canvas.h:180
void onResize(uint width, uint height)
Automatically called by the DerivedRenderApp when the window is resized.
Definition canvas.h:161
bool onScreenshot(const std::string &filename, uint width=0, uint height=0)
Automatically called by the DerivedRenderApp when a drawer asks for a screenshot.
Definition canvas.h:253
The Color class represents a 32 bit color.
Definition color.h:48
static Context & instance(void *windowHandle=nullptr, void *displayHandle=nullptr)
Return the context instance.
Definition context.cpp:365
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:58
ScalarType & x()
Returns a reference to the x-component of the Point object.
Definition point.h:131
ScalarType & y()
Returns a reference to the y-component of the Point object.
Definition point.h:153
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
Definition render_app.h:31