diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index cc359c533..3ce033f27 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -41,6 +41,7 @@ add_library( # Sets the name of the library. src/main/cpp/VRLayer.cpp src/main/cpp/VRLayerNode.cpp src/main/cpp/Widget.cpp + src/main/cpp/WidgetBorder.cpp src/main/cpp/WidgetMover.cpp src/main/cpp/WidgetPlacement.cpp src/main/cpp/WidgetResizer.cpp diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index fa43cf0da..d2d6022c3 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -256,7 +256,16 @@ protected void onCreate(Bundle savedInstanceState) { protected void initializeWidgets() { mWindows = new Windows(this); - mWindows.setDelegate(this::attachToWindow); + mWindows.setDelegate(new Windows.Delegate() { + @Override + public void onFocusedWindowChanged(@NonNull WindowWidget aFocusedWindow, @Nullable WindowWidget aPrevFocusedWindow) { + attachToWindow(aFocusedWindow, aPrevFocusedWindow); + } + @Override + public void onWindowBorderChanged(@NonNull WindowWidget aChangeWindow) { + mKeyboard.proxifyLayerIfNeeded(mWindows.getCurrentWindows()); + } + }); // Create Browser navigation widget mNavigationBar = new NavigationBarWidget(this); @@ -648,20 +657,6 @@ void handleMotionEvent(final int aHandle, final int aDevice, final boolean aPres if (!isWidgetInputEnabled(widget)) { widget = null; // Fallback to mRootWidget in order to allow world clicks to dismiss UI. } - if (widget instanceof WindowWidget) { - WindowWidget window = (WindowWidget) widget; - boolean focused = mWindows.getFocusedWindow() == window; - if (!focused && aPressed) { - // Focus the window when pressed - mWindows.focusWindow(window); - // Discard first click. - return; - } else if (!focused) { - // Do not send hover events to not focused windows. - widget = null; - } - } - float scale = widget != null ? widget.getPlacement().textureScale : 1.0f; final float x = aX / scale; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java index e3063501e..c25c9df6b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java @@ -359,6 +359,23 @@ public void dismiss() { hideOverlays(); } + public void proxifyLayerIfNeeded(ArrayList aWindows) { + if (!SettingsStore.getInstance(getContext()).getLayersEnabled()) { + return; + } + boolean proxify = false; + for (WindowWidget window: aWindows) { + if (window.getPlacement().borderColor != 0) { + proxify = true; + break; + } + } + if (mWidgetPlacement.proxifyLayer != proxify) { + mWidgetPlacement.proxifyLayer = proxify; + mWidgetManager.updateWidget(this); + } + } + private void hideOverlays() { mPopupKeyboardView.setVisibility(View.GONE); mPopupKeyboardLayer.setVisibility(View.GONE); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java index ed46e5ba4..43e3773dd 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java @@ -43,6 +43,9 @@ void resize(int aWidth, int aHeight) { mSurfaceTexture.setDefaultBufferSize(aWidth, aHeight); } } + public boolean isLayer() { + return mSurface != null && mSurfaceTexture == null; + } void release() { if(mSurface != null){ diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java index cd1acb14d..49bec5d87 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java @@ -35,6 +35,7 @@ public interface Delegate { } protected UISurfaceTextureRenderer mRenderer; + protected UISurfaceTextureRenderer mProxyRenderer; protected SurfaceTexture mTexture; protected float mWorldWidth; protected int mHandle; @@ -102,6 +103,15 @@ public void setSurfaceTexture(SurfaceTexture aTexture, final int aWidth, final i Log.d(LOGTAG, "Texture already set"); return; } + if (mRenderer != null && mRenderer.isLayer()) { + // Widget is using a layer write-only surface but we also want a proxy. + if (mProxyRenderer != null) { + mProxyRenderer.release(); + } + mProxyRenderer = new UISurfaceTextureRenderer(aTexture, aWidth, aHeight); + postInvalidate(); + return; + } mTexture = aTexture; if (mRenderer != null) { mRenderer.release(); @@ -211,7 +221,19 @@ public void draw(Canvas aCanvas) { super.draw(aCanvas); return; } - Canvas textureCanvas = mRenderer.drawBegin(); + draw(aCanvas, mRenderer); + if (mProxyRenderer != null && mWidgetPlacement.proxifyLayer) { + draw(aCanvas, mProxyRenderer); + } + + if (mFirstDrawCallback != null) { + mFirstDrawCallback.run(); + mFirstDrawCallback = null; + } + } + + private void draw(Canvas aCanvas, UISurfaceTextureRenderer aRenderer) { + Canvas textureCanvas = aRenderer.drawBegin(); if(textureCanvas != null) { // set the proper scale float xScale = textureCanvas.getWidth() / (float)aCanvas.getWidth(); @@ -219,11 +241,7 @@ public void draw(Canvas aCanvas) { // draw the view to SurfaceTexture super.draw(textureCanvas); } - mRenderer.drawEnd(); - if (mFirstDrawCallback != null) { - mFirstDrawCallback.run(); - mFirstDrawCallback = null; - } + aRenderer.drawEnd(); } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java index c42ed9202..221c6a86f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetPlacement.java @@ -46,9 +46,11 @@ public WidgetPlacement(Context aContext) { public boolean showPointer = true; public boolean firstDraw = false; public boolean layer = true; + public boolean proxifyLayer = false; public float textureScale = 0.7f; // Widget will be curved if enabled. public boolean cylinder = true; + public int borderColor = 0; /* * Flat surface placements are automatically mapped to curved coordinates. * If a radius is set it's used for the automatic mapping of the yaw & angle when the diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index ba7614188..74235df66 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -45,6 +45,8 @@ import org.mozilla.vrbrowser.ui.widgets.prompts.ConfirmPromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.PromptWidget; import org.mozilla.vrbrowser.ui.widgets.prompts.TextPromptWidget; +import org.mozilla.vrbrowser.utils.InternalPages; +import org.mozilla.vrbrowser.utils.ViewUtils; import java.util.ArrayList; @@ -90,7 +92,15 @@ public class WindowWidget extends UIWidget implements SessionChangeListener, private Windows.WindowPlacement mWindowPlacement = Windows.WindowPlacement.FRONT; private float mMaxWindowScale = 3; private boolean mIsRestored = false; + private WindowDelegate mWindowDelegate; boolean mActive = false; + boolean mHovered = false; + boolean mClickedAfterFocus = false; + + public interface WindowDelegate { + void onFocusRequest(@NonNull WindowWidget aWindow); + void onBorderChanged(@NonNull WindowWidget aWindow); + } public WindowWidget(Context aContext, int windowId, boolean privateMode) { super(aContext); @@ -387,6 +397,7 @@ public void setActiveWindow(boolean active) { } TelemetryWrapper.activePlacementEvent(mWindowPlacement.getValue(), mActive); + updateBorder(); } public SessionStack getSessionStack() { @@ -488,6 +499,26 @@ public WidgetPlacement getPlacement() { @Override public void handleTouchEvent(MotionEvent aEvent) { mLastMouseClickPos = new Point((int)aEvent.getX(), (int)aEvent.getY()); + if (aEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (!mActive) { + mClickedAfterFocus = true; + updateBorder(); + if (mWindowDelegate != null) { + // Focus this window + mWindowDelegate.onFocusRequest(this); + } + // Return to discard first click after focus + return; + } + } else if (aEvent.getAction() == MotionEvent.ACTION_UP || aEvent.getAction() == MotionEvent.ACTION_CANCEL) { + mClickedAfterFocus = false; + updateBorder(); + } + + if (!mActive) { + // Do not send touch events to not focused windows. + return; + } if (mView != null) { super.handleTouchEvent(aEvent); @@ -507,6 +538,19 @@ public void handleTouchEvent(MotionEvent aEvent) { @Override public void handleHoverEvent(MotionEvent aEvent) { + if (aEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) { + mHovered = true; + updateBorder(); + } else if (aEvent.getAction() == MotionEvent.ACTION_HOVER_EXIT) { + mHovered = false; + updateBorder(); + } + + if (!mActive) { + // Do not send touch events to not focused windows. + return; + } + if (mView != null) { super.handleHoverEvent(aEvent); @@ -520,6 +564,26 @@ public void handleHoverEvent(MotionEvent aEvent) { } } + protected void updateBorder() { + int color = 0; + if (!mActive && !mClickedAfterFocus && mHovered) { + color = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_border_hover)); + } else if (mClickedAfterFocus) { + color = ViewUtils.ARGBtoRGBA(getContext().getColor(R.color.window_border_click)); + } + if (mWidgetPlacement.borderColor != color) { + mWidgetPlacement.borderColor = color; + mWidgetManager.updateWidget(this); + if (mWindowDelegate != null) { + mWindowDelegate.onBorderChanged(this); + } + } + } + + public void setWindowDelegate(WindowDelegate aDelegate) { + mWindowDelegate = aDelegate; + } + @Override public void handleResizeEvent(float aWorldWidth, float aWorldHeight) { int width = getWindowWidth(aWorldWidth); @@ -975,5 +1039,4 @@ public GeckoResult onLoadRequest(@NonNull GeckoSession session, @No return GeckoResult.ALLOW; } - } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java index f9393cf83..e91f90654 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java @@ -25,7 +25,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; -public class Windows implements TrayListener, TopBarWidget.Delegate, GeckoSession.ContentDelegate { +public class Windows implements TrayListener, TopBarWidget.Delegate, GeckoSession.ContentDelegate, WindowWidget.WindowDelegate { private static final String LOGTAG = Windows.class.getSimpleName(); @@ -86,6 +86,7 @@ public enum WindowPlacement{ public interface Delegate { void onFocusedWindowChanged(@NonNull WindowWidget aFocusedWindow, @Nullable WindowWidget aPrevFocusedWindow); + void onWindowBorderChanged(@NonNull WindowWidget aChangeWindow); } public Windows(Context aContext) { @@ -347,6 +348,7 @@ public void onPause() { } public void onDestroy() { + mDelegate = null; for (WindowWidget window: mRegularWindows) { window.close(); } @@ -436,7 +438,7 @@ private void showMaxWindowsMessage() { mFocusedWindow.showMaxWindowsDialog(MAX_WINDOWS); } - private ArrayList getCurrentWindows() { + public ArrayList getCurrentWindows() { return mPrivateMode ? mPrivateWindows : mRegularWindows; } @@ -510,6 +512,7 @@ private void removeWindow(@NonNull WindowWidget aWindow) { mPrivateWindows.remove(aWindow); aWindow.getTopBar().setVisible(false); aWindow.getTopBar().setDelegate((TopBarWidget.Delegate) null); + aWindow.setWindowDelegate(null); aWindow.getSessionStack().removeContentListener(this); aWindow.close(); updateMaxWindowScales(); @@ -664,6 +667,7 @@ private void updateTopBars() { private WindowWidget createWindow() { int newWindowId = sIndex++; WindowWidget window = new WindowWidget(mContext, newWindowId, mPrivateMode); + window.setWindowDelegate(this); getCurrentWindows().add(window); window.getTopBar().setDelegate(this); window.getSessionStack().addContentListener(this); @@ -782,4 +786,18 @@ private WindowWidget getWindowWithSession(GeckoSession aSession) { return null; } + // WindowWidget.Delegate + @Override + public void onFocusRequest(WindowWidget aWindow) { + focusWindow(aWindow); + } + + @Override + public void onBorderChanged(WindowWidget aWindow) { + if (mDelegate != null) { + mDelegate.onWindowBorderChanged(aWindow); + } + + } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java index 7627b19db..62b681221 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/ViewUtils.java @@ -1,5 +1,6 @@ package org.mozilla.vrbrowser.utils; +import android.graphics.Color; import android.os.Build; import android.text.Html; import android.text.SpannableStringBuilder; @@ -7,6 +8,7 @@ import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; @@ -117,4 +119,7 @@ public static boolean isInsideView(@NotNull View view, int rx, int ry) { return true; } + public static int ARGBtoRGBA(int c) { + return (c & 0x00FFFFFF) << 8 | (c & 0xFF000000) >>> 24; + } } diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index 0507230ed..8ea32cd79 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -910,6 +910,8 @@ BrowserWorld::UpdateWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement widget->SetWorldWidth(newWorldWidth); } + widget->SetBorderColor(vrb::Color(aPlacement->borderColor)); + widget->SetProxifyLayer(aPlacement->proxifyLayer); LayoutWidget(aHandle); } diff --git a/app/src/main/cpp/Cylinder.cpp b/app/src/main/cpp/Cylinder.cpp index 2a7b81077..134750f8d 100644 --- a/app/src/main/cpp/Cylinder.cpp +++ b/app/src/main/cpp/Cylinder.cpp @@ -217,6 +217,18 @@ Cylinder::Create(vrb::CreationContextPtr aContext, const float aRadius, const fl return result; } +CylinderPtr +Cylinder::Create(vrb::CreationContextPtr aContext, const Cylinder& aCylinder) { + CylinderPtr result = std::make_shared >(aContext); + result->m.radius = aCylinder.m.radius; + result->m.height = aCylinder.m.height; + result->m.solidColor = aCylinder.m.solidColor; + result->m.border = aCylinder.m.border;; + result->m.borderColor = aCylinder.m.borderColor; + result->m.Initialize(); + return result; +} + CylinderPtr Cylinder::Create(vrb::CreationContextPtr aContext, const VRLayerCylinderPtr& aLayer) { CylinderPtr result = std::make_shared >(aContext); diff --git a/app/src/main/cpp/Cylinder.h b/app/src/main/cpp/Cylinder.h index d378a4108..d390c0228 100644 --- a/app/src/main/cpp/Cylinder.h +++ b/app/src/main/cpp/Cylinder.h @@ -29,6 +29,7 @@ class Cylinder { static CylinderPtr Create(vrb::CreationContextPtr aContext, const float aRadius, const float aHeight, const VRLayerCylinderPtr& aLayer = nullptr); static CylinderPtr Create(vrb::CreationContextPtr aContext, const float aRadius, const float aHeight, const vrb::Color& aSolidColor, const float kBorder, const vrb::Color& aBorderColor); static CylinderPtr Create(vrb::CreationContextPtr aContext, const VRLayerCylinderPtr& aLayer = nullptr); + static CylinderPtr Create(vrb::CreationContextPtr aContext, const Cylinder& aCylinder); static float kWorldDensityRatio; void GetTextureSize(int32_t& aWidth, int32_t& aHeight) const; void SetTextureSize(int32_t aWidth, int32_t aHeight); diff --git a/app/src/main/cpp/Device.h b/app/src/main/cpp/Device.h index 76dcee7ee..71911c02c 100644 --- a/app/src/main/cpp/Device.h +++ b/app/src/main/cpp/Device.h @@ -6,6 +6,8 @@ #ifndef VRBROWSER_DEVICE_H #define VRBROWSER_DEVICE_H +#include + namespace crow { namespace device { typedef uint32_t CapabilityFlags; diff --git a/app/src/main/cpp/Quad.cpp b/app/src/main/cpp/Quad.cpp index 896c23037..a6eb09e6b 100644 --- a/app/src/main/cpp/Quad.cpp +++ b/app/src/main/cpp/Quad.cpp @@ -166,6 +166,15 @@ Quad::Create(vrb::CreationContextPtr aContext, const float aWorldWidth, const fl return result; } +QuadPtr +Quad::Create(vrb::CreationContextPtr aContext, const Quad& aQuad) { + QuadPtr result = std::make_shared >(aContext); + result->m.worldMin = aQuad.m.worldMin; + result->m.worldMax = aQuad.m.worldMax; + result->m.Initialize(); + return result; +} + vrb::GeometryPtr Quad::CreateGeometry(vrb::CreationContextPtr aContext, const vrb::Vector &aMin, const vrb::Vector &aMax) { device::EyeRect rect(0.0f, 0.0f, 1.0f, 1.0f); diff --git a/app/src/main/cpp/Quad.h b/app/src/main/cpp/Quad.h index 56c158dbc..a8cebf5b1 100644 --- a/app/src/main/cpp/Quad.h +++ b/app/src/main/cpp/Quad.h @@ -33,6 +33,7 @@ class Quad { }; static QuadPtr Create(vrb::CreationContextPtr aContext, const vrb::Vector& aMin, const vrb::Vector& aMax, const VRLayerQuadPtr& aLayer = nullptr); static QuadPtr Create(vrb::CreationContextPtr aContext, const float aWorldWidth, const float aWorldHeight, const VRLayerQuadPtr& aLayer = nullptr); + static QuadPtr Create(vrb::CreationContextPtr aContext, const Quad& aQuad); static vrb::GeometryPtr CreateGeometry(vrb::CreationContextPtr aContext, const vrb::Vector& aMin, const vrb::Vector& aMax); static vrb::GeometryPtr CreateGeometry(vrb::CreationContextPtr aContext, const float aWorldWidth, const float aWorldHeight); static vrb::GeometryPtr CreateGeometry(vrb::CreationContextPtr aContext, const vrb::Vector& aMin, const vrb::Vector& aMax, const device::EyeRect& aRect); diff --git a/app/src/main/cpp/Widget.cpp b/app/src/main/cpp/Widget.cpp index 1f537c8bb..c3b1e43b2 100644 --- a/app/src/main/cpp/Widget.cpp +++ b/app/src/main/cpp/Widget.cpp @@ -10,11 +10,15 @@ #include "VRBrowser.h" #include "WidgetPlacement.h" #include "WidgetResizer.h" +#include "WidgetBorder.h" #include "vrb/ConcreteClass.h" #include "vrb/Color.h" #include "vrb/RenderContext.h" +#include "vrb/CreationContext.h" +#include "vrb/TextureGL.h" #include "vrb/Matrix.h" +#include "vrb/GLError.h" #include "vrb/Geometry.h" #include "vrb/RenderState.h" #include "vrb/SurfaceTextureFactory.h" @@ -26,6 +30,14 @@ namespace crow { +static const float kFrameSize = 0.02f; +#if defined(OCULUSVR) +static const float kBorder = 0.0f; +#else +static const float kBorder = kFrameSize * 0.15f; +#endif + + struct Widget::State { vrb::RenderContextWeak context; std::string name; @@ -43,6 +55,9 @@ struct Widget::State { WidgetResizerPtr resizer; bool resizing; bool toggleState; + vrb::TogglePtr bordersContainer; + std::vector borders; + vrb::TogglePtr layerProxy; State() : handle(0) @@ -169,6 +184,14 @@ struct Widget::State { resizer = nullptr; } } + + void RemoveBorder() { + if (bordersContainer) { + bordersContainer->RemoveFromParents(); + bordersContainer = nullptr; + } + borders.clear(); + } }; WidgetPtr @@ -185,7 +208,7 @@ Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const float a const int32_t aTextureWidth, const int32_t aTextureHeight, const CylinderPtr& aCylinder) { WidgetPtr result = std::make_shared >(aContext); result->m.min = vrb::Vector(-aWorldWidth * 0.5f, -aWorldHeight * 0.5f, 0.0f); - result->m.max = vrb::Vector(aWorldWidth *0.5f, aWorldHeight * 0.5f, 0.0f); + result->m.max = vrb::Vector(aWorldWidth * 0.5f, aWorldHeight * 0.5f, 0.0f); result->m.Initialize(aHandle, aTextureWidth, aTextureHeight, nullptr, aCylinder); return result; } @@ -247,6 +270,7 @@ Widget::SetWorldWidth(float aWorldWidth) const { const float aspect = (float)width / (float) height; const float worldHeight = aWorldWidth / aspect; + const float oldWidth = m.max.x() - m.min.x(); m.min = vrb::Vector(-aWorldWidth * 0.5f, -worldHeight * 0.5f, 0.0f); m.max = vrb::Vector(aWorldWidth *0.5f, worldHeight * 0.5f, 0.0f); @@ -260,6 +284,10 @@ Widget::SetWorldWidth(float aWorldWidth) const { if (m.resizing && m.resizer) { m.resizer->SetSize(m.min, m.max); } + + if (oldWidth != aWorldWidth) { + m.RemoveBorder(); + } } void @@ -346,7 +374,7 @@ Widget::GetCylinder() const { } void -Widget::SetQuad(const QuadPtr& aQuad) const { +Widget::SetQuad(const QuadPtr& aQuad) { int32_t textureWidth, textureHeight; GetSurfaceTextureSize(textureWidth, textureHeight); if (m.cylinder) { @@ -362,11 +390,12 @@ Widget::SetQuad(const QuadPtr& aQuad) const { m.transformContainer->SetTransform(vrb::Matrix::Identity()); m.RemoveResizer(); + m.RemoveBorder(); m.UpdateSurface(textureWidth, textureHeight); } void -Widget::SetCylinder(const CylinderPtr& aCylinder) const { +Widget::SetCylinder(const CylinderPtr& aCylinder) { int32_t textureWidth, textureHeight; GetSurfaceTextureSize(textureWidth, textureHeight); if (m.quad) { @@ -381,6 +410,7 @@ Widget::SetCylinder(const CylinderPtr& aCylinder) const { m.transform->AddNode(aCylinder->GetRoot()); m.RemoveResizer(); + m.RemoveBorder(); m.UpdateSurface(textureWidth, textureHeight); } @@ -461,7 +491,6 @@ void Widget::HandleResize(const vrb::Vector& aPoint, bool aPressed, bool& aResized, bool &aResizeEnded) { m.resizer->HandleResizeGestures(aPoint, aPressed, aResized, aResizeEnded); if (aResized || aResizeEnded) { - m.min = m.resizer->GetResizeMin(); m.max = m.resizer->GetResizeMax(); if (m.quad) { @@ -469,6 +498,7 @@ Widget::HandleResize(const vrb::Vector& aPoint, bool aPressed, bool& aResized, b } else if (m.cylinder) { m.UpdateCylinderMatrix(); } + m.RemoveBorder(); } } @@ -492,6 +522,75 @@ Widget::GetCylinderDensity() const { return m.cylinderDensity; } +void +Widget::SetBorderColor(const vrb::Color &aColor) { + const bool visible = aColor.Alpha() > 0.0f; + if (!visible && m.bordersContainer) { + m.bordersContainer->ToggleAll(false); + return; + } + if (visible && !m.bordersContainer) { + vrb::RenderContextPtr render = m.context.lock(); + vrb::CreationContextPtr create = render->GetRenderThreadCreationContext(); + m.bordersContainer = vrb::Toggle::Create(create); + m.borders = WidgetBorder::CreateFrame(create, *this, kFrameSize, kBorder); + for (const WidgetBorderPtr& border: m.borders) { + m.bordersContainer->AddNode(border->GetTransformNode()); + } + m.transform->InsertNode(m.bordersContainer, 0); + } + + if (visible) { + m.bordersContainer->ToggleAll(true); + for (const WidgetBorderPtr& border: m.borders) { + border->SetColor(aColor); + } + } +} + +void +Widget::SetProxifyLayer(const bool aValue) { + if (!aValue) { + if (m.layerProxy) { + m.layerProxy->ToggleAll(false); + } + return; + } + + if (!m.layerProxy) { + vrb::RenderContextPtr render = m.context.lock(); + vrb::CreationContextPtr create = render->GetRenderThreadCreationContext(); + m.layerProxy = vrb::Toggle::Create(create); + // Proxy objects must clear the existing surface, so set a proper blend function. + m.layerProxy->SetPreRenderLambda(create, []() { + VRB_GL_CHECK(glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA)); + }); + m.layerProxy->SetPostRenderLambda(create, []() { + VRB_GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + }); + m.transform->AddNode(m.layerProxy); + int32_t textureWidth, textureHeight; + GetSurfaceTextureSize(textureWidth, textureHeight); + // Reduce quality, proxy objects do not need full quality. + textureWidth /= 2; + textureHeight /= 2; + vrb::TextureSurfacePtr proxySurface = vrb::TextureSurface::Create(render, m.name); + if (m.cylinder) { + CylinderPtr proxy = Cylinder::Create(create, *m.cylinder); + proxy->SetCylinderTheta(m.cylinder->GetCylinderTheta()); + proxy->SetTexture(proxySurface, textureWidth, textureHeight); + proxy->SetTransform(m.cylinder->GetTransformNode()->GetTransform()); + m.layerProxy->AddNode(proxy->GetRoot()); + } else { + QuadPtr proxy = Quad::Create(create, *m.quad); + proxy->SetTexture(proxySurface, textureWidth, textureHeight); + m.layerProxy->AddNode(proxy->GetRoot()); + } + } + + m.layerProxy->ToggleAll(true); +} + Widget::Widget(State& aState, vrb::RenderContextPtr& aContext) : m(aState) { m.context = aContext; } diff --git a/app/src/main/cpp/Widget.h b/app/src/main/cpp/Widget.h index d1f612e3f..bc6d5b8d7 100644 --- a/app/src/main/cpp/Widget.h +++ b/app/src/main/cpp/Widget.h @@ -60,8 +60,8 @@ class Widget { vrb::NodePtr GetRoot() const; QuadPtr GetQuad() const; CylinderPtr GetCylinder() const; - void SetQuad(const QuadPtr& aQuad) const; - void SetCylinder(const CylinderPtr& aCylinder) const; + void SetQuad(const QuadPtr& aQuad); + void SetCylinder(const CylinderPtr& aCylinder); VRLayerSurfacePtr GetLayer() const; vrb::TransformPtr GetTransformNode() const; const WidgetPlacementPtr& GetPlacement() const; @@ -74,6 +74,8 @@ class Widget { void HoverExitResize(); void SetCylinderDensity(const float aDensity); float GetCylinderDensity() const; + void SetBorderColor(const vrb::Color& aColor); + void SetProxifyLayer(const bool aValue); protected: struct State; Widget(State& aState, vrb::RenderContextPtr& aContext); diff --git a/app/src/main/cpp/WidgetBorder.cpp b/app/src/main/cpp/WidgetBorder.cpp new file mode 100644 index 000000000..33556dea7 --- /dev/null +++ b/app/src/main/cpp/WidgetBorder.cpp @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WidgetBorder.h" +#include "WidgetPlacement.h" +#include "Widget.h" +#include "Cylinder.h" +#include "Quad.h" +#include "vrb/ConcreteClass.h" + +#include "vrb/Color.h" +#include "vrb/CreationContext.h" +#include "vrb/Matrix.h" +#include "vrb/Geometry.h" +#include "vrb/RenderState.h" +#include "vrb/SurfaceTextureFactory.h" +#include "vrb/TextureGL.h" +#include "vrb/TextureSurface.h" +#include "vrb/Toggle.h" +#include "vrb/Transform.h" +#include "vrb/Vector.h" +#include "vrb/VertexArray.h" +#include "WidgetBorder.h" +#include + +namespace crow { + +static const char* sCylinderFragmentShader = R"SHADER( +precision highp float; + +uniform sampler2D u_texture0; +varying vec4 v_color; +varying vec2 v_uv; + +void main() { + vec4 color = vec4(1.0f, 1.0f, 1.0f, 1.0f); + if ((v_uv.x < 0.0f) || (v_uv.x > 1.0f)) { + color.a = 0.0f; + } + gl_FragColor = color * v_color; +} + +)SHADER"; + +struct WidgetBorder::State { + CylinderPtr cylinder; + vrb::GeometryPtr geometry; + vrb::TransformPtr transform; + + template + void UpdateMaterial(const T &aTarget, const vrb::Color &aDiffuse) { + vrb::Color ambient(0.5f, 0.5f, 0.5f, 1.0f); + aTarget->SetMaterial(ambient, aDiffuse, vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + } + + void AppendBorder(const vrb::GeometryPtr &geometry, GLint index1, GLint index2, + const vrb::Vector &offset, const vrb::Color &aColor, GLint ¤tIndex) { + vrb::VertexArrayPtr array = geometry->GetVertexArray(); + vrb::Vector offset1 = array->GetVertex(index1 - 1) + offset; + vrb::Vector offset2 = array->GetVertex(index2 - 1) + offset; + array->AppendVertex(offset1); + array->AppendVertex(offset2); + array->AppendColor(aColor); + array->AppendColor(aColor); + + GLint index3 = currentIndex++; + GLint index4 = currentIndex++; + std::vector index; + if (offset.y() > 0.0f) { + index = {index1, index2, index4, index3}; + } else if (offset.y() < 0.0f) { + index = {index3, index4, index2, index1}; + } else if (offset.x() > 0.0f) { + index = {index1, index3, index4, index2}; + } else { + index = {index3, index1, index2, index4}; + } + + std::vector normalIndex; + normalIndex.push_back(1); + normalIndex.push_back(1); + normalIndex.push_back(1); + normalIndex.push_back(1); + geometry->AddFace(index, index, normalIndex); + } + + vrb::GeometryPtr + CreateGeometry(vrb::CreationContextPtr aContext, const vrb::Vector &aMin, const vrb::Vector &aMax, + const device::EyeRect &aBorder) { + vrb::VertexArrayPtr array = vrb::VertexArray::Create(aContext); + vrb::Color solid(1.0f, 1.0f, 1.0f, 1.0f); + vrb::Color border(1.0f, 1.0f, 1.0f, 0.0f); + + const vrb::Vector bottomRight(aMax.x(), aMin.y(), aMin.z()); + array->AppendVertex(aMin); // Bottom left + array->AppendVertex(bottomRight); // Bottom right + array->AppendVertex(aMax); // Top right + array->AppendVertex(vrb::Vector(aMin.x(), aMax.y(), aMax.z())); // Top left + for (int i = 0; i < 4; ++i) { + array->AppendColor(solid); + } + + vrb::Vector normal = (bottomRight - aMin).Cross(aMax - aMin).Normalize(); + array->AppendNormal(normal); + + vrb::RenderStatePtr state = vrb::RenderState::Create(aContext); + state->SetVertexColorEnabled(true); + vrb::GeometryPtr geometry = vrb::Geometry::Create(aContext); + geometry->SetVertexArray(array); + geometry->SetRenderState(state); + + std::vector index; + index.push_back(1); + index.push_back(2); + index.push_back(3); + index.push_back(4); + std::vector normalIndex; + normalIndex.push_back(1); + normalIndex.push_back(1); + normalIndex.push_back(1); + normalIndex.push_back(1); + + geometry->AddFace(index, index, normalIndex); + + GLint currentIndex = 5; + + if (aBorder.mX > 0.0f) { + AppendBorder(geometry, 1, 4, vrb::Vector(-aBorder.mX, 0.0f, 0.0f), border, currentIndex); + } + if (aBorder.mWidth > 0.0f) { + AppendBorder(geometry, 2, 3, vrb::Vector(aBorder.mWidth, 0.0f, 0.0f), border, currentIndex); + } + if (aBorder.mY > 0.0f) { + AppendBorder(geometry, 1, 2, vrb::Vector(0.0f, -aBorder.mY, 0.0f), border, currentIndex); + } + if (aBorder.mHeight > 0.0f) { + AppendBorder(geometry, 4, 3, vrb::Vector(0.0f, aBorder.mHeight, 0.0f), border, currentIndex); + } + + return geometry; + } +}; // struct WidgetBorder::State + +WidgetBorderPtr WidgetBorder::Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aBarSize, + const float aBorderSize, const device::EyeRect& aBorderRect, + const WidgetBorder::Mode aMode) { + auto result = std::make_shared>(aContext); + vrb::Vector max(aBarSize.x() * 0.5f, aBarSize.y() * 0.5f, 0.0f); + result->m.transform = vrb::Transform::Create(aContext); + if (aMode == WidgetBorder::Mode::Cylinder) { + result->m.cylinder = Cylinder::Create(aContext, 1.0f, aBarSize.y(), vrb::Color(1.0f, 1.0f, 1.0f, 1.0f), aBorderSize, vrb::Color(1.0f, 1.0f, 1.0f, 0.0f)); + result->m.cylinder->SetLightsEnabled(false); + // Fix sticking out borders + // Sometimes there is no handle to hide it (e.g. bottom bar and anchor points != 0.5f) + vrb::TextureGLPtr defaultTexture = aContext->GetDefaultTexture(); + result->m.cylinder->SetTexture(defaultTexture, defaultTexture->GetWidth(), defaultTexture->GetHeight()); + result->m.cylinder->GetRenderState()->SetCustomFragmentShader(sCylinderFragmentShader); + result->m.transform->AddNode(result->m.cylinder->GetRoot()); + } else { + result->m.geometry = result->m.CreateGeometry(aContext, -max, max, aBorderRect); + result->m.geometry->GetRenderState()->SetLightsEnabled(false); + result->m.transform->AddNode(result->m.geometry); + } + + return result; +} + +void +WidgetBorder::SetColor(const vrb::Color& aColor) { + if (m.cylinder) { + m.UpdateMaterial(m.cylinder, aColor); + } else { + m.UpdateMaterial(m.geometry->GetRenderState(), aColor); + } +} + +const vrb::TransformPtr& +WidgetBorder::GetTransformNode() const { + return m.transform; +} + +const CylinderPtr& +WidgetBorder::GetCylinder() const { + return m.cylinder; +} + +std::vector +WidgetBorder::CreateFrame(vrb::CreationContextPtr &aContext, const Widget& aTarget, const float aFrameSize, const float aBorderSize) { + + device::EyeRect horizontalBorder(0.0f, aBorderSize, 0.0f, aBorderSize); + device::EyeRect verticalBorder(aBorderSize, 0.0f, aBorderSize, 0.0f); + + float w; + float h; + aTarget.GetWorldSize(w, h); + WidgetBorder::Mode mode = aTarget.GetCylinder() ? WidgetBorder::Mode::Cylinder : WidgetBorder::Mode::Quad; + + WidgetBorderPtr left = WidgetBorder::Create(aContext, vrb::Vector(aFrameSize, h + aFrameSize, 0.0f), aBorderSize, verticalBorder, WidgetBorder::Mode::Quad); + WidgetBorderPtr right = WidgetBorder::Create(aContext, vrb::Vector(aFrameSize, h + aFrameSize , 0.0f), aBorderSize, verticalBorder, WidgetBorder::Mode::Quad); + WidgetBorderPtr top = WidgetBorder::Create(aContext, vrb::Vector(w - aFrameSize, aFrameSize, 0.0f), aBorderSize, horizontalBorder, mode); + WidgetBorderPtr bottom = WidgetBorder::Create(aContext, vrb::Vector(w - aFrameSize, aFrameSize, 0.0f), aBorderSize, horizontalBorder, mode); + + if (mode == WidgetBorder::Mode::Quad) { + left->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(-w * 0.5f, 0.0f, 0.0f))); + right->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(w * 0.5f, 0.0f, 0.0f))); + top->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(0.0f, h * 0.5f, 0.0f))); + bottom->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(0.0f, -h * 0.5f, 0.0f))); + } else { + const float theta = aTarget.GetCylinder()->GetCylinderTheta(); + const float radius = aTarget.GetCylinder()->GetTransformNode()->GetTransform().GetScale().x(); + // Place top and bottom cylinders + top->m.cylinder->SetCylinderTheta(theta); + bottom->m.cylinder->SetCylinderTheta(theta); + vrb::Matrix cylinderScale = vrb::Matrix::Identity(); + cylinderScale.ScaleInPlace(vrb::Vector(radius, 1.0f, radius)); + top->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(0.0f, h * 0.5f, radius)).PostMultiply(cylinderScale)); + bottom->m.transform->SetTransform(vrb::Matrix::Translation(vrb::Vector(0.0f, -h * 0.5f, radius)).PostMultiply(cylinderScale)); + // Place left and right borders on the cylinder sides + auto placeBorder = [=](WidgetBorderPtr& aBorder, float aAngle) { + vrb::Matrix rotation = vrb::Matrix::Rotation(vrb::Vector(-cosf(aAngle), 0.0f, sinf(aAngle))); + vrb::Matrix translation = vrb::Matrix::Position(vrb::Vector(radius * cosf(aAngle), 0.0f, + radius - radius * sinf(aAngle))); + aBorder->m.transform->SetTransform(translation.PostMultiply(rotation)); + }; + + placeBorder(left, (float)M_PI * 0.5f + theta * 0.5f); + placeBorder(right, (float)M_PI * 0.5f - theta * 0.5f); + } + + + return {left, right, top, bottom}; +} + +WidgetBorder::WidgetBorder(State& aState, vrb::CreationContextPtr& aContext) : m(aState) { +} + +} // namespace crow diff --git a/app/src/main/cpp/WidgetBorder.h b/app/src/main/cpp/WidgetBorder.h new file mode 100644 index 000000000..f39c26a63 --- /dev/null +++ b/app/src/main/cpp/WidgetBorder.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef VRBROWSER_WIDGET_BORDER_DOT_H +#define VRBROWSER_WIDGET_BORDER_DOT_H + +#include "Device.h" +#include "vrb/Forward.h" +#include "vrb/MacroUtils.h" + +#include +#include +#include +#include + +namespace crow { + +class Cylinder; +typedef std::shared_ptr CylinderPtr; + +class Widget; + +class WidgetBorder; +typedef std::shared_ptr WidgetBorderPtr; + +class WidgetBorder { +public: + enum class Mode { + Quad, + Cylinder + }; + + static WidgetBorderPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aBarSize, + const float aBorderSize, const device::EyeRect& aBorderRect, + const WidgetBorder::Mode aMode); + void SetColor(const vrb::Color& aColor); + const vrb::TransformPtr& GetTransformNode() const; + const CylinderPtr& GetCylinder() const; + static std::vector CreateFrame(vrb::CreationContextPtr& aContext, const Widget& aTarget, + const float aFrameSize, const float aBorderSize); +protected: + struct State; + WidgetBorder(State& aState, vrb::CreationContextPtr& aContext); + ~WidgetBorder() = default; +private: + State& m; + WidgetBorder() = delete; + VRB_NO_DEFAULTS(WidgetBorder) +}; + +} // namespace crow + +#endif // VRBROWSER_WIDGET_BORDER_DOT_H diff --git a/app/src/main/cpp/WidgetPlacement.cpp b/app/src/main/cpp/WidgetPlacement.cpp index d67115960..5556f1680 100644 --- a/app/src/main/cpp/WidgetPlacement.cpp +++ b/app/src/main/cpp/WidgetPlacement.cpp @@ -55,9 +55,11 @@ WidgetPlacement::FromJava(JNIEnv* aEnv, jobject& aObject) { GET_BOOLEAN_FIELD(showPointer); GET_BOOLEAN_FIELD(firstDraw); GET_BOOLEAN_FIELD(layer); + GET_BOOLEAN_FIELD(proxifyLayer); GET_FLOAT_FIELD(textureScale, "textureScale"); GET_BOOLEAN_FIELD(cylinder); GET_FLOAT_FIELD(cylinderMapRadius, "cylinderMapRadius"); + GET_INT_FIELD(borderColor); return result; } diff --git a/app/src/main/cpp/WidgetPlacement.h b/app/src/main/cpp/WidgetPlacement.h index b68e9c0bf..4cc4d23c6 100644 --- a/app/src/main/cpp/WidgetPlacement.h +++ b/app/src/main/cpp/WidgetPlacement.h @@ -31,9 +31,11 @@ struct WidgetPlacement { bool showPointer; bool firstDraw; bool layer; + bool proxifyLayer; float textureScale; bool cylinder; float cylinderMapRadius; + int borderColor; int32_t GetTextureWidth() const; int32_t GetTextureHeight() const; diff --git a/app/src/main/cpp/WidgetResizer.cpp b/app/src/main/cpp/WidgetResizer.cpp index 07d0153b3..b6fdf9125 100644 --- a/app/src/main/cpp/WidgetResizer.cpp +++ b/app/src/main/cpp/WidgetResizer.cpp @@ -6,6 +6,7 @@ #include "WidgetResizer.h" #include "WidgetPlacement.h" #include "Widget.h" +#include "WidgetBorder.h" #include "Cylinder.h" #include "Quad.h" #include "vrb/ConcreteClass.h" @@ -25,23 +26,6 @@ namespace crow { -static const char* sCylinderFragmentShader = R"SHADER( -precision highp float; - -uniform sampler2D u_texture0; -varying vec4 v_color; -varying vec2 v_uv; - -void main() { - vec4 color = vec4(1.0f, 1.0f, 1.0f, 1.0f); - if ((v_uv.x < 0.0f) || (v_uv.x > 1.0f)) { - color.a = 0.0f; - } - gl_FragColor = color * v_color; -} - -)SHADER"; - struct ResizeBar; typedef std::shared_ptr ResizeBarPtr; @@ -80,120 +64,17 @@ static void UpdateResizeMaterial(const T& aTarget, ResizeState aState) { } struct ResizeBar { - enum class Mode { - Quad, - Cylinder - }; - static ResizeBarPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aCenter, const vrb::Vector& aScale, const device::EyeRect& aBorder, const ResizeBar::Mode aMode) { + static ResizeBarPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aCenter, const vrb::Vector& aScale, const device::EyeRect& aBorderRect, const WidgetBorder::Mode aMode) { auto result = std::make_shared(); result->center = aCenter; result->scale = aScale; - vrb::Vector max(kBarSize * 0.5f, kBarSize * 0.5f, 0.0f); - result->transform = vrb::Transform::Create(aContext); - if (aMode == ResizeBar::Mode::Cylinder) { - result->cylinder = Cylinder::Create(aContext, 1.0f, kBarSize, vrb::Color(1.0f, 1.0f, 1.0f, 1.0f), kBorder, vrb::Color(1.0f, 1.0f, 1.0f, 0.0f)); - result->cylinder->SetLightsEnabled(false); - // Fix sticking out borders - // Sometimes there is no handle to hide it (e.e. bottom bar and anchor points != 0.5f) - vrb::TextureGLPtr defaultTexture = aContext->GetDefaultTexture(); - result->cylinder->SetTexture(defaultTexture, defaultTexture->GetWidth(), defaultTexture->GetHeight()); - result->cylinder->GetRenderState()->SetCustomFragmentShader(sCylinderFragmentShader); - result->transform->AddNode(result->cylinder->GetRoot()); - } else { - result->geometry = CreateGeometry(aContext, -max, max, aBorder); - result->geometry->GetRenderState()->SetLightsEnabled(false); - result->transform->AddNode(result->geometry); - } - + vrb::Vector size(kBarSize, kBarSize, 0.0f); + result->border = WidgetBorder::Create(aContext, size, kBorder, aBorderRect, aMode); result->resizeState = ResizeState::Default; result->UpdateMaterial(); return result; } - static void AppendBorder(const vrb::GeometryPtr& geometry, GLint index1, GLint index2, const vrb::Vector& offset, const vrb::Color& aColor, GLint& currentIndex) { - vrb::VertexArrayPtr array = geometry->GetVertexArray(); - vrb::Vector offset1 = array->GetVertex(index1 - 1) + offset; - vrb::Vector offset2 = array->GetVertex(index2 - 1) + offset; - array->AppendVertex(offset1); - array->AppendVertex(offset2); - array->AppendColor(aColor); - array->AppendColor(aColor); - - GLint index3 = currentIndex++; - GLint index4 = currentIndex++; - std::vector index; - if (offset.y() > 0.0f) { - index = { index1, index2, index4, index3}; - } else if (offset.y() < 0.0f) { - index = { index3, index4, index2, index1}; - } else if (offset.x() > 0.0f) { - index = { index1, index3, index4, index2}; - } else { - index = { index3, index1, index2, index4}; - } - - std::vector normalIndex; - normalIndex.push_back(1); - normalIndex.push_back(1); - normalIndex.push_back(1); - normalIndex.push_back(1); - geometry->AddFace(index, index, normalIndex); - } - - static vrb::GeometryPtr CreateGeometry(vrb::CreationContextPtr aContext, const vrb::Vector &aMin, const vrb::Vector &aMax, const device::EyeRect& aBorder) { - vrb::VertexArrayPtr array = vrb::VertexArray::Create(aContext); - vrb::Color solid(1.0f, 1.0f, 1.0f, 1.0f); - vrb::Color border(1.0f, 1.0f, 1.0f, 0.0f); - - const vrb::Vector bottomRight(aMax.x(), aMin.y(), aMin.z()); - array->AppendVertex(aMin); // Bottom left - array->AppendVertex(bottomRight); // Bottom right - array->AppendVertex(aMax); // Top right - array->AppendVertex(vrb::Vector(aMin.x(), aMax.y(), aMax.z())); // Top left - for (int i = 0; i < 4; ++i) { - array->AppendColor(solid); - } - - vrb::Vector normal = (bottomRight - aMin).Cross(aMax - aMin).Normalize(); - array->AppendNormal(normal); - - vrb::RenderStatePtr state = vrb::RenderState::Create(aContext); - state->SetVertexColorEnabled(true); - vrb::GeometryPtr geometry = vrb::Geometry::Create(aContext); - geometry->SetVertexArray(array); - geometry->SetRenderState(state); - - std::vector index; - index.push_back(1); - index.push_back(2); - index.push_back(3); - index.push_back(4); - std::vector normalIndex; - normalIndex.push_back(1); - normalIndex.push_back(1); - normalIndex.push_back(1); - normalIndex.push_back(1); - - geometry->AddFace(index, index, normalIndex); - - GLint currentIndex = 5; - - if (aBorder.mX > 0.0f) { - AppendBorder(geometry, 1, 4, vrb::Vector(-aBorder.mX, 0.0f, 0.0f), border, currentIndex); - } - if (aBorder.mWidth > 0.0f) { - AppendBorder(geometry, 2, 3, vrb::Vector(aBorder.mWidth, 0.0f, 0.0f), border, currentIndex); - } - if (aBorder.mY > 0.0f) { - AppendBorder(geometry, 1, 2, vrb::Vector(0.0f, -aBorder.mY, 0.0f), border, currentIndex); - } - if (aBorder.mHeight > 0.0f) { - AppendBorder(geometry, 4, 3, vrb::Vector(0.0f, aBorder.mHeight, 0.0f), border, currentIndex); - } - - return geometry; - } - void SetResizeState(ResizeState aState) { if (resizeState != aState) { resizeState = aState; @@ -202,18 +83,22 @@ struct ResizeBar { } void UpdateMaterial() { - if (cylinder) { - UpdateResizeMaterial(cylinder, resizeState); - } else { - UpdateResizeMaterial(geometry->GetRenderState(), resizeState); + vrb::Color color = kDefaultColor; + if (resizeState == ResizeState::Hovered) { + color = kHoverColor; + } else if (resizeState == ResizeState::Active) { + color = kActiveColor; } + border->SetColor(color); + } + + void SetTransform(const vrb::Matrix& aTransform) { + border->GetTransformNode()->SetTransform(aTransform); } vrb::Vector center; vrb::Vector scale; - CylinderPtr cylinder; - vrb::GeometryPtr geometry; - vrb::TransformPtr transform; + WidgetBorderPtr border; ResizeState resizeState; }; @@ -394,11 +279,11 @@ struct WidgetResizer::State { vrb::Vector verticalSize(0.5f, 0.0f, 0.0f); device::EyeRect horizontalBorder(0.0f, kBorder, 0.0f, kBorder); device::EyeRect verticalBorder(kBorder, 0.0f, kBorder, 0.0f); - ResizeBar::Mode mode = widget->GetCylinder() ? ResizeBar::Mode::Cylinder : ResizeBar::Mode::Quad; - ResizeBarPtr leftTop = CreateResizeBar(vrb::Vector(0.0f, 0.75f, 0.0f), horizontalSize, verticalBorder, ResizeBar::Mode::Quad); - ResizeBarPtr leftBottom = CreateResizeBar(vrb::Vector(0.0f, 0.25f, 0.0f), horizontalSize, verticalBorder, ResizeBar::Mode::Quad); - ResizeBarPtr rightTop = CreateResizeBar(vrb::Vector(1.0f, 0.75f, 0.0f), horizontalSize, verticalBorder, ResizeBar::Mode::Quad); - ResizeBarPtr rightBottom = CreateResizeBar(vrb::Vector(1.0f, 0.25f, 0.0f), horizontalSize, verticalBorder, ResizeBar::Mode::Quad); + WidgetBorder::Mode mode = widget->GetCylinder() ? WidgetBorder::Mode::Cylinder : WidgetBorder::Mode::Quad; + ResizeBarPtr leftTop = CreateResizeBar(vrb::Vector(0.0f, 0.75f, 0.0f), horizontalSize, verticalBorder, WidgetBorder::Mode::Quad); + ResizeBarPtr leftBottom = CreateResizeBar(vrb::Vector(0.0f, 0.25f, 0.0f), horizontalSize, verticalBorder, WidgetBorder::Mode::Quad); + ResizeBarPtr rightTop = CreateResizeBar(vrb::Vector(1.0f, 0.75f, 0.0f), horizontalSize, verticalBorder, WidgetBorder::Mode::Quad); + ResizeBarPtr rightBottom = CreateResizeBar(vrb::Vector(1.0f, 0.25f, 0.0f), horizontalSize, verticalBorder, WidgetBorder::Mode::Quad); ResizeBarPtr topLeft = CreateResizeBar(vrb::Vector(0.25f, 1.0f, 0.0f), verticalSize, horizontalBorder, mode); ResizeBarPtr topRight = CreateResizeBar(vrb::Vector(0.75f, 1.0f, 0.0f), verticalSize, horizontalBorder, mode); //ResizeBarPtr bottomLeft = CreateResizeBar(vrb::Vector(0.25f, 0.0f, 0.0f), verticalSize, mode); @@ -419,14 +304,14 @@ struct WidgetResizer::State { Layout(); } - ResizeBarPtr CreateResizeBar(const vrb::Vector& aCenter, vrb::Vector aScale, const device::EyeRect& aBorder, const ResizeBar::Mode aMode) { + ResizeBarPtr CreateResizeBar(const vrb::Vector& aCenter, vrb::Vector aScale, const device::EyeRect& aBorder, const WidgetBorder::Mode aMode) { vrb::CreationContextPtr create = context.lock(); if (!create) { return nullptr; } ResizeBarPtr result = ResizeBar::Create(create, aCenter, aScale, aBorder, aMode); resizeBars.push_back(result); - root->AddNode(result->transform); + root->AddNode(result->border->GetTransformNode()); return result; } @@ -469,7 +354,7 @@ struct WidgetResizer::State { float targetHeight = bar->scale.y() > 0.0f ? (bar->scale.y() * fabs(height)) + kBarSize : kBarSize; vrb::Matrix matrix = vrb::Matrix::Position(vrb::Vector(min.x() + width * bar->center.x(), min.y() + height * bar->center.y(), 0.005f)); matrix.ScaleInPlace(vrb::Vector(targetWidth / kBarSize, targetHeight / kBarSize, 1.0f)); - bar->transform->SetTransform(matrix); + bar->SetTransform(matrix); } for (ResizeHandlePtr& handle: resizeHandles) { @@ -504,19 +389,19 @@ struct WidgetResizer::State { float targetHeight = bar->scale.y() > 0.0f ? (bar->scale.y() * fabs(height)) + kBarSize : kBarSize; float pointerAngle = (float)M_PI * 0.5f + theta * 0.5f - theta * bar->center.x() + angleDelta; vrb::Matrix rotation = vrb::Matrix::Rotation(vrb::Vector(-cosf(pointerAngle), 0.0f, sinf(pointerAngle))); - if (bar->cylinder) { - bar->cylinder->SetCylinderTheta(theta * bar->scale.x()); + if (bar->border->GetCylinder()) { + bar->border->GetCylinder()->SetCylinderTheta(theta * bar->scale.x()); vrb::Matrix translation = vrb::Matrix::Position(vrb::Vector(0.0f, min.y() + height * bar->center.y(), radius)); vrb::Matrix scale = vrb::Matrix::Identity(); scale.ScaleInPlace(vrb::Vector(radius, 1.0f, radius)); - bar->transform->SetTransform(translation.PostMultiply(scale).PostMultiply(rotation)); + bar->SetTransform(translation.PostMultiply(scale).PostMultiply(rotation)); } else { vrb::Matrix translation = vrb::Matrix::Position(vrb::Vector(radius * cosf(pointerAngle), min.y() + height * bar->center.y(), radius - radius * sinf(pointerAngle))); vrb::Matrix scale = vrb::Matrix::Identity(); scale.ScaleInPlace(vrb::Vector(targetWidth / kBarSize, targetHeight / kBarSize, 1.0f)); - bar->transform->SetTransform(translation.PostMultiply(scale).PostMultiply(rotation)); + bar->SetTransform(translation.PostMultiply(scale).PostMultiply(rotation)); } } diff --git a/app/src/main/cpp/vrb b/app/src/main/cpp/vrb index b14cc4362..db3c19d44 160000 --- a/app/src/main/cpp/vrb +++ b/app/src/main/cpp/vrb @@ -1 +1 @@ -Subproject commit b14cc4362c7fe0b2e6a3ed67ce25326ac39782f0 +Subproject commit db3c19d44adfb20f7303747f71ac55ef5ea6687c diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 1716c6a32..74057b58a 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -38,4 +38,6 @@ #8F000000 #7FFFFFFF #f5f6fa + #1ac1dd + #2bd2ee