| 168 | |
| 169 | |
| 170 | void FramebufferWidget::render(math::Vec scale, math::Vec offsetF, math::Rect clipBox) { |
| 171 | // In case we fail drawing the framebuffer, don't try again the next frame, so reset `dirty` here. |
| 172 | dirty = false; |
| 173 | NVGcontext* vg = APP->window->vg; |
| 174 | NVGcontext* fbVg = APP->window->fbVg; |
| 175 | |
| 176 | internal->fbScale = scale; |
| 177 | internal->fbOffsetF = offsetF; |
| 178 | |
| 179 | math::Rect localBox; |
| 180 | if (children.empty()) { |
| 181 | localBox = box.zeroPos(); |
| 182 | } |
| 183 | else { |
| 184 | localBox = getVisibleChildrenBoundingBox(); |
| 185 | } |
| 186 | |
| 187 | // Intersect local box with viewport if viewportMargin is set |
| 188 | internal->fbClipBox = clipBox.grow(viewportMargin); |
| 189 | if (internal->fbClipBox.size.isFinite()) { |
| 190 | localBox = localBox.intersect(internal->fbClipBox); |
| 191 | } |
| 192 | |
| 193 | // DEBUG("rendering FramebufferWidget localBox (%f, %f; %f, %f) fbOffset (%f, %f) fbScale (%f, %f)", RECT_ARGS(localBox), VEC_ARGS(internal->fbOffsetF), VEC_ARGS(internal->fbScale)); |
| 194 | // Transform to world coordinates, then expand to nearest integer coordinates |
| 195 | math::Vec min = localBox.getTopLeft().mult(internal->fbScale).plus(internal->fbOffsetF).floor(); |
| 196 | math::Vec max = localBox.getBottomRight().mult(internal->fbScale).plus(internal->fbOffsetF).ceil(); |
| 197 | internal->fbBox = math::Rect::fromMinMax(min, max); |
| 198 | // DEBUG("%g %g %g %g", RECT_ARGS(internal->fbBox)); |
| 199 | |
| 200 | float pixelRatio = std::fmax(1.f, std::floor(APP->window->pixelRatio)); |
| 201 | math::Vec newFbSize = internal->fbBox.size.mult(pixelRatio).ceil(); |
| 202 | |
| 203 | // Create framebuffer if a new size is needed |
| 204 | if (!internal->fb || !newFbSize.equals(internal->fbSize)) { |
| 205 | // Delete old framebuffer |
| 206 | deleteFramebuffer(); |
| 207 | |
| 208 | // Create a framebuffer |
| 209 | if (newFbSize.isFinite() && !newFbSize.isZero()) { |
| 210 | // DEBUG("Creating framebuffer of size (%f, %f)", VEC_ARGS(newFbSize)); |
| 211 | internal->fb = nvgluCreateFramebuffer(vg, newFbSize.x, newFbSize.y, 0); |
| 212 | FramebufferWidget_totalPixels += newFbSize.area(); |
| 213 | } |
| 214 | |
| 215 | // DEBUG("Framebuffer total pixels: %.1f Mpx", FramebufferWidget_totalPixels / 1e6); |
| 216 | internal->fbSize = newFbSize; |
| 217 | } |
| 218 | if (!internal->fb) { |
| 219 | WARN("Framebuffer of size (%f, %f) could not be created for FramebufferWidget %p.", VEC_ARGS(internal->fbSize), this); |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | // DEBUG("Drawing to framebuffer of size (%f, %f)", VEC_ARGS(internal->fbSize)); |
| 224 | |
| 225 | // Render to framebuffer |
| 226 | if (oversample == 1.0) { |
| 227 | // If not oversampling, render directly to framebuffer. |
no test coverage detected