UI: Track translate/scale/fade transform by screen.

This translates drawing, scissor, and touch to the transform.
This commit is contained in:
Unknown W. Brackets 2017-03-19 14:28:24 -07:00
parent 92b0f00cd8
commit a36ecb7065
11 changed files with 136 additions and 29 deletions

View File

@ -772,8 +772,8 @@ void NativeRender(GraphicsContext *graphicsContext) {
ortho = ortho * g_display_rot_matrix;
}
ui_draw2d.SetDrawMatrix(ortho);
ui_draw2d_front.SetDrawMatrix(ortho);
ui_draw2d.PushDrawMatrix(ortho);
ui_draw2d_front.PushDrawMatrix(ortho);
screenManager->render();
if (screenManager->getUIContext()->Text()) {
@ -820,6 +820,9 @@ void NativeRender(GraphicsContext *graphicsContext) {
}
#endif
}
ui_draw2d.PopDrawMatrix();
ui_draw2d_front.PopDrawMatrix();
}
void HandleGlobalMessage(const std::string &msg, const std::string &value) {

View File

@ -24,9 +24,9 @@ uint32_t alphaMul(uint32_t color, float alphaMul) {
uint32_t rgb = color & 0xFFFFFF;
uint32_t alpha = color >> 24;
alpha *= alphaMul;
if (alpha < 0.0f) alpha = 0.0f;
if (alpha > 255.0f) alpha = 255.0f;
return ((int)(alpha)<<24) | (rgb & 0xFFFFFF);
if (alpha < 0) alpha = 0.0f;
if (alpha > 255) alpha = 255.0f;
return (alpha << 24) | (rgb & 0xFFFFFF);
}
uint32_t rgba(float r, float g, float b, float alpha) {

View File

@ -115,7 +115,7 @@ void DrawBuffer::V(float x, float y, float z, uint32_t color, float u, float v)
vert->x = x;
vert->y = y;
vert->z = z;
vert->rgba = color;
vert->rgba = alpha_ == 1.0f ? color : alphaMul(color, alpha_);
vert->u = u;
vert->v = v;
}

View File

@ -2,6 +2,8 @@
// "Immediate mode"-lookalike buffered drawing. Very fast way to draw 2D.
#include <vector>
#include "base/basictypes.h"
#include "base/colorutil.h"
#include "gfx/gl_lost_manager.h"
@ -147,10 +149,30 @@ public:
static void DoAlign(int flags, float *x, float *y, float *w, float *h);
void SetDrawMatrix(const Matrix4x4 &m) {
void PushDrawMatrix(const Matrix4x4 &m) {
drawMatrixStack_.push_back(drawMatrix_);
drawMatrix_ = m;
}
void PopDrawMatrix() {
drawMatrix_ = drawMatrixStack_.back();
drawMatrixStack_.pop_back();
}
Matrix4x4 GetDrawMatrix() {
return drawMatrix_;
}
void PushAlpha(float a) {
alphaStack_.push_back(alpha_);
alpha_ *= a;
}
void PopAlpha() {
alpha_ = alphaStack_.back();
alphaStack_.pop_back();
}
private:
struct Vertex {
float x, y, z;
@ -159,6 +181,10 @@ private:
};
Matrix4x4 drawMatrix_;
std::vector<Matrix4x4> drawMatrixStack_;
float alpha_ = 1.0f;
std::vector<float> alphaStack_;
Draw::DrawContext *draw_;
Draw::Buffer *vbuf_;

View File

@ -71,7 +71,8 @@ void ScreenManager::switchToNext() {
bool ScreenManager::touch(const TouchInput &touch) {
std::lock_guard<std::mutex> guard(inputLock_);
if (!stack_.empty()) {
return stack_.back().screen->touch(touch);
Screen *screen = stack_.back().screen;
return screen->touch(screen->transformTouch(touch));
} else {
return false;
}

View File

@ -19,6 +19,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/NativeApp.h"
#include "input/input_state.h"
namespace UI {
class View;
@ -74,6 +75,8 @@ public:
virtual bool isTransparent() const { return false; }
virtual bool isTopLevel() const { return false; }
virtual TouchInput transformTouch(const TouchInput &touch) { return touch; }
private:
ScreenManager *screenManager_;
DISALLOW_COPY_AND_ASSIGN(Screen);

View File

@ -70,10 +70,10 @@ void UIContext::End() {
Flush();
}
// TODO: Support transformed bounds using stencil
// TODO: Support transformed bounds using stencil instead.
void UIContext::PushScissor(const Bounds &bounds) {
Flush();
Bounds clipped = bounds;
Bounds clipped = TransformBounds(bounds);
if (scissorStack_.size())
clipped.Clip(scissorStack_.back());
scissorStack_.push_back(clipped);
@ -103,9 +103,7 @@ void UIContext::ActivateTopScissor() {
int w = ceilf(scale * bounds.w);
int h = ceilf(scale * bounds.h);
draw_->SetScissorRect(x, y, w, h);
}
else {
bounds = bounds_;
} else {
// Avoid rounding errors
draw_->SetScissorRect(0, 0, pixel_xres, pixel_yres);
}
@ -203,3 +201,44 @@ void UIContext::FillRect(const UI::Drawable &drawable, const Bounds &bounds) {
break;
}
}
void UIContext::PushTransform(const UITransform &transform) {
Flush();
Matrix4x4 m = Draw()->GetDrawMatrix();
const Vec3 &t = transform.translate;
Vec3 scaledTranslate = Vec3(
t.x * m.xx + t.y * m.xy + t.z * m.xz + m.xw,
t.x * m.yx + t.y * m.yy + t.z * m.yz + m.yw,
t.x * m.zx + t.y * m.zy + t.z * m.zz + m.zw);
m.translateAndScale(scaledTranslate, transform.scale);
Draw()->PushDrawMatrix(m);
Draw()->PushAlpha(transform.alpha);
transformStack_.push_back(transform);
}
void UIContext::PopTransform() {
Flush();
transformStack_.pop_back();
Draw()->PopDrawMatrix();
Draw()->PopAlpha();
}
Bounds UIContext::TransformBounds(const Bounds &bounds) {
if (!transformStack_.empty()) {
const UITransform t = transformStack_.back();
Bounds translated = bounds.Offset(t.translate.x, t.translate.y);
// Scale around the center as the origin.
float scaledX = (translated.x - dp_xres * 0.5f) * t.scale.x + dp_xres * 0.5f;
float scaledY = (translated.y - dp_yres * 0.5f) * t.scale.y + dp_yres * 0.5f;
return Bounds(scaledX, scaledY, translated.w * t.scale.x, translated.h * t.scale.y);
}
return bounds;
}

View File

@ -4,6 +4,7 @@
#include "base/basictypes.h"
#include "math/geom2d.h"
#include "math/lin/vec3.h"
#include "gfx/texture_atlas.h"
// Everything you need to draw a UI collected into a single unit that can be passed around.
@ -31,6 +32,13 @@ namespace UI {
class DrawBuffer;
struct UITransform {
// TODO: Or just use a matrix?
Vec3 translate;
Vec3 scale;
float alpha;
};
class UIContext {
public:
UIContext();
@ -78,6 +86,10 @@ public:
const Bounds &GetBounds() const { return bounds_; }
Draw::DrawContext *GetDrawContext() { return draw_; }
void PushTransform(const UITransform &transform);
void PopTransform();
Bounds TransformBounds(const Bounds &bounds);
private:
Draw::DrawContext *draw_;
Bounds bounds_;
@ -96,4 +108,5 @@ private:
DrawBuffer *uidrawbufferTop_;
std::vector<Bounds> scissorStack_;
std::vector<UITransform> transformStack_;
};

View File

@ -11,7 +11,9 @@
static const bool ClickDebug = false;
UIScreen::UIScreen()
: Screen(), root_(0), recreateViews_(true), hatDown_(0) {
: Screen(), root_(nullptr), recreateViews_(true), hatDown_(0) {
translation_ = Vec3(0.0f);
scale_ = Vec3(1.0f);
}
UIScreen::~UIScreen() {
@ -88,16 +90,33 @@ void UIScreen::render() {
DoRecreateViews();
if (root_) {
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_);
UIContext *uiContext = screenManager()->getUIContext();
UI::LayoutViewHierarchy(*uiContext, root_);
screenManager()->getUIContext()->Begin();
DrawBackground(*screenManager()->getUIContext());
root_->Draw(*screenManager()->getUIContext());
screenManager()->getUIContext()->End();
screenManager()->getUIContext()->Flush();
uiContext->PushTransform({translation_, scale_, alpha_});
uiContext->Begin();
DrawBackground(*uiContext);
root_->Draw(*uiContext);
uiContext->End();
uiContext->Flush();
uiContext->PopTransform();
}
}
TouchInput UIScreen::transformTouch(const TouchInput &touch) {
TouchInput updated = touch;
float x = touch.x - translation_.x;
float y = touch.y - translation_.y;
// Scale around the center as the origin.
updated.x = (x - dp_xres * 0.5f) / scale_.x + dp_xres * 0.5f;
updated.y = (y - dp_yres * 0.5f) / scale_.y + dp_yres * 0.5f;
return updated;
}
bool UIScreen::touch(const TouchInput &touch) {
if (root_) {
if (ClickDebug && (touch.flags & TOUCH_DOWN)) {

View File

@ -24,6 +24,8 @@ public:
virtual bool key(const KeyInput &touch) override;
virtual bool axis(const AxisInput &touch) override;
virtual TouchInput transformTouch(const TouchInput &touch) override;
// Some useful default event handlers
UI::EventReturn OnOK(UI::EventParams &e);
UI::EventReturn OnCancel(UI::EventParams &e);
@ -36,6 +38,9 @@ protected:
virtual void RecreateViews() override { recreateViews_ = true; }
UI::ViewGroup *root_;
Vec3 translation_;
Vec3 scale_;
float alpha_ = 1.0f;
private:
void DoRecreateViews();

View File

@ -130,12 +130,11 @@ void ViewGroup::Draw(UIContext &dc) {
}
dc.FillRect(bg_, bounds_);
for (auto iter = views_.begin(); iter != views_.end(); ++iter) {
// TODO: If there is a transformation active, transform input coordinates accordingly.
if ((*iter)->GetVisibility() == V_VISIBLE) {
for (View *view : views_) {
if (view->GetVisibility() == V_VISIBLE) {
// Check if bounds are in current scissor rectangle.
if (dc.GetScissorBounds().Intersects((*iter)->GetBounds()))
(*iter)->Draw(dc);
if (dc.GetScissorBounds().Intersects(dc.TransformBounds(view->GetBounds())))
view->Draw(dc);
}
}
if (clip_) {
@ -144,10 +143,9 @@ void ViewGroup::Draw(UIContext &dc) {
}
void ViewGroup::Update() {
for (auto iter = views_.begin(); iter != views_.end(); ++iter) {
// TODO: If there is a transformation active, transform input coordinates accordingly.
if ((*iter)->GetVisibility() != V_GONE)
(*iter)->Update();
for (View *view : views_) {
if (view->GetVisibility() != V_GONE)
view->Update();
}
}