From c0a72427edd8bf46259822fc5ee51b99b6dec93d Mon Sep 17 00:00:00 2001 From: skyjake Date: Fri, 26 Apr 2013 07:39:15 +0300 Subject: [PATCH] libgui|GLState|Canvas: Viewport is now part of the GL state Notable change: the topmost GLState on the stack is now applied automatically when a Canvas is drawn. The future implication is that the client's initial GL state for a frame needs to be on the GL state stack. --- doomsday/libgui/include/de/gui/glstate.h | 6 ++ doomsday/libgui/src/canvas.cpp | 4 + doomsday/libgui/src/displaymode_windows.cpp | 4 +- doomsday/libgui/src/glstate.cpp | 100 +++++++++++++++----- doomsday/libgui/src/gltarget.cpp | 6 +- 5 files changed, 89 insertions(+), 31 deletions(-) diff --git a/doomsday/libgui/include/de/gui/glstate.h b/doomsday/libgui/include/de/gui/glstate.h index 493ff19f70..1de6745100 100644 --- a/doomsday/libgui/include/de/gui/glstate.h +++ b/doomsday/libgui/include/de/gui/glstate.h @@ -24,6 +24,7 @@ #define LIBGUI_GLSTATE_H #include +#include #include #include "libgui.h" @@ -82,6 +83,9 @@ namespace gl * drawing. GLState::apply() can be called for any GLState instance to use it * as the current GL state. * + * @note The default viewport is (0,0)→(0,0). The viewport has to be set + * when the desired size is known (for instance when a Canvas is resized). + * * @ingroup gl */ class LIBGUI_PUBLIC GLState @@ -104,6 +108,7 @@ class LIBGUI_PUBLIC GLState void setBlendOp(gl::BlendOp op); void setTarget(GLTarget &target); void setDefaultTarget(); + void setViewport(Rectangleui const &viewportRect); gl::Cull cull() const; bool depthTest() const; @@ -115,6 +120,7 @@ class LIBGUI_PUBLIC GLState gl::BlendFunc blendFunc() const; gl::BlendOp blendOp() const; GLTarget &target() const; + Rectangleui viewport() const; /** * Updates the OpenGL state to match this GLState. Until this is called no diff --git a/doomsday/libgui/src/canvas.cpp b/doomsday/libgui/src/canvas.cpp index 4c6627f8d7..25c00d3ea9 100644 --- a/doomsday/libgui/src/canvas.cpp +++ b/doomsday/libgui/src/canvas.cpp @@ -19,6 +19,7 @@ #include "de/Canvas" #include "de/CanvasWindow" +#include "de/GLState" #include "de/gui/opengl.h" #include @@ -298,6 +299,9 @@ void Canvas::notifyReady() void Canvas::paintGL() { + // Make sure any changes to the state stack become effective. + GLState::top().apply(); + DENG2_FOR_AUDIENCE(GLDraw, i) i->canvasGLDraw(*this); } diff --git a/doomsday/libgui/src/displaymode_windows.cpp b/doomsday/libgui/src/displaymode_windows.cpp index 3af64f93be..34e867dbd3 100644 --- a/doomsday/libgui/src/displaymode_windows.cpp +++ b/doomsday/libgui/src/displaymode_windows.cpp @@ -116,7 +116,7 @@ int DisplayMode_Native_Change(const DisplayMode* mode, int shouldCapture) void DisplayMode_Native_SetColorTransfer(DisplayColorTransfer const *colors) { - HWND hWnd = (HWND) de::PersistentCanvasWindow::main().nativeHandle(); + HWND hWnd = (HWND) de::CanvasWindow::main().nativeHandle(); DENG2_ASSERT(hWnd != 0); HDC hDC = GetDC(hWnd); @@ -129,7 +129,7 @@ void DisplayMode_Native_SetColorTransfer(DisplayColorTransfer const *colors) void DisplayMode_Native_GetColorTransfer(DisplayColorTransfer *colors) { - HWND hWnd = (HWND) de::PersistentCanvasWindow::main().nativeHandle(); + HWND hWnd = (HWND) de::CanvasWindow::main().nativeHandle(); DENG2_ASSERT(hWnd != 0); HDC hDC = GetDC(hWnd); diff --git a/doomsday/libgui/src/glstate.cpp b/doomsday/libgui/src/glstate.cpp index 273668b8c4..593a247103 100644 --- a/doomsday/libgui/src/glstate.cpp +++ b/doomsday/libgui/src/glstate.cpp @@ -38,6 +38,10 @@ namespace internal BlendFuncSrc, BlendFuncDest, BlendOp, + ViewportX, + ViewportY, + ViewportWidth, + ViewportHeight, MAX_PROPERTIES }; @@ -66,20 +70,26 @@ DENG2_PIMPL(GLState) Instance(Public *i) : Base(i), target(0) { static BitField::Spec const propSpecs[MAX_PROPERTIES] = { - { CullMode, 2 }, - { DepthTest, 1 }, - { DepthFunc, 3 }, - { DepthWrite, 1 }, - { Blend, 1 }, - { BlendFuncSrc, 4 }, - { BlendFuncDest, 4 }, - { BlendOp, 2 } + { CullMode, 2 }, + { DepthTest, 1 }, + { DepthFunc, 3 }, + { DepthWrite, 1 }, + { Blend, 1 }, + { BlendFuncSrc, 4 }, + { BlendFuncDest, 4 }, + { BlendOp, 2 }, + { ViewportX, 12 }, // 4096 max + { ViewportY, 12 }, // 4096 max + { ViewportWidth, 12 }, // 4096 max + { ViewportHeight, 12 } // 4096 max }; props.addElements(propSpecs, MAX_PROPERTIES); } Instance(Public *i, Instance const &other) - : Base(i), props(other.props), target(other.target) + : Base(i), + props(other.props), + target(other.target) {} static GLenum glComp(gl::Comparison comp) @@ -182,10 +192,37 @@ DENG2_PIMPL(GLState) } break; + case ViewportX: + case ViewportY: + case ViewportWidth: + case ViewportHeight: + { + Rectangleui vp = self.viewport(); + glViewport(vp.left(), vp.top(), vp.width(), vp.height()); + break; + } + default: break; } } + + void removeRedundancies(BitField::Ids &changed) + { + if(changed.contains(BlendFuncSrc) && changed.contains(BlendFuncDest)) + { + changed.remove(BlendFuncDest); + } + + if(changed.contains(ViewportX) || changed.contains(ViewportY) || + changed.contains(ViewportWidth) || changed.contains(ViewportHeight)) + { + changed.insert(ViewportX); + changed.remove(ViewportY); + changed.remove(ViewportWidth); + changed.remove(ViewportHeight); + } + } }; GLState::GLState() : d(new Instance(this)) @@ -256,6 +293,14 @@ void GLState::setDefaultTarget() d->target = 0; } +void GLState::setViewport(Rectangleui const &viewportRect) +{ + d->props.set(ViewportX, viewportRect.left()); + d->props.set(ViewportY, viewportRect.top()); + d->props.set(ViewportWidth, viewportRect.width()); + d->props.set(ViewportHeight, viewportRect.height()); +} + gl::Cull GLState::cull() const { return d->props.valueAs(CullMode); @@ -307,13 +352,29 @@ GLTarget &GLState::target() const { return *d->target; } - return PersistentCanvasWindow::main().canvas().renderTarget(); + return CanvasWindow::main().canvas().renderTarget(); +} + +Rectangleui GLState::viewport() const +{ + return Rectangleui(d->props[ViewportX], + d->props[ViewportY], + d->props[ViewportWidth], + d->props[ViewportHeight]); } void GLState::apply() const { - BitField::Ids changed; + // Update the render target. + if(currentTarget != d->target) + { + if(currentTarget) currentTarget->glRelease(); + currentTarget = d->target; + if(currentTarget) currentTarget->glBind(); + } + // Determine which properties have changed. + BitField::Ids changed; if(!currentProps.size()) { // Apply everything. @@ -327,27 +388,14 @@ void GLState::apply() const if(!changed.isEmpty()) { - currentProps = d->props; - - // The blend func only needs to be set once. - if(changed.contains(BlendFuncSrc) && changed.contains(BlendFuncDest)) - { - changed.remove(BlendFuncDest); - } + d->removeRedundancies(changed); // Apply the changed properties. foreach(BitField::Id id, changed) { d->glApply(Property(id)); } - } - - // Update the render target. - if(currentTarget != d->target) - { - if(currentTarget) currentTarget->glRelease(); - currentTarget = d->target; - if(currentTarget) currentTarget->glBind(); + currentProps = d->props; } } diff --git a/doomsday/libgui/src/gltarget.cpp b/doomsday/libgui/src/gltarget.cpp index 1856a94fe1..99875c1a2c 100644 --- a/doomsday/libgui/src/gltarget.cpp +++ b/doomsday/libgui/src/gltarget.cpp @@ -22,7 +22,7 @@ #include "de/GLTarget" #include "de/GLTexture" #include "de/GLState" -#include "de/PersistentCanvasWindow" +#include "de/CanvasWindow" #include namespace de { @@ -212,7 +212,7 @@ QImage GLTarget::toImage() const { if(!d->fbo) { - return PersistentCanvasWindow::main().canvas().grabImage(); + return CanvasWindow::main().canvas().grabImage(); } else if(d->flags & Color) { @@ -265,7 +265,7 @@ GLTarget::Size GLTarget::size() const { return d->size; } - return PersistentCanvasWindow::main().canvas().size(); + return CanvasWindow::main().canvas().size(); } } // namespace de