| 1 | /* |
| 2 | nanogui/glcanvas.cpp -- Canvas widget for rendering full-fledged |
| 3 | OpenGL content within its designated area. Very useful for |
| 4 | displaying and manipulating 3D objects or scenes. Subclass it and |
| 5 | overload `drawGL` for rendering. |
| 6 | |
| 7 | NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>. |
| 8 | The widget drawing code is based on the NanoVG demo application |
| 9 | by Mikko Mononen. |
| 10 | |
| 11 | All rights reserved. Use of this source code is governed by a |
| 12 | BSD-style license that can be found in the LICENSE.txt file. |
| 13 | */ |
| 14 | |
| 15 | #include <nanogui/window.h> |
| 16 | #include <nanogui/screen.h> |
| 17 | #include <nanogui/glcanvas.h> |
| 18 | #include <nanogui/theme.h> |
| 19 | #include <nanogui/opengl.h> |
| 20 | #include <nanogui/serializer/core.h> |
| 21 | |
| 22 | NAMESPACE_BEGIN(nanogui) |
| 23 | |
| 24 | GLCanvas::GLCanvas(Widget *parent) |
| 25 | : Widget(parent), mBackgroundColor(Vector4i(128, 128, 128, 255)), |
| 26 | mDrawBorder(true) { |
| 27 | mSize = Vector2i(250, 250); |
| 28 | } |
| 29 | |
| 30 | void GLCanvas::drawWidgetBorder(NVGcontext *ctx) const { |
| 31 | nvgBeginPath(ctx); |
| 32 | nvgStrokeWidth(ctx, 1.0f); |
| 33 | nvgRoundedRect(ctx, mPos.x() - 0.5f, mPos.y() - 0.5f, |
| 34 | mSize.x() + 1, mSize.y() + 1, mTheme->mWindowCornerRadius); |
| 35 | nvgStrokeColor(ctx, mTheme->mBorderLight); |
| 36 | nvgRoundedRect(ctx, mPos.x() - 1.0f, mPos.y() - 1.0f, |
| 37 | mSize.x() + 2, mSize.y() + 2, mTheme->mWindowCornerRadius); |
| 38 | nvgStrokeColor(ctx, mTheme->mBorderDark); |
| 39 | nvgStroke(ctx); |
| 40 | } |
| 41 | |
| 42 | void GLCanvas::draw(NVGcontext *ctx) { |
| 43 | Widget::draw(ctx); |
| 44 | nvgEndFrame(ctx); |
| 45 | |
| 46 | if (mDrawBorder) |
| 47 | drawWidgetBorder(ctx); |
| 48 | |
| 49 | const Screen* screen = this->screen(); |
| 50 | assert(screen); |
| 51 | |
| 52 | float pixelRatio = screen->pixelRatio(); |
| 53 | Vector2f screenSize = screen->size().cast<float>(); |
| 54 | Vector2i positionInScreen = absolutePosition(); |
| 55 | |
| 56 | Vector2i size = (mSize.cast<float>() * pixelRatio).cast<int>(), |
| 57 | imagePosition = (Vector2f(positionInScreen[0], |
| 58 | screenSize[1] - positionInScreen[1] - |
| 59 | (float) mSize[1]) * pixelRatio).cast<int>(); |
| 60 | |
| 61 | GLint storedViewport[4]; |
| 62 | glGetIntegerv(GL_VIEWPORT, storedViewport); |
| 63 | |
| 64 | glViewport(imagePosition[0], imagePosition[1], size[0] , size[1]); |
| 65 | |
| 66 | glEnable(GL_SCISSOR_TEST); |
| 67 | glScissor(imagePosition[0], imagePosition[1], size[0], size[1]); |
| 68 | glClearColor(mBackgroundColor[0], mBackgroundColor[1], |
| 69 | mBackgroundColor[2], mBackgroundColor[3]); |
| 70 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| 71 | |
| 72 | this->drawGL(); |
| 73 | |
| 74 | glDisable(GL_SCISSOR_TEST); |
| 75 | glViewport(storedViewport[0], storedViewport[1], |
| 76 | storedViewport[2], storedViewport[3]); |
| 77 | } |
| 78 | |
| 79 | void GLCanvas::save(Serializer &s) const { |
| 80 | Widget::save(s); |
| 81 | s.set("backgroundColor" , mBackgroundColor); |
| 82 | s.set("drawBorder" , mDrawBorder); |
| 83 | } |
| 84 | |
| 85 | bool GLCanvas::load(Serializer &s) { |
| 86 | if (!Widget::load(s)) return false; |
| 87 | if (!s.get("backgroundColor" , mBackgroundColor)) return false; |
| 88 | if (!s.get("drawBorder" , mDrawBorder)) return false; |
| 89 | return true; |
| 90 | } |
| 91 | |
| 92 | NAMESPACE_END(nanogui) |
| 93 | |