mirror of
https://github.com/libretro/ppsspp.git
synced 2025-03-04 14:37:17 +00:00
UI: Track translate/scale/fade transform by screen.
This translates drawing, scissor, and touch to the transform.
This commit is contained in:
parent
92b0f00cd8
commit
a36ecb7065
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user