diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index eee8bccf2..4aef1bed0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -20,6 +20,7 @@ add_library( # Sets the name of the library. # Provides a relative path to your source file(s). src/main/cpp/BrowserWorld.cpp + src/main/cpp/Cylinder.cpp src/main/cpp/Controller.cpp src/main/cpp/ControllerContainer.cpp src/main/cpp/DeviceUtils.cpp diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index 6da1558db..5c31ca7d4 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -185,6 +185,7 @@ protected void onCreate(Bundle savedInstanceState) { queueRunnable(() -> createOffscreenDisplay()); final String tempPath = getCacheDir().getAbsolutePath(); queueRunnable(() -> setTemporaryFilePath(tempPath)); + setCylinderDensity(SettingsStore.getInstance(this).getCylinderDensity()); initializeWorld(); // Setup the search engine @@ -983,6 +984,10 @@ public void resetUIYaw() { queueRunnable(this::resetUIYawNative); } + public void setCylinderDensity(final float aDensity) { + queueRunnable(() -> setCylinderDensityNative(aDensity)); + } + private native void addWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void updateWidgetNative(int aHandle, WidgetPlacement aPlacement); private native void removeWidgetNative(int aHandle); @@ -999,4 +1004,5 @@ public void resetUIYaw() { private native void resetUIYawNative(); private native void setControllersVisibleNative(boolean aVisible); private native void runCallbackNative(long aCallback); + private native void setCylinderDensityNative(float aDensity); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java index 0f4f75a1b..cdfea3c26 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java @@ -55,6 +55,7 @@ SettingsStore getInstance(final @NonNull Context aContext) { public final static float BROWSER_WORLD_HEIGHT_DEFAULT = 2.25f; public final static int MSAA_DEFAULT_LEVEL = 1; public final static boolean AUDIO_ENABLED = false; + public final static float CYLINDER_DENSITY_ENABLED_DEFAULT = 4680.0f; // Enable telemetry by default (opt-out). private final static boolean enableCrashReportingByDefault = false; @@ -361,4 +362,13 @@ public void setVoiceSearchLanguage(String language) { editor.commit(); } + public float getCylinderDensity() { + return mPrefs.getFloat(mContext.getString(R.string.settings_key_cylinder_density), 0); + } + + public void setCylinderDensity(float aDensity) { + SharedPreferences.Editor editor = mPrefs.edit(); + editor.putFloat(mContext.getString(R.string.settings_key_cylinder_density), aDensity); + editor.commit(); + } } 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 0a7260af0..d6c5b9d20 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 @@ -191,6 +191,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.rotation = (float)Math.toRadians(WidgetPlacement.floatDimension(context, R.dimen.keyboard_world_rotation)); aPlacement.worldWidth = WidgetPlacement.floatDimension(context, R.dimen.keyboard_world_width); aPlacement.visible = false; + aPlacement.cylinder = true; } public void setBrowserWidget(UIWidget aWidget) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java index 00b703cf4..9702d7a47 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java @@ -357,6 +357,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.parentAnchorY = 0.0f; aPlacement.translationY = -35; aPlacement.opaque = false; + aPlacement.cylinder = true; } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/RootWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/RootWidget.java index a33dc5859..320bd4bdf 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/RootWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/RootWidget.java @@ -26,6 +26,7 @@ public RootWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.width = 8; aPlacement.height = 8; + aPlacement.cylinder = false; } private void initialize(Context aContext) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java index 13b0a016b..567e8b34d 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java @@ -61,9 +61,9 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.width = WidgetPlacement.dpDimension(context, R.dimen.top_bar_width); aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.top_bar_height); aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * aPlacement.width/getWorldWidth(); - aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.top_bar_world_y); + //aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.top_bar_world_y); aPlacement.anchorX = 0.5f; - aPlacement.anchorY = 0.5f; + aPlacement.anchorY = 0.0f; aPlacement.parentAnchorX = 0.5f; aPlacement.parentAnchorY = 1.0f; aPlacement.opaque = false; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java index aea6b8a64..b941c123c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java @@ -202,6 +202,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.rotationAxisX = 1.0f; aPlacement.rotation = (float)Math.toRadians(-45); aPlacement.opaque = false; + aPlacement.cylinder = false; } @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 dee2590d6..d07cd8dec 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 @@ -39,6 +39,7 @@ public WidgetPlacement(Context aContext) { public boolean showPointer = true; public boolean firstDraw = false; public boolean layer = true; + public boolean cylinder = true; public WidgetPlacement clone() { WidgetPlacement w = new WidgetPlacement(); @@ -67,6 +68,8 @@ public void copyFrom(WidgetPlacement w) { this.opaque = w.opaque; this.showPointer = w.showPointer; this.firstDraw = w.firstDraw; + this.layer = w.layer; + this.cylinder = w.cylinder; } public int textureWidth() { 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 365cef8b0..7c9163794 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 @@ -92,6 +92,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.anchorX = 0.5f; aPlacement.anchorY = 0.0f; aPlacement.visible = true; + aPlacement.cylinder = true; } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/options/DisplayOptionsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/options/DisplayOptionsWidget.java index 1edb88c68..f045e46ae 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/options/DisplayOptionsWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/options/DisplayOptionsWidget.java @@ -8,6 +8,7 @@ import android.content.Context; import android.util.AttributeSet; import android.view.View; +import android.widget.CompoundButton; import android.widget.ScrollView; import org.mozilla.vrbrowser.R; @@ -19,6 +20,7 @@ import org.mozilla.vrbrowser.ui.views.settings.DoubleEditSetting; import org.mozilla.vrbrowser.ui.views.settings.RadioGroupSetting; import org.mozilla.vrbrowser.ui.views.settings.SingleEditSetting; +import org.mozilla.vrbrowser.ui.views.settings.SwitchSetting; import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate; import org.mozilla.vrbrowser.ui.widgets.dialogs.RestartDialogWidget; import org.mozilla.vrbrowser.ui.widgets.UIWidget; @@ -31,6 +33,7 @@ public class DisplayOptionsWidget extends UIWidget implements private AudioEngine mAudio; private UIButton mBackButton; + private SwitchSetting mCurvedDisplaySwitch; private RadioGroupSetting mUaModeRadio; private RadioGroupSetting mMSAARadio; @@ -76,6 +79,13 @@ private void initialize(Context aContext) { } }); + mCurvedDisplaySwitch = findViewById(R.id.curved_display_switch); + mCurvedDisplaySwitch.setChecked(SettingsStore.getInstance(getContext()).getCylinderDensity() > 0.0f); + mCurvedDisplaySwitch.setOnCheckedChangeListener((compoundButton, enabled, apply) -> { + SettingsStore.getInstance(getContext()).setCylinderDensity(enabled ? SettingsStore.CYLINDER_DENSITY_ENABLED_DEFAULT : 0.0f); + showRestartDialog(); + }); + int uaMode = SettingsStore.getInstance(getContext()).getUaMode(); mUaModeRadio = findViewById(R.id.ua_radio); mUaModeRadio.setOnCheckedChangeListener(mUaModeListener); diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index 0c7829890..579d7ec77 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -18,6 +18,7 @@ #include "Pointer.h" #include "Widget.h" #include "WidgetPlacement.h" +#include "Cylinder.h" #include "Quad.h" #include "VRBrowser.h" #include "VRVideo.h" @@ -150,6 +151,7 @@ struct BrowserWorld::State { DrawableListPtr drawList; CameraPtr leftCamera; CameraPtr rightCamera; + float cylinderDensity; float nearClip; float farClip; JNIEnv* env; @@ -167,7 +169,7 @@ struct BrowserWorld::State { SplashAnimationPtr splashAnimation; VRVideoPtr vrVideo; - State() : paused(true), glInitialized(false), modelsLoaded(false), env(nullptr), nearClip(0.1f), + State() : paused(true), glInitialized(false), modelsLoaded(false), env(nullptr), cylinderDensity(0.0f), nearClip(0.1f), farClip(300.0f), activity(nullptr), windowsInitialized(false), exitImmersiveRequested(false), loaderDelay(0) { context = RenderContext::Create(); create = context->GetRenderThreadCreationContext(); @@ -272,15 +274,18 @@ BrowserWorld::State::UpdateControllers(bool& aRelayoutWidgets) { WidgetPtr hitWidget; float hitDistance = farClip; vrb::Vector hitPoint; + vrb::Vector hitNormal; for (const WidgetPtr& widget: widgets) { vrb::Vector result; + vrb::Vector normal; float distance = 0.0f; bool isInWidget = false; - if (widget->TestControllerIntersection(start, direction, result, isInWidget, distance)) { + if (widget->TestControllerIntersection(start, direction, result, normal, isInWidget, distance)) { if (isInWidget && (distance < hitDistance)) { hitWidget = widget; hitDistance = distance; hitPoint = result; + hitNormal = normal; } } } @@ -294,8 +299,10 @@ BrowserWorld::State::UpdateControllers(bool& aRelayoutWidgets) { controller.pointer->SetVisible(hitWidget.get() != nullptr); controller.pointer->SetHitWidget(hitWidget); if (hitWidget) { - vrb::Matrix translate = vrb::Matrix::Translation(vrb::Vector(hitPoint.x(), hitPoint.y(), 0.001f)); - controller.pointer->SetTransform(hitWidget->GetTransform().PostMultiply(translate)); + vrb::Matrix translation = vrb::Matrix::Translation(hitPoint); + vrb::Matrix localRotation = vrb::Matrix::Rotation(hitNormal); + vrb::Matrix reorient = device->GetReorientTransform(); + controller.pointer->SetTransform(reorient.AfineInverse().PostMultiply(translation).PostMultiply(localRotation)); } } @@ -701,17 +708,24 @@ BrowserWorld::AddWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement) { int32_t textureWidth = (int32_t)(ceilf(aPlacement->width * aPlacement->density)); int32_t textureHeight = (int32_t)(ceilf(aPlacement->height * aPlacement->density)); + const float aspect = (float)textureWidth / (float)textureHeight; + const float worldHeight = worldWidth / aspect; + WidgetPtr widget; - VRLayerQuadPtr layer; - if (aPlacement->layer && m.device) { - layer = m.device->CreateLayerQuad(textureWidth, textureHeight, - VRLayerQuad::SurfaceType::AndroidSurface); + if (aPlacement->cylinder && m.cylinderDensity > 0 && m.device) { + VRLayerCylinderPtr layer = m.device->CreateLayerCylinder(textureWidth, textureHeight, VRLayerQuad::SurfaceType::AndroidSurface); + CylinderPtr cylinder = Cylinder::Create(m.create, layer); + widget = Widget::Create(m.context, aHandle, textureWidth, textureHeight, worldWidth, worldHeight, cylinder); } - if (layer) { - widget = Widget::Create(m.context, aHandle, layer, worldWidth); - } else { - widget = Widget::Create(m.context, aHandle, textureWidth, textureHeight, worldWidth); + if (!widget) { + VRLayerQuadPtr layer; + if (aPlacement->layer && m.device) { + layer = m.device->CreateLayerQuad(textureWidth, textureHeight, VRLayerQuad::SurfaceType::AndroidSurface); + } + + QuadPtr quad = Quad::Create(m.create, worldWidth, worldHeight, layer); + widget = Widget::Create(m.context, aHandle, textureWidth, textureHeight, quad); } if (aPlacement->opaque) { @@ -741,6 +755,7 @@ BrowserWorld::UpdateWidget(int32_t aHandle, const WidgetPlacementPtr& aPlacement } widget->SetPlacement(aPlacement); + widget->SetCylinderDensity(m.cylinderDensity); widget->ToggleWidget(aPlacement->visible); widget->SetSurfaceTextureSize((int32_t)(ceilf(aPlacement->width * aPlacement->density)), (int32_t)(ceilf(aPlacement->height * aPlacement->density))); @@ -846,6 +861,9 @@ BrowserWorld::LayoutWidget(int32_t aHandle) { } transform.TranslateInPlace(translation); + if (!parent) { + translation = transform.GetTranslation(); + } widget->SetTransform(parent ? parent->GetTransform().PostMultiply(transform) : transform); } @@ -911,6 +929,14 @@ BrowserWorld::ResetUIYaw() { m.device->SetReorientTransform(matrix); } +void +BrowserWorld::SetCylinderDensity(const float aDensity) { + m.cylinderDensity = aDensity; + for (WidgetPtr& widget: m.widgets) { + widget->SetCylinderDensity(aDensity); + } +} + JNIEnv* BrowserWorld::GetJNIEnv() const { ASSERT_ON_RENDER_THREAD(nullptr); @@ -1149,9 +1175,14 @@ BrowserWorld::DistanceToPlane(const vrb::NodePtr& aNode, const vrb::Vector& aPos return -1.0f; } vrb::Vector result; + vrb::Vector normal; bool inside = false; float distance = -1.0f; - target->GetQuad()->TestIntersection(aPosition, aDirection, result, false, inside, distance); + if (target->GetQuad()) { + target->GetQuad()->TestIntersection(aPosition, aDirection, result, normal, false, inside, distance); + } else if (target->GetCylinder()) { + distance = target->GetCylinder()->DistanceToBackPlane(aPosition, aDirection); + } if (pointer) { distance-= 0.001f; } @@ -1260,6 +1291,12 @@ JNI_METHOD(void, resetUIYawNative) crow::BrowserWorld::Instance().ResetUIYaw(); } +JNI_METHOD(void, setCylinderDensityNative) +(JNIEnv* aEnv, jobject, jfloat aDensity) { + crow::BrowserWorld::Instance().SetCylinderDensity(aDensity); +} + + JNI_METHOD(void, runCallbackNative) (JNIEnv* aEnv, jobject, jlong aCallback) { if (aCallback) { diff --git a/app/src/main/cpp/BrowserWorld.h b/app/src/main/cpp/BrowserWorld.h index b86d09984..b2f7d1304 100644 --- a/app/src/main/cpp/BrowserWorld.h +++ b/app/src/main/cpp/BrowserWorld.h @@ -55,6 +55,7 @@ class BrowserWorld { void HideVRVideo(); void SetControllersVisible(const bool aVisible); void ResetUIYaw(); + void SetCylinderDensity(const float aDensity); JNIEnv* GetJNIEnv() const; protected: struct State; diff --git a/app/src/main/cpp/Cylinder.cpp b/app/src/main/cpp/Cylinder.cpp new file mode 100644 index 000000000..e601d5718 --- /dev/null +++ b/app/src/main/cpp/Cylinder.cpp @@ -0,0 +1,465 @@ +/* -*- 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 "Cylinder.h" +#include "Quad.h" +#include "VRLayer.h" +#include "VRLayerNode.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/TextureSurface.h" +#include "vrb/Toggle.h" +#include "vrb/Transform.h" +#include "vrb/Vector.h" +#include "vrb/VertexArray.h" + +namespace crow { + +struct Cylinder::State { + vrb::CreationContextWeak context; + VRLayerCylinderPtr layer; + VRLayerNodePtr layerNode; + int32_t textureWidth; + int32_t textureHeight; + vrb::TogglePtr root; + vrb::TransformPtr transform; + vrb::GeometryPtr geometry; + float radius; + float height; + float theta; + float textureScaleX; + float textureScaleY; + + State() + : textureWidth(0) + , textureHeight(0) + , radius(1.0f) + , height(2.0f) + , theta((float)M_PI) + , textureScaleX(1.0f) + , textureScaleY(1.0f) + {} + + void Initialize() { + vrb::CreationContextPtr create = context.lock(); + transform = vrb::Transform::Create(create); + if (layer) { + textureWidth = layer->GetWidth(); + textureHeight = layer->GetHeight(); + layer->SetRadius(radius); + layerNode = VRLayerNode::Create(create, layer); + transform->AddNode(layerNode); + } else { + geometry = CreateCylinderGeometry(radius, height, (float) M_PI); + transform->AddNode(geometry); + } + root = vrb::Toggle::Create(create); + root->AddNode(transform); + } + + const int kRadialSegments = 200; + const int kHeightSegments = 1; + + vrb::GeometryPtr CreateCylinderGeometry(const float aRadius, const float aHeight, const float aArcLength) { + const float pi = (float) M_PI; + + const float startAngle = pi * 0.5f + aArcLength * 0.5f; + + vrb::CreationContextPtr create = context.lock(); + vrb::GeometryPtr geometry = vrb::Geometry::Create(create); + vrb::VertexArrayPtr array = vrb::VertexArray::Create(create); + + for (int y = 0; y <= kHeightSegments; ++y) { + const float v = (float) y / (float) kHeightSegments; + for (int x = 0; x <= kRadialSegments; ++x) { + const float u = (float) x / (float) kRadialSegments; + + const float theta = startAngle - aArcLength * u; + + const float sinTheta = sinf(theta); + const float cosTheta = cosf(theta); + vrb::Vector vertex; + vrb::Vector uv; + vrb::Vector normal; + + vertex.x() = aRadius * cosTheta; + vertex.y() = -v * aHeight + aHeight * 0.5f; + vertex.z() = -aRadius * sinTheta; + + uv.x() = u; + uv.y() = v; + uv.z() = 0.0f; + + normal.x() = -cosTheta; + normal.y() = 0.0f; + normal.z() = sinTheta; + + array->AppendVertex(vertex); + array->AppendUV(uv); + array->AppendNormal(vertex.Normalize()); + } + } + geometry->SetVertexArray(array); + + std::vector indices; + + for (int x = 0; x < kRadialSegments; ++x) { + for (int y = 0; y < kHeightSegments; ++y) { + const int a = 1 + y * (kRadialSegments + 1) + x; + const int b = 1 + (y + 1) * (kRadialSegments + 1) + x; + const int c = 1 + (y + 1) * (kRadialSegments + 1) + x + 1; + const int d = 1 + y * (kRadialSegments + 1) + x + 1; + + indices.clear(); + indices.push_back(b); + indices.push_back(c); + indices.push_back(d); + indices.push_back(a); + + // update group counter + geometry->AddFace(indices, indices, indices); + } + } + + vrb::RenderStatePtr state = vrb::RenderState::Create(create); + state->SetLightsEnabled(false); + state->SetFragmentPrecision(GL_HIGH_FLOAT); + state->SetUVTransformEnabled(true); + geometry->SetRenderState(state); + + return geometry; + } + + void updateTextureLayout() { + const float texScaleX = (float)M_PI / theta; + const float texBiasX = -texScaleX * (0.5f * (1.0f - 1.0f / texScaleX)); + const float texScaleY = layer ? 0.5f : 1.0f; + const float texBiasY = -texScaleY * (0.5f * (1.0f - (1.0f / texScaleY))); + vrb::Matrix transform = vrb::Matrix::Translation(vrb::Vector(texBiasX, texBiasY, 0.0f)); + transform.ScaleInPlace(vrb::Vector(texScaleX, texScaleY, 1.0f)); + if (layer) { + layer->SetUVTransform(device::Eye::Left, transform); + layer->SetUVTransform(device::Eye::Right, transform); + } + if (geometry) { + geometry->GetRenderState()->SetUVTransform(transform); + int32_t segments = (int32_t)ceilf(kRadialSegments * fmin(1.0f, 1.0f / texScaleX)); + if (segments % 2 != 0) { + segments++; + } + const int32_t indicesPerSegment = 6; + const int32_t start = (kRadialSegments - segments) / 2; + geometry->SetRenderRange(start * indicesPerSegment, segments * indicesPerSegment); + } + } +}; + +CylinderPtr +Cylinder::Create(vrb::CreationContextPtr aContext, const float aRadius, const float aHeight, const VRLayerCylinderPtr& aLayer) { + CylinderPtr result = std::make_shared >(aContext); + result->m.radius = aRadius; + result->m.height = aHeight; + result->m.layer = aLayer; + result->m.Initialize(); + return result; +} + +CylinderPtr +Cylinder::Create(vrb::CreationContextPtr aContext, const VRLayerCylinderPtr& aLayer) { + CylinderPtr result = std::make_shared >(aContext); + result->m.layer = aLayer; + result->m.Initialize(); + return result; +} + +void +Cylinder::GetTextureSize(int32_t& aWidth, int32_t& aHeight) const { + aWidth = (int32_t)(m.textureWidth * m.textureScaleX); + aHeight = (int32_t)(m.textureHeight * m.textureScaleY); +} + +void +Cylinder::SetTextureSize(int32_t aWidth, int32_t aHeight) { + m.textureWidth = aWidth; + m.textureHeight = aHeight; + if (m.layer) { + m.layer->Resize(aWidth, aHeight); + } + m.updateTextureLayout(); +} + +void +Cylinder::SetTexture(const vrb::TexturePtr& aTexture, int32_t aWidth, int32_t aHeight) { + m.textureWidth = aWidth; + m.textureHeight = aHeight; + if (m.geometry) { + m.geometry->GetRenderState()->SetTexture(aTexture); + } + m.updateTextureLayout(); +} + +void +Cylinder::SetTextureScale(const float aScaleX, const float aScaleY) { + m.textureScaleX = aScaleX; + m.textureScaleY = aScaleY; +} + +void +Cylinder::SetMaterial(const vrb::Color& aAmbient, const vrb::Color& aDiffuse, const vrb::Color& aSpecular, const float aSpecularExponent) { + if (m.geometry) { + m.geometry->GetRenderState()->SetMaterial(aAmbient, aDiffuse, aSpecular, aSpecularExponent); + } +} + +void +Cylinder::SetLightsEnabled(const bool aEnabled) { + if (m.geometry) { + m.geometry->GetRenderState()->SetLightsEnabled(aEnabled); + } +} + +float +Cylinder::GetCylinderRadius() const { + return m.radius; +} + +float +Cylinder::GetCylinderHeight() const { + return m.height; +} + +float +Cylinder::GetCylinderTheta() const { + return m.theta; +} + +void +Cylinder::SetCylinderTheta(const float aAngleLength) { + m.theta = aAngleLength; + m.updateTextureLayout(); +} + +void +Cylinder::SetTintColor(const vrb::Color& aColor) { + if (m.layer) { + m.layer->SetTintColor(aColor); + } else if (m.geometry && m.geometry->GetRenderState()) { + m.geometry->GetRenderState()->SetTintColor(aColor); + } +} + +vrb::NodePtr +Cylinder::GetRoot() const { + return m.root; +} + +VRLayerCylinderPtr +Cylinder::GetLayer() const { + return m.layer; +} + +vrb::TransformPtr +Cylinder::GetTransformNode() const { + return m.transform; +} + +void +Cylinder::SetTransform(const vrb::Matrix& aTransform) { + m.transform->SetTransform(aTransform); +} + +static const float kEpsilon = 0.00000001f; + +bool +Cylinder::TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool aClamp, bool& aIsInside, float& aDistance) const { + aDistance = -1.0f; + if (!m.root->IsEnabled(*m.transform)) { + return false; + } + + vrb::Matrix worldTransform = m.transform->GetWorldTransform(); + vrb::Matrix modelView = worldTransform.AfineInverse(); + vrb::Vector start = modelView.MultiplyPosition(aStartPoint); + vrb::Vector direction = modelView.MultiplyDirection(aDirection); + start = start - direction * 1000.0f; + + const float radius = this->GetCylinderRadius(); + + const vrb::Vector A(0.0f, -m.height * 0.5f, 0.0f); // Cylinder bottom center + const vrb::Vector B(0.0f, m.height * 0.5f, 0.0f); // Cylinder top center + + const vrb::Vector AB = B - A; + const vrb::Vector AO = start - A; + const vrb::Vector AOxAB = AO.Cross(AB); + const vrb::Vector VxAB = direction.Cross(AB); + // Solve quadratic formula + const float ab2 = AB.Dot(AB); + const float a = VxAB.Dot(VxAB); + const float b = 2 * VxAB.Dot(AOxAB); + const float c = AOxAB.Dot(AOxAB) - (radius * radius * ab2); + const float d = b * b - 4 * a * c; + if (d < 0) { + return false; + } + double time = (-b + sqrt(d)) / (2 * a); + if (time < 0) { + return false; + } + + const vrb::Vector intersection = start + direction * time; // intersection point + const vrb::Vector projection = A + AB * (AB.Dot(intersection - A) / ab2); // intersection projected onto cylinder axis + + // Height test + const bool insideHeight = (projection - A).Magnitude() + (B - projection).Magnitude() <= AB.Magnitude(); + + // Normal Test + const vrb::Vector normal = (projection - intersection).Normalize(); + if (normal.z() < 0) { + // Ignore cylinder side not facing the user + return false; + } + + // Cylinder theta angle test + const float maxTheta = m.theta; + const float hitTheta = (float)M_PI - acosf(fabsf(intersection.x()) / radius) * 2.0f; + aIsInside = insideHeight && hitTheta <= maxTheta && fabs(intersection.y()) <= radius; + + vrb::Vector result = intersection; + // Clamp to keep pointer in cylinder surface. + if (aClamp && !aIsInside) { + const float maxX = radius * cosf(0.5f * ((float)M_PI - maxTheta)); + const float minX = -maxX; + if (result.x() > maxX) { result.x() = maxX; } + else if (result.x() < minX) { result.x() = minX; } + + if (result.y() > radius) { result.y() = radius; } + else if (result.y() < radius) { result.y() = -radius; } + } + + aResult = worldTransform.MultiplyPosition(intersection); + aNormal = worldTransform.MultiplyDirection(normal); + aDistance = (aResult - aStartPoint).Magnitude(); + + return true; +} + +void +Cylinder::ConvertToQuadCoordinates(const vrb::Vector& point, float& aX, float& aY, bool aClamp) const { + const vrb::Vector intersection = m.transform->GetWorldTransform().AfineInverse().MultiplyPosition(point); + const float radius = GetCylinderRadius(); + float ratioY; + if (intersection.y() > 0.0f) { + ratioY = 0.5f - 0.5f * intersection.y() / radius; + } else { + ratioY = 0.5f + 0.5f * fabsf(intersection.y()) / radius; + } + + const float hitTheta = (float)M_PI - acosf(fabsf(intersection.x()) / radius) * 2.0f; + const float maxTheta = m.theta; + float ratioTheta = hitTheta / maxTheta * 0.5f; + float ratioX; + if (intersection.x() > 0.0f) { + ratioX = 0.5f + ratioTheta; + } else { + ratioX = 0.5f - ratioTheta; + } + + if (aClamp) { + if (ratioY > 1.0f) { + ratioY = 1.0f; + } + if (ratioY < 0.0f) { + ratioY = 0.0f; + } + if (ratioX > 1.0f) { + ratioX = 1.0f; + } + if (ratioX < 0.0f) { + ratioX = 0.0f; + } + + aX = ratioX * m.textureWidth; + aY = ratioY * m.textureHeight; + } +} + +void +Cylinder::ConvertFromQuadCoordinates(const float aX, const float aY, vrb::Vector& aWorldPoint, vrb::Vector& aNormal) { + const float ratioX = aX / m.textureWidth; + const float ratioY = aY / m.textureHeight; + const float radius = GetCylinderRadius(); + const float pi = (float) M_PI; + float targetTheta; + const float maxTheta = m.theta; + if (ratioX > 0.5f) { + targetTheta = (ratioX - 0.5f) * maxTheta; + } else { + targetTheta = -maxTheta * (0.5f - ratioX); + } + + const float angle = pi * 0.5f - targetTheta; + const float x = radius * cosf(angle); + const float z = -radius * sinf(angle); + float y; + if (ratioY > 0.5f) { + y = radius * (ratioY - 0.5f) * 2.0f; + } else { + y = -radius * (0.5f - ratioY) * 2.0f; + } + + vrb::Vector targetPoint(x, y, z); + aNormal = (vrb::Vector(0.0f, y, 0.0f) - targetPoint).Normalize(); + + aWorldPoint = m.transform->GetWorldTransform().MultiplyPosition(targetPoint); +} + +float Cylinder::DistanceToBackPlane(const vrb::Vector &aStartPoint, const vrb::Vector &aDirection) const { + float result = -1.0f; + if (!m.root->IsEnabled(*m.transform)) { + return result; + } + vrb::Matrix worldTransform = m.transform->GetWorldTransform(); + vrb::Matrix modelView = worldTransform.AfineInverse(); + vrb::Vector point = modelView.MultiplyPosition(aStartPoint); + vrb::Vector direction = modelView.MultiplyDirection(aDirection); + + const vrb::Vector max(1.0f, 1.0f, -1.0f); + const vrb::Vector min(-1.0f, -1.0f, -1.0f); + const vrb::Vector bottomRight(max.x(), min.y(), min.z()); + vrb::Vector normal = (bottomRight - min).Cross(max - min).Normalize(); + const float dotNormals = direction.Dot(normal); + if (dotNormals > -kEpsilon) { + // Not pointed at the plane + return result; + } + + const float dotV = (min - point).Dot(normal); + + if ((dotV < kEpsilon) && (dotV > -kEpsilon)) { + return result; + } + + const float length = dotV / dotNormals; + vrb::Vector intersection = point + (direction * length); + + vrb::Vector worldPoint = worldTransform.MultiplyPosition(intersection); + result = (worldPoint - aStartPoint).Magnitude(); + + return result; +} + +Cylinder::Cylinder(State& aState, vrb::CreationContextPtr& aContext) : m(aState) { + m.context = aContext; +} + +Cylinder::~Cylinder() {} + +} // namespace crow diff --git a/app/src/main/cpp/Cylinder.h b/app/src/main/cpp/Cylinder.h new file mode 100644 index 000000000..7c72432e5 --- /dev/null +++ b/app/src/main/cpp/Cylinder.h @@ -0,0 +1,62 @@ +/* -*- 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_CYLINDER_DOT_H +#define VRBROWSER_CYLINDER_DOT_H + +#include "vrb/Forward.h" +#include "vrb/MacroUtils.h" +#include "Device.h" + +#include +#include +#include +#include + +namespace crow { + + +class VRLayerCylinder; +typedef std::shared_ptr VRLayerCylinderPtr; + +class Cylinder; +typedef std::shared_ptr CylinderPtr; + +class Cylinder { +public: + static CylinderPtr Create(vrb::CreationContextPtr aContext, const float aRadius, const float aHeight, const VRLayerCylinderPtr& aLayer = nullptr); + static CylinderPtr Create(vrb::CreationContextPtr aContext, const VRLayerCylinderPtr& aLayer = nullptr); + void GetTextureSize(int32_t& aWidth, int32_t& aHeight) const; + void SetTextureSize(int32_t aWidth, int32_t aHeight); + void SetTexture(const vrb::TexturePtr& aTexture, int32_t aWidth, int32_t aHeight); + void SetTextureScale(const float aScaleX, const float aScaleY); + void SetMaterial(const vrb::Color& aAmbient, const vrb::Color& aDiffuse, const vrb::Color& aSpecular, const float aSpecularExponent); + void SetLightsEnabled(const bool aEnabled); + float GetCylinderRadius() const; + float GetCylinderHeight() const; + float GetCylinderTheta() const; + void SetCylinderTheta(const float aAngleLength); + void SetTintColor(const vrb::Color& aColor); + vrb::NodePtr GetRoot() const; + VRLayerCylinderPtr GetLayer() const; + vrb::TransformPtr GetTransformNode() const; + void SetTransform(const vrb::Matrix& aTransform); + bool TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool aClamp, bool& aIsInside, float& aDistance) const; + void ConvertToQuadCoordinates(const vrb::Vector& point, float& aX, float& aY, bool aClamp) const; + void ConvertFromQuadCoordinates(const float aX, const float aY, vrb::Vector& aWorldPoint, vrb::Vector& aNormal); + float DistanceToBackPlane(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection) const; + + struct State; + Cylinder(State& aState, vrb::CreationContextPtr& aContext); + ~Cylinder(); +private: + State& m; + Cylinder() = delete; + VRB_NO_DEFAULTS(Cylinder) +}; + +} // namespace crow + +#endif // VRBROWSER_CYLINDER_DOT_H diff --git a/app/src/main/cpp/DeviceDelegate.h b/app/src/main/cpp/DeviceDelegate.h index 0fa318f99..ff3a80a9b 100644 --- a/app/src/main/cpp/DeviceDelegate.h +++ b/app/src/main/cpp/DeviceDelegate.h @@ -62,11 +62,12 @@ class DeviceDelegate { virtual void StartFrame() = 0; virtual void BindEye(const device::Eye aWhich) = 0; virtual void EndFrame(bool aDiscard = false) = 0; - virtual VRLayerQuadPtr CreateLayerQuad(int32_t aWidth, - int32_t aHeight, - VRLayerQuad::SurfaceType aSurfaceType) { return nullptr; } + virtual VRLayerQuadPtr CreateLayerQuad(int32_t aWidth, int32_t aHeight, + VRLayerSurface::SurfaceType aSurfaceType) { return nullptr; } + virtual VRLayerCylinderPtr CreateLayerCylinder(int32_t aWidth, int32_t aHeight, + VRLayerSurface::SurfaceType aSurfaceType) { return nullptr; } virtual VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) { return nullptr; } - virtual VRLayerEquirectPtr CreateLayerEquirect(const VRLayerQuadPtr &aSource) { return nullptr; } + virtual VRLayerEquirectPtr CreateLayerEquirect(const VRLayerPtr &aSource) { return nullptr; } virtual void DeleteLayer(const VRLayerPtr& aLayer) {}; protected: DeviceDelegate() {} diff --git a/app/src/main/cpp/Quad.cpp b/app/src/main/cpp/Quad.cpp index 36317bb57..a1eda04bd 100644 --- a/app/src/main/cpp/Quad.cpp +++ b/app/src/main/cpp/Quad.cpp @@ -380,20 +380,21 @@ Quad::GetTransformNode() const { return m.transform; } -vrb::GeometryPtr -Quad::GetGeometry() const { - return m.geometry; +VRLayerQuadPtr +Quad::GetLayer() const { + return m.layer; } static const float kEpsilon = 0.00000001f; bool -Quad::TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, bool aClamp, bool& aIsInside, float& aDistance) const { +Quad::TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool aClamp, bool& aIsInside, float& aDistance) const { aDistance = -1.0f; if (!m.root->IsEnabled(*m.transform)) { return false; } - vrb::Matrix modelView = m.transform->GetWorldTransform().AfineInverse(); + vrb::Matrix worldTransform = m.transform->GetWorldTransform(); + vrb::Matrix modelView = worldTransform.AfineInverse(); vrb::Vector point = modelView.MultiplyPosition(aStartPoint); vrb::Vector direction = modelView.MultiplyDirection(aDirection); vrb::Vector normal = GetNormal(); @@ -420,8 +421,6 @@ Quad::TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirec aResult = result; - aDistance = (aResult - point).Magnitude(); - // Clamp to keep pointer in quad. if (aClamp) { if (result.x() > m.worldMax.x()) { result.x() = m.worldMax.x(); } @@ -431,12 +430,16 @@ Quad::TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirec else if (result.y() < m.worldMin.y()) { result.y() = m.worldMin.y(); } } + aResult = worldTransform.MultiplyPosition(result); + aNormal = worldTransform.MultiplyDirection(normal); + aDistance = (aResult - aStartPoint).Magnitude(); + return true; } void Quad::ConvertToQuadCoordinates(const vrb::Vector& point, float& aX, float& aY, bool aClamp) const { - vrb::Vector value = point; + vrb::Vector value = m.transform->GetWorldTransform().AfineInverse().MultiplyPosition(point); // Clamp value to quad bounds. if (aClamp) { if (value.x() > m.worldMax.x()) { value.x() = m.worldMax.x(); } diff --git a/app/src/main/cpp/Quad.h b/app/src/main/cpp/Quad.h index 398d7c39d..aa25b0d3d 100644 --- a/app/src/main/cpp/Quad.h +++ b/app/src/main/cpp/Quad.h @@ -54,8 +54,8 @@ class Quad { vrb::Vector GetNormal() const; vrb::NodePtr GetRoot() const; vrb::TransformPtr GetTransformNode() const; - vrb::GeometryPtr GetGeometry() const; - bool TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, bool aClamp, bool& aIsInside, float& aDistance) const; + VRLayerQuadPtr GetLayer() const; + bool TestIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool aClamp, bool& aIsInside, float& aDistance) const; void ConvertToQuadCoordinates(const vrb::Vector& point, float& aX, float& aY, bool aClamp) const; struct State; diff --git a/app/src/main/cpp/VRLayer.cpp b/app/src/main/cpp/VRLayer.cpp index d95d887f4..ad4d39717 100644 --- a/app/src/main/cpp/VRLayer.cpp +++ b/app/src/main/cpp/VRLayer.cpp @@ -65,7 +65,7 @@ VRLayer::GetModelTransform(device::Eye aEye) const { const vrb::Matrix& -VRLayer::GetModelView(device::Eye aEye) const { +VRLayer::GetView(device::Eye aEye) const { return m.modelView[device::EyeIndex(aEye)]; } @@ -135,7 +135,7 @@ VRLayer::SetModelTransform(device::Eye aEye, const vrb::Matrix& aModelTransform) } void -VRLayer::SetModelView(device::Eye aEye, const vrb::Matrix& aModelView) { +VRLayer::SetView(device::Eye aEye, const vrb::Matrix& aModelView) { m.modelView[device::EyeIndex(aEye)] = aModelView; } @@ -189,7 +189,7 @@ void VRLayer::NotifySurfaceChanged(SurfaceChange aChange, const std::function>(); - result->m.width = aWidth; - result->m.height = aHeight; - result->m.surfaceType = aSurfaceType; - return result; -} - - -VRLayerQuad::SurfaceType -VRLayerQuad::GetSurfaceType() const { +VRLayerSurface::SurfaceType +VRLayerSurface::GetSurfaceType() const { return m.surfaceType; } int32_t -VRLayerQuad::GetWidth() const { +VRLayerSurface::GetWidth() const { return m.width; } int32_t -VRLayerQuad::GetHeight() const { +VRLayerSurface::GetHeight() const { return m.height; } float -VRLayerQuad::GetWorldWidth() const { +VRLayerSurface::GetWorldWidth() const { return m.worldWidth; } float -VRLayerQuad::GetWorldHeight() const { +VRLayerSurface::GetWorldHeight() const { return m.worldHeight; } jobject -VRLayerQuad::GetSurface() const { +VRLayerSurface::GetSurface() const { return m.surface; } void -VRLayerQuad::Bind(GLenum aTarget) { +VRLayerSurface::Bind(GLenum aTarget) { m.boundTarget = aTarget; if (m.bindDelegate) { m.bindDelegate(aTarget, true); @@ -260,7 +250,7 @@ VRLayerQuad::Bind(GLenum aTarget) { } void -VRLayerQuad::Unbind(){ +VRLayerSurface::Unbind(){ if (m.bindDelegate) { m.bindDelegate(m.boundTarget, false); } @@ -268,13 +258,13 @@ VRLayerQuad::Unbind(){ void -VRLayerQuad::SetWorldSize(const float aWidth, const float aHeight) { +VRLayerSurface::SetWorldSize(const float aWidth, const float aHeight) { m.worldWidth = aWidth; m.worldHeight = aHeight; } void -VRLayerQuad::Resize(const int32_t aWidth, const int32_t aHeight) { +VRLayerSurface::Resize(const int32_t aWidth, const int32_t aHeight) { if (m.width == aWidth && m.height == aHeight) { return; } @@ -286,26 +276,94 @@ VRLayerQuad::Resize(const int32_t aWidth, const int32_t aHeight) { } void -VRLayerQuad::SetResizeDelegate(const ResizeDelegate& aDelegate) { +VRLayerSurface::SetResizeDelegate(const ResizeDelegate& aDelegate) { m.resizeDelegate = aDelegate; } void -VRLayerQuad::SetBindDelegate(const BindDelegate& aDelegate) { +VRLayerSurface::SetBindDelegate(const BindDelegate& aDelegate) { m.bindDelegate = aDelegate; } void -VRLayerQuad::SetSurface(jobject aSurface) { +VRLayerSurface::SetSurface(jobject aSurface) { m.surface = aSurface; } -VRLayerQuad::VRLayerQuad(State& aState): VRLayer(aState, LayerType::QUAD), m(aState) { +VRLayerSurface::VRLayerSurface(State& aState, LayerType aLayerType): VRLayer(aState, aLayerType), m(aState) { +} + +VRLayerSurface::~VRLayerSurface() {} + +// Layer Quad + +struct VRLayerQuad::State: public VRLayerSurface::State { + State() {} +}; + +VRLayerQuadPtr +VRLayerQuad::Create(const int32_t aWidth, const int32_t aHeight, VRLayerSurface::SurfaceType aSurfaceType) { + auto result = std::make_shared>(); + result->m.width = aWidth; + result->m.height = aHeight; + result->m.surfaceType = aSurfaceType; + return result; +} + +VRLayerQuad::VRLayerQuad(State& aState): VRLayerSurface(aState, LayerType::QUAD), m(aState) { } VRLayerQuad::~VRLayerQuad() {} +// Layer Cylinder + +struct VRLayerCylinder::State: public VRLayerSurface::State { + float radius; + vrb::Matrix uvTransform[2]; + State(): + radius(1.0f) + { + uvTransform[0] = vrb::Matrix::Identity(); + uvTransform[1] = vrb::Matrix::Identity(); + } +}; + + +VRLayerCylinderPtr +VRLayerCylinder::Create(const int32_t aWidth, const int32_t aHeight, VRLayerSurface::SurfaceType aSurfaceType) { + auto result = std::make_shared>(); + result->m.width = aWidth; + result->m.height = aHeight; + result->m.surfaceType = aSurfaceType; + return result; +} + +float +VRLayerCylinder::GetRadius() const { + return m.radius; +} + +const vrb::Matrix& +VRLayerCylinder::GetUVTransform(device::Eye aEye) const { + return m.uvTransform[device::EyeIndex(aEye)]; +} + +void +VRLayerCylinder::SetUVTransform(device::Eye aEye, const vrb::Matrix& aTransform) { + m.uvTransform[device::EyeIndex(aEye)] = aTransform; +} + +void +VRLayerCylinder::SetRadius(const float aRadius) { + m.radius = aRadius; +} + +VRLayerCylinder::VRLayerCylinder(State& aState): VRLayerSurface(aState, LayerType::QUAD), m(aState) { + +} + +VRLayerCylinder::~VRLayerCylinder() {} // Layer Cube diff --git a/app/src/main/cpp/VRLayer.h b/app/src/main/cpp/VRLayer.h index e78c65ffc..2b61091cf 100644 --- a/app/src/main/cpp/VRLayer.h +++ b/app/src/main/cpp/VRLayer.h @@ -41,7 +41,7 @@ class VRLayer { bool IsInitialized() const; bool IsDrawRequested() const; const vrb::Matrix& GetModelTransform(device::Eye aEye) const; - const vrb::Matrix& GetModelView(device::Eye aEye) const; + const vrb::Matrix& GetView(device::Eye aEye) const; device::Eye GetCurrentEye() const; int32_t GetPriority() const; const vrb::Color& GetTintColor() const; @@ -53,7 +53,7 @@ class VRLayer { void RequestDraw(); void ClearRequestDraw(); void SetModelTransform(device::Eye aEye, const vrb::Matrix& aModelTransform); - void SetModelView(device::Eye aEye, const vrb::Matrix& aModelView); + void SetView(device::Eye aEye, const vrb::Matrix& aModelView); void SetCurrentEye(device::Eye aEye); void SetPriority(int32_t aPriority); void SetTintColor(const vrb::Color& aTintColor); @@ -70,11 +70,10 @@ class VRLayer { VRB_NO_DEFAULTS(VRLayer) }; +class VRLayerSurface; +typedef std::shared_ptr VRLayerSurfacePtr; -class VRLayerQuad; -typedef std::shared_ptr VRLayerQuadPtr; - -class VRLayerQuad: public VRLayer { +class VRLayerSurface: public VRLayer { public: typedef std::function ResizeDelegate; typedef std::function BindDelegate; @@ -84,8 +83,6 @@ class VRLayerQuad: public VRLayer { FBO, }; - static VRLayerQuadPtr Create(const int32_t aWidth, const int32_t aHeight, VRLayerQuad::SurfaceType aSurfaceType); - SurfaceType GetSurfaceType() const; int32_t GetWidth() const; int32_t GetHeight() const; @@ -103,6 +100,21 @@ class VRLayerQuad: public VRLayer { void SetResizeDelegate(const ResizeDelegate& aDelegate); void SetBindDelegate(const BindDelegate& aDelegate); void SetSurface(jobject aSurface); +protected: + struct State; + VRLayerSurface(State& aState, LayerType aLayerType); + virtual ~VRLayerSurface(); +private: + State& m; + VRB_NO_DEFAULTS(VRLayerSurface) +}; + +class VRLayerQuad; +typedef std::shared_ptr VRLayerQuadPtr; + +class VRLayerQuad: public VRLayerSurface { +public: + static VRLayerQuadPtr Create(const int32_t aWidth, const int32_t aHeight, VRLayerSurface::SurfaceType aSurfaceType); protected: struct State; VRLayerQuad(State& aState); @@ -112,6 +124,27 @@ class VRLayerQuad: public VRLayer { VRB_NO_DEFAULTS(VRLayerQuad) }; + +class VRLayerCylinder; +typedef std::shared_ptr VRLayerCylinderPtr; + +class VRLayerCylinder: public VRLayerSurface { +public: + static VRLayerCylinderPtr Create(const int32_t aWidth, const int32_t aHeight, VRLayerSurface::SurfaceType aSurfaceType); + float GetRadius() const; + const vrb::Matrix& GetUVTransform(device::Eye aEye) const; + void SetRadius(const float aRadius); + void SetUVTransform(device::Eye aEye, const vrb::Matrix& aTransform); +protected: + struct State; + VRLayerCylinder(State& aState); + virtual ~VRLayerCylinder(); +private: + State& m; + VRB_NO_DEFAULTS(VRLayerCylinder) +}; + + class VRLayerCube; typedef std::shared_ptr VRLayerCubePtr; diff --git a/app/src/main/cpp/VRLayerNode.cpp b/app/src/main/cpp/VRLayerNode.cpp index dd98988bb..7806cd923 100644 --- a/app/src/main/cpp/VRLayerNode.cpp +++ b/app/src/main/cpp/VRLayerNode.cpp @@ -62,7 +62,7 @@ VRLayerNode::Draw(const Camera& aCamera, const Matrix& aModelTransform) { m.layer->RequestDraw(); device::Eye eye = m.layer->GetCurrentEye(); m.layer->SetModelTransform(eye, aModelTransform); - m.layer->SetModelView(eye, aCamera.GetView().PostMultiply(aModelTransform)); + m.layer->SetView(eye, aCamera.GetView()); } VRLayerNode::VRLayerNode(State& aState, CreationContextPtr& aContext) : diff --git a/app/src/main/cpp/VRVideo.cpp b/app/src/main/cpp/VRVideo.cpp index 739a4543a..dbbe41bb5 100644 --- a/app/src/main/cpp/VRVideo.cpp +++ b/app/src/main/cpp/VRVideo.cpp @@ -49,7 +49,7 @@ struct VRVideo::State { window = aWindow; projection = aProjection; root = vrb::Toggle::Create(create); - VRLayerQuadPtr windowLayer = aWindow->GetLayer(); + VRLayerSurfacePtr windowLayer = aWindow->GetLayer(); if (windowLayer) { layerTextureBackup[0] = windowLayer->GetTextureRect(device::Eye::Left); layerTextureBackup[1] = windowLayer->GetTextureRect(device::Eye::Right); @@ -286,7 +286,7 @@ struct VRVideo::State { vrb::TogglePtr createQuadProjectionLayer(device::Eye aEye, const device::EyeRect& aUVRect) { vrb::CreationContextPtr create = context.lock(); - VRLayerQuadPtr windowLayer = window->GetLayer(); + VRLayerSurfacePtr windowLayer = window->GetLayer(); windowLayer->SetTextureRect(aEye, aUVRect); layer = windowLayer; @@ -345,7 +345,7 @@ VRVideo::GetRoot() const { void VRVideo::Exit() { - VRLayerQuadPtr windowLayer = m.window->GetLayer(); + VRLayerSurfacePtr windowLayer = m.window->GetLayer(); if (windowLayer) { windowLayer->SetTextureRect(device::Eye::Left, m.layerTextureBackup[0]); windowLayer->SetTextureRect(device::Eye::Right, m.layerTextureBackup[1]); diff --git a/app/src/main/cpp/Widget.cpp b/app/src/main/cpp/Widget.cpp index 9a88cd7ef..6f1ceaea4 100644 --- a/app/src/main/cpp/Widget.cpp +++ b/app/src/main/cpp/Widget.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Widget.h" +#include "Cylinder.h" #include "Quad.h" #include "VRLayer.h" #include "VRBrowser.h" @@ -29,8 +30,11 @@ struct Widget::State { vrb::RenderContextWeak context; std::string name; uint32_t handle; + vrb::Vector min; + vrb::Vector max; QuadPtr quad; - VRLayerQuadPtr layer; + CylinderPtr cylinder; + float cylinderDensity; vrb::TogglePtr root; vrb::TransformPtr transform; vrb::TextureSurfacePtr surface; @@ -43,17 +47,23 @@ struct Widget::State { : handle(0) , resizing(false) , toggleState(false) + , cylinderDensity(4680.0f) {} - void Initialize(const int aHandle, const vrb::Vector& aWindowMin, const vrb::Vector& aWindowMax, - const int32_t aTextureWidth, const int32_t aTextureHeight, const VRLayerQuadPtr& aLayer) { + void Initialize(const int aHandle, const int32_t aTextureWidth, const int32_t aTextureHeight, + const QuadPtr& aQuad, const CylinderPtr& aCylinder) { handle = aHandle; name = "crow::Widget-" + std::to_string(handle); vrb::RenderContextPtr render = context.lock(); if (!render) { return; } - layer = aLayer; + + quad = aQuad; + cylinder = aCylinder; + + VRLayerPtr layer = GetLayer(); + if (layer) { layer->SetSurfaceChangedDelegate([=](const VRLayer& aLayer, VRLayer::SurfaceChange aChange, const std::function& aCallback) { const VRLayerQuad& layerQuad = static_cast(aLayer); @@ -61,18 +71,24 @@ struct Widget::State { }); } else { surface = vrb::TextureSurface::Create(render, name); - } - vrb::CreationContextPtr create = render->GetRenderThreadCreationContext(); - quad = Quad::Create(create, aWindowMin, aWindowMax, layer); - if (surface) { - quad->SetTexture(surface, aTextureWidth, aTextureHeight); - quad->SetMaterial(vrb::Color(0.4f, 0.4f, 0.4f), vrb::Color(1.0f, 1.0f, 1.0f), vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + if (quad) { + quad->SetTexture(surface, aTextureWidth, aTextureHeight); + quad->SetMaterial(vrb::Color(0.4f, 0.4f, 0.4f), vrb::Color(1.0f, 1.0f, 1.0f), vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + } else if (cylinder) { + cylinder->SetTexture(surface, aTextureWidth, aTextureHeight); + cylinder->SetMaterial(vrb::Color(0.4f, 0.4f, 0.4f), vrb::Color(1.0f, 1.0f, 1.0f), vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + } } + vrb::CreationContextPtr create = render->GetRenderThreadCreationContext(); transform = vrb::Transform::Create(create); - transform->AddNode(quad->GetRoot()); root = vrb::Toggle::Create(create); root->AddNode(transform); + if (quad) { + transform->AddNode(quad->GetRoot()); + } else { + transform->AddNode(cylinder->GetRoot()); + } if (layer) { toggleState = true; @@ -88,34 +104,70 @@ struct Widget::State { } return placement->firstDraw; } -}; -WidgetPtr -Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const int32_t aWidth, const int32_t aHeight, float aWorldWidth) { - WidgetPtr result = std::make_shared >(aContext); - const float aspect = (float)aWidth / (float)aHeight; - const float worldHeight = aWorldWidth / aspect; - vrb::Vector windowMin(-aWorldWidth * 0.5f, -worldHeight * 0.5f, 0.0f); - vrb::Vector windowMax(aWorldWidth *0.5f, worldHeight * 0.5f, 0.0f); - result->m.Initialize(aHandle, windowMin, windowMax, aWidth, aHeight, nullptr); - return result; -} + const VRLayerSurfacePtr GetLayer() { + return quad ? (VRLayerSurfacePtr) quad->GetLayer() : cylinder->GetLayer(); + } + + float WorldWidth() const { + return max.x() - min.x(); + } + + float WorldHeight() const { + return max.y() - min.y(); + } + + void UpdateCylinderMatrix() { + float w = WorldWidth(); + float h = WorldHeight(); + int32_t textureWidth, textureHeight; + cylinder->GetTextureSize(textureWidth, textureHeight); + + const float radius = cylinder->GetCylinderRadius(); + const float surfaceWidth = (float)textureWidth / placement->density; + const float surfaceHeight = (float)textureHeight / placement->density; + // Cylinder density measures the pixels for a 360 cylinder + // Oculus recommends 4680px density, which is 13 pixels per degree. + const float theta = (float)M_PI * surfaceWidth / (cylinderDensity * 0.5f); + cylinder->SetCylinderTheta(theta); + const float heightScale = surfaceHeight * (float)M_PI / cylinderDensity; + const float scale = h / (cylinder->GetCylinderHeight() * heightScale); + vrb::Matrix scaleMatrix = vrb::Matrix::Identity(); + scaleMatrix.ScaleInPlace(vrb::Vector(radius * scale, radius * scale * heightScale, radius * scale)); + vrb::Matrix translation = vrb::Matrix::Translation(vrb::Vector(0.0f, 0.0f, radius * scale)); + + const float x = transform->GetWorldTransform().GetTranslation().x(); + if (x != 0.0f) { + // Automatically adjust correct yaw angle & position for the cylinders not centered on the X axis + const float r = radius * scale; + const float perimeter = 2.0f * r * (float)M_PI; + const float angle = 0.5f * (float)M_PI - x / perimeter * 2.0f * (float)M_PI; + vrb::Matrix rotation = vrb::Matrix::Rotation(vrb::Vector(-cosf(angle), 0.0f, sinf(angle))); + vrb::Matrix transform = translation.PostMultiply(scaleMatrix).PostMultiply(rotation); + transform.PreMultiplyInPlace(vrb::Matrix::Translation(vrb::Vector(-x, 0.0f, 0.0f))); + cylinder->SetTransform(transform); + } else { + cylinder->SetTransform(translation.PostMultiply(scaleMatrix)); + } + } +}; WidgetPtr -Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const VRLayerQuadPtr& aLayer, float aWorldWidth) { +Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, + const int32_t aTextureWidth, const int32_t aTextureHeight,const QuadPtr& aQuad) { WidgetPtr result = std::make_shared >(aContext); - const float aspect = (float)aLayer->GetWidth() / (float)aLayer->GetHeight(); - const float worldHeight = aWorldWidth / aspect; - vrb::Vector windowMin(-aWorldWidth * 0.5f, -worldHeight * 0.5f, 0.0f); - vrb::Vector windowMax(aWorldWidth *0.5f, worldHeight * 0.5f, 0.0f); - result->m.Initialize(aHandle, windowMin, windowMax, aLayer->GetWidth(), aLayer->GetHeight(), aLayer); + aQuad->GetWorldMinAndMax(result->m.min, result->m.max); + result->m.Initialize(aHandle, aTextureWidth, aTextureHeight, aQuad, nullptr); return result; } WidgetPtr -Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const int32_t aWidth, const int32_t aHeight, const vrb::Vector& aMin, const vrb::Vector& aMax) { +Widget::Create(vrb::RenderContextPtr& aContext, const int aHandle, const float aWorldWidth, const float aWorldHeight, + const int32_t aTextureWidth, const int32_t aTextureHeight, const CylinderPtr& aCylinder) { WidgetPtr result = std::make_shared >(aContext); - result->m.Initialize(aHandle, aMin, aMax, aWidth, aHeight, nullptr); + 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.Initialize(aHandle, aTextureWidth, aTextureHeight, nullptr, aCylinder); return result; } @@ -146,47 +198,71 @@ Widget::GetSurfaceTexture() const { void Widget::GetSurfaceTextureSize(int32_t& aWidth, int32_t& aHeight) const { - m.quad->GetTextureSize(aWidth, aHeight); + if (m.quad) { + m.quad->GetTextureSize(aWidth, aHeight); + } else { + m.cylinder->GetTextureSize(aWidth, aHeight); + } } void Widget::SetSurfaceTextureSize(int32_t aWidth, int32_t aHeight) { - m.quad->SetTextureSize(aWidth, aHeight); + if (m.quad) { + m.quad->SetTextureSize(aWidth, aHeight); + } else { + m.cylinder->SetTextureSize(aWidth, aHeight); + m.UpdateCylinderMatrix(); + } } void Widget::GetWidgetMinAndMax(vrb::Vector& aMin, vrb::Vector& aMax) const { - m.quad->GetWorldMinAndMax(aMin, aMax); + aMin = m.min; + aMax = m.max; } void Widget::SetWorldWidth(float aWorldWidth) const { int32_t width, height; - m.quad->GetTextureSize(width, height); + this->GetSurfaceTextureSize(width, height); const float aspect = (float)width / (float) height; const float worldHeight = aWorldWidth / aspect; - m.quad->SetWorldSize(aWorldWidth, worldHeight); + + m.min = vrb::Vector(-aWorldWidth * 0.5f, -worldHeight * 0.5f, 0.0f); + m.max = vrb::Vector(aWorldWidth *0.5f, worldHeight * 0.5f, 0.0f); + + if (m.quad) { + m.quad->SetWorldSize(aWorldWidth, worldHeight); + } + if (m.cylinder) { + m.UpdateCylinderMatrix(); + } + if (m.resizing && m.resizer) { - vrb::Vector min(-aWorldWidth * 0.5f, -worldHeight * 0.5f, 0.0f); - vrb::Vector max(aWorldWidth *0.5f, worldHeight * 0.5f, 0.0f); - m.resizer->SetSize(min, max); + m.resizer->SetSize(m.min, m.max); } } void Widget::GetWorldSize(float& aWidth, float& aHeight) const { - m.quad->GetWorldSize(aWidth, aHeight); + aWidth = m.max.x() - m.min.x(); + aHeight = m.max.y() - m.min.y(); } bool -Widget::TestControllerIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, bool& aIsInWidget, float& aDistance) const { +Widget::TestControllerIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool& aIsInWidget, float& aDistance) const { aDistance = -1.0f; if (!m.root->IsEnabled(*m.transform)) { return false; } bool clamp = !m.resizing; - bool result = m.quad->TestIntersection(aStartPoint, aDirection, aResult, clamp, aIsInWidget, aDistance); + bool result; + if (m.quad) { + result = m.quad->TestIntersection(aStartPoint, aDirection, aResult, aNormal, clamp, aIsInWidget, aDistance); + } else { + result = m.cylinder->TestIntersection(aStartPoint, aDirection, aResult, aNormal, clamp, aIsInWidget, aDistance); + } if (result && m.resizing && !aIsInWidget) { // Handle extra intersections while resizing aIsInWidget = m.resizer->TestIntersection(aResult); @@ -198,7 +274,11 @@ Widget::TestControllerIntersection(const vrb::Vector& aStartPoint, const vrb::Ve void Widget::ConvertToWidgetCoordinates(const vrb::Vector& point, float& aX, float& aY) const { bool clamp = !m.resizing; - m.quad->ConvertToQuadCoordinates(point, aX, aY, clamp); + if (m.quad) { + m.quad->ConvertToQuadCoordinates(point, aX, aY, clamp); + } else { + m.cylinder->ConvertToQuadCoordinates(point, aX, aY, clamp); + } } void @@ -214,6 +294,9 @@ Widget::GetTransform() const { void Widget::SetTransform(const vrb::Matrix& aTransform) { m.transform->SetTransform(aTransform); + if (m.cylinder) { + m.UpdateCylinderMatrix(); + } } void @@ -238,9 +321,14 @@ Widget::GetQuad() const { return m.quad; } -const VRLayerQuadPtr& +CylinderPtr +Widget::GetCylinder() const { + return m.cylinder; +} + +VRLayerSurfacePtr Widget::GetLayer() const { - return m.layer; + return m.GetLayer(); } vrb::TransformPtr @@ -259,25 +347,32 @@ Widget::SetPlacement(const WidgetPlacementPtr& aPlacement) { m.root->ToggleAll(m.toggleState); } m.placement = aPlacement; + if (m.cylinder) { + m.UpdateCylinderMatrix(); + } } void Widget::StartResize() { + vrb::Vector worldMin, worldMax; + GetWidgetMinAndMax(worldMin, worldMax); if (m.resizer) { - m.resizer->SetSize(m.quad->GetWorldMin(), m.quad->GetWorldMax()); + m.resizer->SetSize(worldMin, worldMax); } else { vrb::RenderContextPtr render = m.context.lock(); if (!render) { return; } vrb::CreationContextPtr create = render->GetRenderThreadCreationContext(); - m.resizer = WidgetResizer::Create(create, m.quad->GetWorldMin(), m.quad->GetWorldMax()); + m.resizer = WidgetResizer::Create(create, this); m.transform->InsertNode(m.resizer->GetRoot(), 0); } m.resizing = true; m.resizer->ToggleVisible(true); - m.quad->SetScaleMode(Quad::ScaleMode::AspectFit); - m.quad->SetBackgroundColor(vrb::Color(1.0f, 1.0f, 1.0f, 1.0f)); + if (m.quad) { + m.quad->SetScaleMode(Quad::ScaleMode::AspectFit); + m.quad->SetBackgroundColor(vrb::Color(1.0f, 1.0f, 1.0f, 1.0f)); + } } void @@ -287,8 +382,10 @@ Widget::FinishResize() { } m.resizing = false; m.resizer->ToggleVisible(false); - m.quad->SetScaleMode(Quad::ScaleMode::Fill); - m.quad->SetBackgroundColor(vrb::Color(0.0f, 0.0f, 0.0f, 0.0f)); + if (m.quad) { + m.quad->SetScaleMode(Quad::ScaleMode::Fill); + m.quad->SetBackgroundColor(vrb::Color(0.0f, 0.0f, 0.0f, 0.0f)); + } } bool @@ -300,7 +397,14 @@ void Widget::HandleResize(const vrb::Vector& aPoint, bool aPressed, bool& aResized, bool &aResizeEnded) { m.resizer->HandleResizeGestures(aPoint, aPressed, aResized, aResizeEnded); if (aResized || aResizeEnded) { - m.quad->SetWorldSize(m.resizer->GetCurrentMin(), m.resizer->GetCurrentMax()); + + m.min = m.resizer->GetCurrentMin(); + m.max = m.resizer->GetCurrentMax(); + if (m.quad) { + m.quad->SetWorldSize(m.min, m.max); + } else if (m.cylinder) { + m.UpdateCylinderMatrix(); + } } } @@ -311,6 +415,14 @@ Widget::HoverExitResize() { } } +void +Widget::SetCylinderDensity(const float aDensity) { + m.cylinderDensity = aDensity; + if (m.cylinder) { + m.UpdateCylinderMatrix(); + } +} + 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 b2b215967..a36158704 100644 --- a/app/src/main/cpp/Widget.h +++ b/app/src/main/cpp/Widget.h @@ -9,6 +9,7 @@ #include "vrb/Forward.h" #include "vrb/MacroUtils.h" #include "vrb/Color.h" +#include "DeviceDelegate.h" #include #include @@ -17,12 +18,15 @@ namespace crow { +class Cylinder; +typedef std::shared_ptr CylinderPtr; + +class VRLayer; +typedef std::shared_ptr VRLayerPtr; + class Quad; typedef std::shared_ptr QuadPtr; -class VRLayerQuad; -typedef std::shared_ptr VRLayerQuadPtr; - class Widget; typedef std::shared_ptr WidgetPtr; @@ -31,9 +35,10 @@ typedef std::shared_ptr WidgetPlacementPtr; class Widget { public: - static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const int32_t aWidth, const int32_t aHeight, float aWorldWidth); - static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const VRLayerQuadPtr& aLayer, float aWorldWidth); - static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const int32_t aWidth, const int32_t aHeight, const vrb::Vector& aMin, const vrb::Vector& aMax); + static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, + const int32_t aTextureWidth, const int32_t aTextureHeight, const QuadPtr& aQuad); + static WidgetPtr Create(vrb::RenderContextPtr& aContext, const int aHandle, const float aWorldWidth, const float aWorldHeight, + const int32_t aTextureWidth, const int32_t aTextureHeight, const CylinderPtr& aCylinder); uint32_t GetHandle() const; void ResetFirstDraw(); const std::string& GetSurfaceTextureName() const; @@ -43,7 +48,7 @@ class Widget { void GetWidgetMinAndMax(vrb::Vector& aMin, vrb::Vector& aMax) const; void SetWorldWidth(float aWorldWidth) const; void GetWorldSize(float& aWidth, float& aHeight) const; - bool TestControllerIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, bool& aIsInWidget, float& aDistance) const; + bool TestControllerIntersection(const vrb::Vector& aStartPoint, const vrb::Vector& aDirection, vrb::Vector& aResult, vrb::Vector& aNormal, bool& aIsInWidget, float& aDistance) const; void ConvertToWidgetCoordinates(const vrb::Vector& aPoint, float& aX, float& aY) const; void ConvertToWorldCoordinates(const vrb::Vector& aPoint, vrb::Vector& aResult) const; const vrb::Matrix GetTransform() const; @@ -52,7 +57,8 @@ class Widget { bool IsVisible() const; vrb::NodePtr GetRoot() const; QuadPtr GetQuad() const; - const VRLayerQuadPtr& GetLayer() const; + CylinderPtr GetCylinder() const; + VRLayerSurfacePtr GetLayer() const; vrb::TransformPtr GetTransformNode() const; const WidgetPlacementPtr& GetPlacement() const; void SetPlacement(const WidgetPlacementPtr& aPlacement); @@ -61,6 +67,7 @@ class Widget { bool IsResizing() const; void HandleResize(const vrb::Vector& aPoint, bool aPressed, bool& aResized, bool &aResizeEnded); void HoverExitResize(); + void SetCylinderDensity(const float aDensity); protected: struct State; Widget(State& aState, vrb::RenderContextPtr& aContext); diff --git a/app/src/main/cpp/WidgetPlacement.cpp b/app/src/main/cpp/WidgetPlacement.cpp index 60d772c1d..128b1b8fe 100644 --- a/app/src/main/cpp/WidgetPlacement.cpp +++ b/app/src/main/cpp/WidgetPlacement.cpp @@ -53,6 +53,7 @@ WidgetPlacement::FromJava(JNIEnv* aEnv, jobject& aObject) { GET_BOOLEAN_FIELD(showPointer); GET_BOOLEAN_FIELD(firstDraw); GET_BOOLEAN_FIELD(layer); + GET_BOOLEAN_FIELD(cylinder); return result; } diff --git a/app/src/main/cpp/WidgetPlacement.h b/app/src/main/cpp/WidgetPlacement.h index 57a152722..7a8b37315 100644 --- a/app/src/main/cpp/WidgetPlacement.h +++ b/app/src/main/cpp/WidgetPlacement.h @@ -31,6 +31,7 @@ struct WidgetPlacement { bool showPointer; bool firstDraw; bool layer; + bool cylinder; static WidgetPlacementPtr FromJava(JNIEnv* aEnv, jobject& aObject); private: diff --git a/app/src/main/cpp/WidgetResizer.cpp b/app/src/main/cpp/WidgetResizer.cpp index 062758c68..d3f295df6 100644 --- a/app/src/main/cpp/WidgetResizer.cpp +++ b/app/src/main/cpp/WidgetResizer.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WidgetResizer.h" +#include "Widget.h" +#include "Cylinder.h" #include "Quad.h" #include "vrb/ConcreteClass.h" @@ -40,7 +42,8 @@ enum class ResizeState { }; -static void UpdateResizeMaterial(const vrb::GeometryPtr& aGeometry, ResizeState aState) { +template +static void UpdateResizeMaterial(const T& aTarget, ResizeState aState) { vrb::Color ambient(0.5f, 0.5f, 0.5f, 1.0f); vrb::Color diffuse = kDefaultColor; if (aState == ResizeState::Hovered) { @@ -49,33 +52,53 @@ static void UpdateResizeMaterial(const vrb::GeometryPtr& aGeometry, ResizeState diffuse = kActiveColor; } - aGeometry->GetRenderState()->SetMaterial(ambient, diffuse, vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); + aTarget->SetMaterial(ambient, diffuse, vrb::Color(0.0f, 0.0f, 0.0f), 0.0f); } struct ResizeBar { - static ResizeBarPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aCenter, const vrb::Vector& aScale) { + enum class Mode { + Quad, + Cylinder + }; + static ResizeBarPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aCenter, const vrb::Vector& aScale, const ResizeBar::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->geometry = Quad::CreateGeometry(aContext, -max, max); - result->geometry->GetRenderState()->SetLightsEnabled(false); result->transform = vrb::Transform::Create(aContext); - result->transform->AddNode(result->geometry); + if (aMode == ResizeBar::Mode::Cylinder) { + result->cylinder = Cylinder::Create(aContext, 1.0f, kBarSize); + result->cylinder->SetLightsEnabled(false); + result->transform->AddNode(result->cylinder->GetRoot()); + } else { + result->geometry = Quad::CreateGeometry(aContext, -max, max); + result->geometry->GetRenderState()->SetLightsEnabled(false); + result->transform->AddNode(result->geometry); + } + result->resizeState = ResizeState::Default; - UpdateResizeMaterial(result->geometry, result->resizeState); + result->UpdateMaterial(); return result; } void SetResizeState(ResizeState aState) { if (resizeState != aState) { resizeState = aState; - UpdateResizeMaterial(geometry, resizeState); + UpdateMaterial(); + } + } + + void UpdateMaterial() { + if (cylinder) { + UpdateResizeMaterial(cylinder, resizeState); + } else { + UpdateResizeMaterial(geometry->GetRenderState(), resizeState); } } vrb::Vector center; vrb::Vector scale; + CylinderPtr cylinder; vrb::GeometryPtr geometry; vrb::TransformPtr transform; ResizeState resizeState; @@ -102,14 +125,14 @@ struct ResizeHandle { result->transform = vrb::Transform::Create(aContext); result->transform->AddNode(result->geometry); result->resizeState = ResizeState ::Default; - UpdateResizeMaterial(result->geometry, result->resizeState); + UpdateResizeMaterial(result->geometry->GetRenderState(), result->resizeState); return result; } void SetResizeState(ResizeState aState) { if (resizeState != aState) { resizeState = aState; - UpdateResizeMaterial(geometry, resizeState); + UpdateResizeMaterial(geometry->GetRenderState(), resizeState); } for (const ResizeBarPtr& bar: attachedBars) { @@ -168,12 +191,13 @@ struct ResizeHandle { struct WidgetResizer::State { vrb::CreationContextWeak context; + Widget * widget; vrb::Vector min; vrb::Vector max; vrb::Vector resizeStartMin; vrb::Vector resizeStartMax; - vrb::Vector defaultMin; - vrb::Vector defaultMax; + vrb::Vector currentMin; + vrb::Vector currentMax; vrb::Vector pointerOffset; bool resizing; vrb::TogglePtr root; @@ -183,7 +207,8 @@ struct WidgetResizer::State { bool wasPressed; State() - : resizing(false) + : widget(nullptr) + , resizing(false) , wasPressed(false) {} @@ -193,17 +218,20 @@ struct WidgetResizer::State { return; } root = vrb::Toggle::Create(create); + currentMin = min; + currentMax = max; vrb::Vector horizontalSize(0.0f, 0.5f, 0.0f); vrb::Vector verticalSize(0.5f, 0.0f, 0.0f); - ResizeBarPtr leftTop = CreateResizeBar(vrb::Vector(0.0f, 0.75f, 0.0f), horizontalSize); - ResizeBarPtr leftBottom = CreateResizeBar(vrb::Vector(0.0f, 0.25f, 0.0f), horizontalSize); - ResizeBarPtr rightTop = CreateResizeBar(vrb::Vector(1.0f, 0.75f, 0.0f), horizontalSize); - ResizeBarPtr rightBottom = CreateResizeBar(vrb::Vector(1.0f, 0.25f, 0.0f), horizontalSize); - ResizeBarPtr topLeft = CreateResizeBar(vrb::Vector(0.25f, 1.0f, 0.0f), verticalSize); - ResizeBarPtr topRight = CreateResizeBar(vrb::Vector(0.75f, 1.0f, 0.0f), verticalSize); - ResizeBarPtr bottomLeft = CreateResizeBar(vrb::Vector(0.25f, 0.0f, 0.0f), verticalSize); - ResizeBarPtr bottomRight = CreateResizeBar(vrb::Vector(0.75f, 0.0f, 0.0f), verticalSize); + ResizeBar::Mode mode = widget->GetCylinder() ? ResizeBar::Mode::Cylinder : ResizeBar::Mode::Quad; + ResizeBarPtr leftTop = CreateResizeBar(vrb::Vector(0.0f, 0.75f, 0.0f), horizontalSize, ResizeBar::Mode::Quad); + ResizeBarPtr leftBottom = CreateResizeBar(vrb::Vector(0.0f, 0.25f, 0.0f), horizontalSize, ResizeBar::Mode::Quad); + ResizeBarPtr rightTop = CreateResizeBar(vrb::Vector(1.0f, 0.75f, 0.0f), horizontalSize, ResizeBar::Mode::Quad); + ResizeBarPtr rightBottom = CreateResizeBar(vrb::Vector(1.0f, 0.25f, 0.0f), horizontalSize, ResizeBar::Mode::Quad); + ResizeBarPtr topLeft = CreateResizeBar(vrb::Vector(0.25f, 1.0f, 0.0f), verticalSize, mode); + ResizeBarPtr topRight = CreateResizeBar(vrb::Vector(0.75f, 1.0f, 0.0f), verticalSize, mode); + ResizeBarPtr bottomLeft = CreateResizeBar(vrb::Vector(0.25f, 0.0f, 0.0f), verticalSize, mode); + ResizeBarPtr bottomRight = CreateResizeBar(vrb::Vector(0.75f, 0.0f, 0.0f), verticalSize, mode); CreateResizeHandle(vrb::Vector(0.0f, 1.0f, 0.0f), ResizeHandle::ResizeMode::Both, {leftTop, topLeft}); CreateResizeHandle(vrb::Vector(1.0f, 1.0f, 0.0f), ResizeHandle::ResizeMode::Both, {rightTop, topRight}); @@ -217,12 +245,12 @@ struct WidgetResizer::State { Layout(); } - ResizeBarPtr CreateResizeBar(const vrb::Vector& aCenter, vrb::Vector aScale) { + ResizeBarPtr CreateResizeBar(const vrb::Vector& aCenter, vrb::Vector aScale, const ResizeBar::Mode aMode) { vrb::CreationContextPtr create = context.lock(); if (!create) { return nullptr; } - ResizeBarPtr result = ResizeBar::Create(create, aCenter, aScale); + ResizeBarPtr result = ResizeBar::Create(create, aCenter, aScale, aMode); resizeBars.push_back(result); root->AddNode(result->transform); return result; @@ -248,8 +276,26 @@ struct WidgetResizer::State { return max.y() - min.y(); } + vrb::Vector ProjectPoint(const vrb::Vector& aWorldPoint) const { + vrb::Matrix modelView = widget->GetTransformNode()->GetWorldTransform().AfineInverse(); + if (widget->GetCylinder()) { + // Map the position in the cylinder to the position it would have on a quad + const float radius = widget->GetCylinder()->GetTransformNode()->GetTransform().GetScale().x(); + float cosAngle = fminf(1.0f, fabsf(aWorldPoint.x()) / radius); + const float sign = aWorldPoint.x() > 0 ? 1.0f : -1.0f; + const float angle = acosf(cosAngle); + const float surfaceArc = (float)M_PI - angle * 2.0f; + const float projectedWidth = WorldWidth() * surfaceArc / widget->GetCylinder()->GetCylinderTheta(); + vrb::Vector point(projectedWidth * 0.5f * sign, aWorldPoint.y(), aWorldPoint.z()); + vrb::Vector result = modelView.MultiplyPosition(point); + result.z() = 0.0f; + return result; + } else { + return modelView.MultiplyPosition(aWorldPoint); + } + } - void Layout() { + void LayoutQuad() { const float width = WorldWidth(); const float height = WorldHeight(); @@ -267,6 +313,55 @@ struct WidgetResizer::State { } } + void LayoutCylinder() { + const float width = currentMax.x() - currentMin.x(); + const float height = currentMax.y() - currentMin.y(); + const float sx = width / WorldWidth(); + const float radius = widget->GetCylinder()->GetTransformNode()->GetTransform().GetScale().x() - kBarSize * 0.5f; + const float theta = widget->GetCylinder()->GetCylinderTheta() * sx; + int32_t textureWidth, textureHeight; + widget->GetCylinder()->GetTextureSize(textureWidth, textureHeight); + vrb::Matrix modelView = widget->GetTransformNode()->GetWorldTransform().AfineInverse(); + + for (ResizeBarPtr& bar: resizeBars) { + float targetWidth = bar->scale.x() > 0.0f ? (bar->scale.x() * fabsf(width)) + kBarSize : kBarSize; + float targetHeight = bar->scale.y() > 0.0f ? (bar->scale.y() * fabs(height)) + kBarSize : kBarSize; + const float pointerAngle = (float)M_PI * 0.5f + theta * 0.5f - theta * bar->center.x(); + vrb::Matrix rotation = vrb::Matrix::Rotation(vrb::Vector(-cosf(pointerAngle), 0.0f, sinf(pointerAngle))); + if (bar->cylinder) { + bar->cylinder->SetCylinderTheta(theta * 0.5f); + 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)); + } 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)); + } + } + + for (ResizeHandlePtr& handle: resizeHandles) { + const float pointerAngle = (float)M_PI * 0.5f + theta * 0.5f - theta * handle->center.x(); + vrb::Matrix translation = vrb::Matrix::Position(vrb::Vector(radius * cosf(pointerAngle), + min.y() + height * handle->center.y(), + radius - radius * sinf(pointerAngle))); + vrb::Matrix rotation = vrb::Matrix::Rotation(vrb::Vector(-cosf(pointerAngle), 0.0f, sinf(pointerAngle))); + handle->transform->SetTransform(translation.PostMultiply(rotation)); + } + } + + void Layout() { + if (widget->GetCylinder()) { + LayoutCylinder(); + } else { + LayoutQuad(); + } + } + ResizeHandlePtr GetIntersectingHandler(const vrb::Vector& point) { for (const ResizeHandlePtr& handle: resizeHandles) { vrb::Vector worldCenter(min.x() + WorldWidth() * handle->center.x(), min.y() + WorldHeight() * handle->center.y(), 0.0f); @@ -310,19 +405,24 @@ struct WidgetResizer::State { height = width / originalAspect; } + currentMin = vrb::Vector(-width * 0.5f, -height * 0.5f, 0.0f); + currentMax = vrb::Vector(width * 0.5f, height * 0.5f, 0.0f); + // Reset world min and max points with the new resize values - min = vrb::Vector(-width * 0.5f, -height * 0.5f, 0.0f); - max = vrb::Vector(width * 0.5f, height * 0.5f, 0.0f); + if (!widget->GetCylinder() || keepAspect) { + min = currentMin; + max = currentMax; + } Layout(); } }; WidgetResizerPtr -WidgetResizer::Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aMin, const vrb::Vector& aMax) { +WidgetResizer::Create(vrb::CreationContextPtr& aContext, Widget * aWidget) { WidgetResizerPtr result = std::make_shared >(aContext); - result->m.min = aMin; - result->m.max = aMax; + aWidget->GetWidgetMinAndMax(result->m.min, result->m.max); + result->m.widget = aWidget; result->m.Initialize(); return result; } @@ -337,6 +437,8 @@ void WidgetResizer::SetSize(const vrb::Vector& aMin, const vrb::Vector& aMax) { m.min = aMin; m.max = aMax; + m.currentMin = aMin; + m.currentMax = aMax; m.Layout(); } @@ -346,10 +448,14 @@ WidgetResizer::ToggleVisible(bool aVisible) { } bool -WidgetResizer::TestIntersection(const vrb::Vector& point) const { +WidgetResizer::TestIntersection(const vrb::Vector& aWorldPoint) const { if (m.activeHandle) { return true; } + const vrb::Vector point = m.ProjectPoint(aWorldPoint); + if (m.widget->GetCylinder()) { + //point = + } vrb::Vector extraMin = vrb::Vector(m.min.x() - kBarSize * 0.5f, m.min.y() - kBarSize * 0.5f, 0.0f); vrb::Vector extraMax = vrb::Vector(m.max.x() + kBarSize * 0.5f, m.max.y() + kBarSize * 0.5f, 0.0f); @@ -363,7 +469,8 @@ WidgetResizer::TestIntersection(const vrb::Vector& point) const { } void -WidgetResizer::HandleResizeGestures(const vrb::Vector& aPoint, bool aPressed, bool& aResized, bool &aResizeEnded) { +WidgetResizer::HandleResizeGestures(const vrb::Vector& aWorldPoint, bool aPressed, bool& aResized, bool &aResizeEnded) { + const vrb::Vector point = m.ProjectPoint(aWorldPoint); for (const ResizeHandlePtr& handle: m.resizeHandles) { handle->SetResizeState(ResizeState::Default); } @@ -372,29 +479,34 @@ WidgetResizer::HandleResizeGestures(const vrb::Vector& aPoint, bool aPressed, bo if (aPressed && !m.wasPressed) { // Handle resize handle click - m.activeHandle = m.GetIntersectingHandler(aPoint); + m.activeHandle = m.GetIntersectingHandler(point); if (m.activeHandle) { m.resizeStartMin = m.min; m.resizeStartMax = m.max; + m.currentMin = m.min; + m.currentMax = m.max; m.activeHandle->SetResizeState(ResizeState::Active); - vrb::Vector center = m.activeHandle->transform->GetTransform().GetTranslation(); - m.pointerOffset = aPoint - center; + vrb::Vector center(m.min.x() + m.WorldWidth() * m.activeHandle->center.x(), + m.min.y() + m.WorldHeight() * m.activeHandle->center.y(), 0.0f); + m.pointerOffset = point - center; } } else if (!aPressed && m.wasPressed) { // Handle resize handle unclick if (m.activeHandle) { m.activeHandle->SetResizeState(ResizeState::Hovered); + m.min = m.currentMin; + m.max = m.currentMax; aResizeEnded = true; } m.activeHandle.reset(); } else if (aPressed && m.activeHandle) { // Handle resize gesture m.activeHandle->SetResizeState(ResizeState::Active); - m.HandleResize(aPoint); + m.HandleResize(point); aResized = true; } else if (!aPressed) { // Handle hover - ResizeHandlePtr handle = m.GetIntersectingHandler(aPoint); + ResizeHandlePtr handle = m.GetIntersectingHandler(point); if (handle) { handle->SetResizeState(ResizeState::Hovered); } diff --git a/app/src/main/cpp/WidgetResizer.h b/app/src/main/cpp/WidgetResizer.h index 9415ee26f..35563af7d 100644 --- a/app/src/main/cpp/WidgetResizer.h +++ b/app/src/main/cpp/WidgetResizer.h @@ -16,12 +16,13 @@ namespace crow { +class Widget; class WidgetResizer; typedef std::shared_ptr WidgetResizerPtr; class WidgetResizer { public: - static WidgetResizerPtr Create(vrb::CreationContextPtr& aContext, const vrb::Vector& aMin, const vrb::Vector& aMax); + static WidgetResizerPtr Create(vrb::CreationContextPtr& aContext, Widget * aWidget); vrb::NodePtr GetRoot() const; void SetSize(const vrb::Vector& aMin, const vrb::Vector& aMax); void ToggleVisible(bool aVisible); diff --git a/app/src/main/cpp/vrb b/app/src/main/cpp/vrb index 01c7f9e5d..a4d9785db 160000 --- a/app/src/main/cpp/vrb +++ b/app/src/main/cpp/vrb @@ -1 +1 @@ -Subproject commit 01c7f9e5d24adcc48f4231ea0243a0b775a3c935 +Subproject commit a4d9785dbd3fda9193326feaa0e107f583fc678c diff --git a/app/src/main/res/layout/curvature_controls.xml b/app/src/main/res/layout/curvature_controls.xml new file mode 100644 index 000000000..dce8061a5 --- /dev/null +++ b/app/src/main/res/layout/curvature_controls.xml @@ -0,0 +1,30 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/options_display.xml b/app/src/main/res/layout/options_display.xml index 8404c7a92..2f818155d 100644 --- a/app/src/main/res/layout/options_display.xml +++ b/app/src/main/res/layout/options_display.xml @@ -45,6 +45,12 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + settings_gfx_msaa settings_audio settings_voice_search_language + settings_cylinder_density https://support.mozilla.org/kb/private-mode-firefox-reality settings_browser_world_width settings_browser_world_height diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b4eee2ad0..1d9223818 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,6 +162,10 @@ from being restarted. --> Restart Later + + Enable Curved Display + Enable Remote Debugging diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp index 2abaebf6c..423c5df22 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp @@ -114,22 +114,44 @@ struct OculusEyeSwapChain { } }; -template + +class OculusLayer; +typedef std::shared_ptr OculusLayerPtr; + class OculusLayer { +public: + virtual void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) = 0; + virtual void Update(const ovrTracking2& aTracking) = 0; + virtual ovrTextureSwapChain * GetSwapChain() const = 0; + virtual const ovrLayerHeader2 * Header() const = 0; + virtual void SetCurrentEye(device::Eye aEye) = 0; + virtual bool IsDrawRequested() const = 0; + virtual bool GetDrawInFront() const = 0; + virtual void ClearRequestDraw() = 0; + virtual bool IsComposited() const = 0; + virtual VRLayerPtr GetLayer() const = 0; + virtual void Destroy() = 0; + typedef std::function BindDelegate; + virtual void SetBindDelegate(const BindDelegate& aDelegate) = 0; + virtual ~OculusLayer() {} +}; + +template +class OculusLayerBase: public OculusLayer { public: ovrTextureSwapChain * swapChain = nullptr; bool composited = false; T layer; U ovrLayer; - void Init() { + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { layer->SetInitialized(true); layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { composited = true; }); } - virtual void Update(const ovrTracking2& aTracking) { + virtual void Update(const ovrTracking2& aTracking) override{ vrb::Color tintColor = layer->GetTintColor(); ovrLayer.Header.ColorScale.x = tintColor.Red(); ovrLayer.Header.ColorScale.y = tintColor.Green(); @@ -137,24 +159,38 @@ class OculusLayer { ovrLayer.Header.ColorScale.w = tintColor.Alpha(); } - virtual const ovrLayerHeader2 * Header() const = 0; + virtual ovrTextureSwapChain * GetSwapChain() const override { + return swapChain; + } - void SetCurrentEye(device::Eye aEye) { + const ovrLayerHeader2 * Header() const override { + return &ovrLayer.Header; + } + + void SetCurrentEye(device::Eye aEye) override { layer->SetCurrentEye(aEye); } - virtual bool IsDrawRequested() const { + virtual bool IsDrawRequested() const override { return swapChain && composited && layer->IsDrawRequested(); } - bool GetDrawInFront() const { + bool GetDrawInFront() const override { return layer->GetDrawInFront(); } - void ClearRequestDraw() const { + void ClearRequestDraw() override { layer->ClearRequestDraw(); } + bool IsComposited() const override { + return composited; + } + + VRLayerPtr GetLayer() const override { + return layer; + } + void SetClipEnabled(bool aEnabled) { if (aEnabled) { ovrLayer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT; @@ -163,8 +199,7 @@ class OculusLayer { } } - - void Destroy() { + void Destroy() override { if (swapChain != nullptr) { vrapi_DestroyTextureSwapChain(swapChain); swapChain = nullptr; @@ -174,91 +209,40 @@ class OculusLayer { layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Destroy, nullptr); } - virtual ~OculusLayer() { - Destroy(); - } + void SetBindDelegate(const BindDelegate& aDelegate) override {} + virtual ~OculusLayerBase() {} }; -class OculusLayerQuad; -typedef std::shared_ptr OculusLayerQuadPtr; -class OculusLayerQuad: public OculusLayer { +template +class OculusLayerSurface: public OculusLayerBase { public: jobject surface = nullptr; vrb::FBOPtr fbo; vrb::RenderContextWeak contextWeak; JNIEnv * jniEnv = nullptr; + OculusLayer::BindDelegate bindDelegate; - static OculusLayerQuadPtr Create(const VRLayerQuadPtr& aLayer) { - auto result = std::make_shared(); - result->layer = aLayer; - return result; - } - - void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) { - if (swapChain) { + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { + if (this->swapChain) { return; } - jniEnv = aEnv; - contextWeak = aContext; - - ovrLayer = vrapi_DefaultLayerProjection2(); - ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; - ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; + this->jniEnv = aEnv; + this->contextWeak = aContext; + this->ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; + this->ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; - InitSwapChain(swapChain, surface, fbo); - layer->SetResizeDelegate([=]{ + InitSwapChain(this->swapChain, this->surface, this->fbo); + this->layer->SetResizeDelegate([=]{ Resize(); }); - OculusLayer::Init(); - } - - void Destroy(JNIEnv * aEnv) { - fbo = nullptr; - if (surface) { - aEnv->DeleteGlobalRef(surface); - surface = nullptr; - layer->SetSurface(nullptr); - } - OculusLayer::Destroy(); - } - - void Update(const ovrTracking2& aTracking) override { - OculusLayer::Update(aTracking); - const float w = layer->GetWorldWidth(); - const float h = layer->GetWorldHeight(); - - vrb::Matrix scale = vrb::Matrix::Identity(); - scale.ScaleInPlace(vrb::Vector(w * 0.5f, h * 0.5f, 1.0f)); - - bool clip = false; - - for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { - device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; - vrb::Matrix matrix = layer->GetModelView(eye); - matrix.PostMultiplyInPlace(scale); - ovrMatrix4f modelView = ovrMatrixFrom(matrix); - - device::EyeRect textureRect = layer->GetTextureRect(eye); - - ovrLayer.Textures[i].ColorSwapChain = swapChain; - ovrLayer.Textures[i].SwapChainIndex = 0; - ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromUnitSquare(&modelView); - ovrLayer.Textures[i].TextureRect.x = textureRect.mX; - ovrLayer.Textures[i].TextureRect.y = textureRect.mY; - ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; - ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; - clip = clip || !textureRect.IsDefault(); - } - SetClipEnabled(clip); - - ovrLayer.HeadPose = aTracking.HeadPose; + OculusLayerBase::Init(aEnv, aContext); } void Resize() { - if (!swapChain) { + if (!this->swapChain) { return; } // Delay the destruction of the current swapChain until the new one is composited. @@ -267,36 +251,51 @@ class OculusLayerQuad: public OculusLayer { jobject newSurface = nullptr; vrb::FBOPtr newFBO; InitSwapChain(newSwapChain, newSurface, newFBO); - layer->SetSurface(newSurface); - layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { - if (swapChain) { - vrapi_DestroyTextureSwapChain(swapChain); + this->layer->SetSurface(newSurface); + this->layer->NotifySurfaceChanged(VRLayer::SurfaceChange::Create, [=]() { + if (this->swapChain) { + vrapi_DestroyTextureSwapChain(this->swapChain); } - if (surface) { - jniEnv->DeleteGlobalRef(surface); + if (this->surface) { + jniEnv->DeleteGlobalRef(this->surface); } - swapChain = newSwapChain; - surface = newSurface; - fbo = newFBO; - composited = true; + this->swapChain = newSwapChain; + this->surface = newSurface; + this->fbo = newFBO; + this->composited = true; }); } - const ovrLayerHeader2 * Header() const override { - return &ovrLayer.Header; + void Destroy() override { + this->fbo = nullptr; + if (this->surface) { + this->jniEnv->DeleteGlobalRef(surface); + this->surface = nullptr; + this->layer->SetSurface(nullptr); + } + OculusLayerBase::Destroy(); + } + + void SetBindDelegate(const OculusLayer::BindDelegate& aDelegate) override { + bindDelegate = aDelegate; + this->layer->SetBindDelegate([=](GLenum aTarget, bool aBind) { + if (bindDelegate) { + bindDelegate(this->fbo, aTarget, aBind); + } + }); } private: void InitSwapChain(ovrTextureSwapChain*& swapChainOut, jobject & surfaceOut, vrb::FBOPtr& fboOut) { - if (layer->GetSurfaceType() == VRLayerQuad::SurfaceType::AndroidSurface) { - swapChainOut = vrapi_CreateAndroidSurfaceSwapChain(layer->GetWidth(), layer->GetHeight()); + if (this->layer->GetSurfaceType() == VRLayerQuad::SurfaceType::AndroidSurface) { + swapChainOut = vrapi_CreateAndroidSurfaceSwapChain(this->layer->GetWidth(), this->layer->GetHeight()); surfaceOut = vrapi_GetTextureSwapChainAndroidSurface(swapChainOut); - surfaceOut = jniEnv->NewGlobalRef(surfaceOut); - layer->SetSurface(surface); + surfaceOut = this->jniEnv->NewGlobalRef(surfaceOut); + this->layer->SetSurface(surface); } else { swapChainOut = vrapi_CreateTextureSwapChain(VRAPI_TEXTURE_TYPE_2D, VRAPI_TEXTURE_FORMAT_8888, - layer->GetWidth(), layer->GetHeight(), 1, false); - vrb::RenderContextPtr ctx = contextWeak.lock(); + this->layer->GetWidth(), this->layer->GetHeight(), 1, false); + vrb::RenderContextPtr ctx = this->contextWeak.lock(); fboOut = vrb::FBO::Create(ctx); GLuint texture = vrapi_GetTextureSwapChainHandle(swapChainOut, 0); VRB_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture)); @@ -307,24 +306,120 @@ class OculusLayerQuad: public OculusLayer { vrb::FBO::Attributes attributes; attributes.depth = false; attributes.samples = 0; - VRB_GL_CHECK(fboOut->SetTextureHandle(texture, layer->GetWidth(), layer->GetHeight(), attributes)); + VRB_GL_CHECK(fboOut->SetTextureHandle(texture, this->layer->GetWidth(), this->layer->GetHeight(), attributes)); if (fboOut->IsValid()) { fboOut->Bind(); VRB_GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); VRB_GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); fboOut->Unbind(); } else { - VRB_WARN("FAILED to make valid FBO for OculusLayerQuad"); + VRB_WARN("FAILED to make valid FBO for OculusLayerSurface"); } } } }; +class OculusLayerQuad; +typedef std::shared_ptr OculusLayerQuadPtr; + +class OculusLayerQuad: public OculusLayerSurface { +public: + static OculusLayerQuadPtr Create(const VRLayerQuadPtr& aLayer) { + auto result = std::make_shared(); + result->layer = aLayer; + return result; + } + + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { + ovrLayer = vrapi_DefaultLayerProjection2(); + OculusLayerSurface::Init(aEnv, aContext); + } + + void Update(const ovrTracking2& aTracking) override { + OculusLayerSurface::Update(aTracking); + const float w = layer->GetWorldWidth(); + const float h = layer->GetWorldHeight(); + + vrb::Matrix scale = vrb::Matrix::Identity(); + scale.ScaleInPlace(vrb::Vector(w * 0.5f, h * 0.5f, 1.0f)); + + bool clip = false; + + for (int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; ++i) { + device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; + vrb::Matrix matrix = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); + matrix.PostMultiplyInPlace(scale); + ovrMatrix4f modelView = ovrMatrixFrom(matrix); + + device::EyeRect textureRect = layer->GetTextureRect(eye); + + ovrLayer.Textures[i].ColorSwapChain = swapChain; + ovrLayer.Textures[i].SwapChainIndex = 0; + ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromUnitSquare(&modelView); + ovrLayer.Textures[i].TextureRect.x = textureRect.mX; + ovrLayer.Textures[i].TextureRect.y = textureRect.mY; + ovrLayer.Textures[i].TextureRect.width = textureRect.mWidth; + ovrLayer.Textures[i].TextureRect.height = textureRect.mHeight; + clip = clip || !textureRect.IsDefault(); + } + SetClipEnabled(clip); + + ovrLayer.HeadPose = aTracking.HeadPose; + } +}; + +class OculusLayerCylinder; +typedef std::shared_ptr OculusLayerCylinderPtr; + +class OculusLayerCylinder: public OculusLayerSurface { +public: + static OculusLayerCylinderPtr Create(const VRLayerCylinderPtr& aLayer) { + auto result = std::make_shared(); + result->layer = aLayer; + return result; + } + + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { + ovrLayer = vrapi_DefaultLayerCylinder2(); + OculusLayerSurface::Init(aEnv, aContext); + } + + void Update(const ovrTracking2& aTracking) override { + OculusLayerSurface::Update(aTracking); + const float w = layer->GetWorldWidth(); + const float h = layer->GetWorldHeight(); + + ovrLayer.HeadPose = aTracking.HeadPose; + ovrLayer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE; + ovrLayer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA; + + for ( int i = 0; i < VRAPI_FRAME_LAYER_EYE_MAX; i++ ) { + device::Eye eye = i == 0 ? device::Eye::Left : device::Eye::Right; + vrb::Matrix modelView = layer->GetView(eye).PostMultiply(layer->GetModelTransform(eye)); + ovrMatrix4f matrix = ovrMatrixFrom(modelView); + ovrLayer.Textures[i].TexCoordsFromTanAngles = ovrMatrix4f_Inverse(&matrix); + ovrLayer.Textures[i].ColorSwapChain = swapChain; + ovrLayer.Textures[i].SwapChainIndex = 0; + + const vrb::Vector scale = layer->GetUVTransform(eye).GetScale(); + const vrb::Vector translation = layer->GetUVTransform(eye).GetTranslation(); + + ovrLayer.Textures[i].TextureMatrix.M[0][0] = scale.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][1] = scale.y(); + ovrLayer.Textures[i].TextureMatrix.M[0][2] = translation.x(); + ovrLayer.Textures[i].TextureMatrix.M[1][2] = translation.y(); + + ovrLayer.Textures[i].TextureRect.width = 1.0f; + ovrLayer.Textures[i].TextureRect.height = 1.0f; + } + } +}; + class OculusLayerCube; typedef std::shared_ptr OculusLayerCubePtr; -class OculusLayerCube: public OculusLayer { +class OculusLayerCube: public OculusLayerBase { public: static OculusLayerCubePtr Create(const VRLayerCubePtr& aLayer, GLint aInternalFormat) { auto result = std::make_shared(); @@ -333,7 +428,7 @@ class OculusLayerCube: public OculusLayer { return result; } - void Init() { + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { if (swapChain) { return; } @@ -344,16 +439,16 @@ class OculusLayerCube: public OculusLayer { ovrLayer.Offset.z = 0.0f; swapChain = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_CUBE, glFormat, layer->GetWidth(), layer->GetHeight(), 1, 1); layer->SetTextureHandle(vrapi_GetTextureSwapChainHandle(swapChain, 0)); - OculusLayer::Init(); + OculusLayerBase::Init(aEnv, aContext); } - void Destroy() { + void Destroy() override { if (swapChain == nullptr) { return; } layer->SetTextureHandle(0); layer->SetLoaded(false); - OculusLayer::Destroy(); + OculusLayerBase::Destroy(); } bool IsLoaded() const { @@ -361,7 +456,7 @@ class OculusLayerCube: public OculusLayer { } void Update(const ovrTracking2& aTracking) override { - OculusLayer::Update(aTracking); + OculusLayerBase::Update(aTracking); const ovrMatrix4f centerEyeViewMatrix = vrapi_GetViewMatrixFromPose(&aTracking.HeadPose.Pose); const ovrMatrix4f cubeMatrix = ovrMatrix4f_TanAngleMatrixForCubeMap(¢erEyeViewMatrix); ovrLayer.HeadPose = aTracking.HeadPose; @@ -373,9 +468,6 @@ class OculusLayerCube: public OculusLayer { } } - const ovrLayerHeader2 * Header() const override { - return &ovrLayer.Header; - } protected: GLint glFormat; }; @@ -384,24 +476,24 @@ class OculusLayerCube: public OculusLayer { class OculusLayerEquirect; typedef std::shared_ptr OculusLayerEquirectPtr; -class OculusLayerEquirect: public OculusLayer { +class OculusLayerEquirect: public OculusLayerBase { public: - std::weak_ptr sourceLayer; + std::weak_ptr sourceLayer; - static OculusLayerEquirectPtr Create(const VRLayerEquirectPtr& aLayer, const OculusLayerQuadPtr& aSourceLayer) { + static OculusLayerEquirectPtr Create(const VRLayerEquirectPtr& aLayer, const OculusLayerPtr& aSourceLayer) { auto result = std::make_shared(); result->layer = aLayer; result->sourceLayer = aSourceLayer; return result; } - void Init() { - OculusLayerQuadPtr source = sourceLayer.lock(); + void Init(JNIEnv * aEnv, vrb::RenderContextPtr& aContext) override { + OculusLayerPtr source = sourceLayer.lock(); if (!source) { return; } - swapChain = source->swapChain; + swapChain = source->GetSwapChain(); ovrLayer = vrapi_DefaultLayerEquirect2(); ovrLayer.HeadPose.Pose.Position.x = 0.0f; ovrLayer.HeadPose.Pose.Position.y = 0.0f; @@ -411,25 +503,25 @@ class OculusLayerEquirect: public OculusLayer::Init(aEnv, aContext); } - void Destroy() { + void Destroy() override { swapChain = nullptr; - OculusLayer::Destroy(); + OculusLayerBase::Destroy(); } bool IsDrawRequested() const override { - OculusLayerQuadPtr source = sourceLayer.lock(); - return source && source->swapChain && source->composited && layer->IsDrawRequested(); + OculusLayerPtr source = sourceLayer.lock(); + return source && source->GetSwapChain() && source->IsComposited() && layer->IsDrawRequested(); } void Update(const ovrTracking2& aTracking) override { - OculusLayerQuadPtr source = sourceLayer.lock(); + OculusLayerPtr source = sourceLayer.lock(); if (source) { - swapChain = source->swapChain; + swapChain = source->GetSwapChain(); } - OculusLayer::Update(aTracking); + OculusLayerBase::Update(aTracking); vrb::Quaternion q(layer->GetModelTransform(device::Eye::Left)); ovrLayer.HeadPose.Pose.Orientation.x = q.x(); @@ -459,10 +551,6 @@ class OculusLayerEquirect: public OculusLayer uiLayers; + std::vector uiLayers; device::RenderMode renderMode = device::RenderMode::StandAlone; vrb::FBOPtr currentFBO; vrb::FBOPtr previousFBO; @@ -563,6 +651,24 @@ struct DeviceDelegateOculusVR::State { vrapi_SetPropertyInt(&java, VRAPI_REORIENT_HMD_ON_CONTROLLER_RECENTER, 1); } + void AddUILayer(const OculusLayerPtr& aLayer, VRLayerSurface::SurfaceType aSurfaceType) { + if (ovr) { + vrb::RenderContextPtr ctx = context.lock(); + aLayer->Init(java.Env, ctx); + } + uiLayers.push_back(aLayer); + if (aSurfaceType == VRLayerSurface::SurfaceType::FBO) { + aLayer->SetBindDelegate([=](const vrb::FBOPtr& aFBO, GLenum aTarget, bool bound){ + if (aFBO) { + HandleQuadLayerBind(aFBO, aTarget, bound); + } + }); + if (currentFBO) { + currentFBO->Bind(); + } + } + } + void GetImmersiveRenderSize(uint32_t& aWidth, uint32_t& aHeight) { aWidth = (uint32_t)(vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH)); aHeight = (uint32_t)(vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT)); @@ -777,9 +883,9 @@ struct DeviceDelegateOculusVR::State { } } - void HandleQuadLayerBind(const OculusLayerQuadPtr& aLayer, GLenum aTarget, bool bound) { + void HandleQuadLayerBind(const vrb::FBOPtr& aFBO, GLenum aTarget, bool bound) { if (!bound) { - if (currentFBO && currentFBO == aLayer->fbo) { + if (currentFBO && currentFBO == aFBO) { currentFBO->Unbind(); currentFBO = nullptr; } @@ -791,7 +897,7 @@ struct DeviceDelegateOculusVR::State { return; } - if (currentFBO == aLayer->fbo) { + if (currentFBO == aFBO) { // Layer already bound return; } @@ -800,8 +906,8 @@ struct DeviceDelegateOculusVR::State { currentFBO->Unbind(); } previousFBO = currentFBO; - aLayer->fbo->Bind(aTarget); - currentFBO = aLayer->fbo; + aFBO->Bind(aTarget); + currentFBO = aFBO; } }; @@ -1015,7 +1121,7 @@ DeviceDelegateOculusVR::BindEye(const device::Eye aWhich) { VRB_LOG("No Swap chain FBO found"); } - for (const OculusLayerQuadPtr& layer: m.uiLayers) { + for (const OculusLayerPtr& layer: m.uiLayers) { layer->SetCurrentEye(aWhich); } } @@ -1051,12 +1157,12 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { } // Sort quad layers by draw priority - std::sort(m.uiLayers.begin(), m.uiLayers.end(), [](const OculusLayerQuadPtr & a, OculusLayerQuadPtr & b) -> bool { - return a->layer->ShouldDrawBefore(*b->layer); + std::sort(m.uiLayers.begin(), m.uiLayers.end(), [](const OculusLayerPtr & a, OculusLayerPtr & b) -> bool { + return a->GetLayer()->ShouldDrawBefore(*b->GetLayer()); }); // Draw back layers - for (const OculusLayerQuadPtr& layer: m.uiLayers) { + for (const OculusLayerPtr& layer: m.uiLayers) { if (!layer->GetDrawInFront() && layer->IsDrawRequested() && layerCount < ovrMaxLayerCount) { layer->Update(m.predictedTracking); layers[layerCount++] = layer->Header(); @@ -1084,7 +1190,7 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { layers[layerCount++] = &projection.Header; // Draw front layers - for (const OculusLayerQuadPtr& layer: m.uiLayers) { + for (const OculusLayerPtr& layer: m.uiLayers) { if (layer->GetDrawInFront() && layer->IsDrawRequested() && layerCount < ovrMaxLayerCount) { layer->Update(m.predictedTracking); layers[layerCount++] = layer->Header(); @@ -1111,32 +1217,29 @@ DeviceDelegateOculusVR::EndFrame(const bool aDiscard) { VRLayerQuadPtr DeviceDelegateOculusVR::CreateLayerQuad(int32_t aWidth, int32_t aHeight, - VRLayerQuad::SurfaceType aSurfaceType) { + VRLayerSurface::SurfaceType aSurfaceType) { if (!m.layersEnabled) { return nullptr; } VRLayerQuadPtr layer = VRLayerQuad::Create(aWidth, aHeight, aSurfaceType); OculusLayerQuadPtr oculusLayer = OculusLayerQuad::Create(layer); - if (m.ovr) { - vrb::RenderContextPtr context = m.context.lock(); - oculusLayer->Init(m.java.Env, context); - } - m.uiLayers.push_back(oculusLayer); - if (aSurfaceType == VRLayerQuad::SurfaceType::FBO) { - std::weak_ptr weakLayer = oculusLayer; - layer->SetBindDelegate([=](GLenum aTarget, bool bound){ - OculusLayerQuadPtr layer = weakLayer.lock(); - if (layer) { - m.HandleQuadLayerBind(layer, aTarget, bound); - } - }); - if (m.currentFBO) { - m.currentFBO->Bind(); - } + m.AddUILayer(oculusLayer, aSurfaceType); + return layer; +} + +VRLayerCylinderPtr +DeviceDelegateOculusVR::CreateLayerCylinder(int32_t aWidth, int32_t aHeight, + VRLayerSurface::SurfaceType aSurfaceType) { + if (!m.layersEnabled) { + return nullptr; } + VRLayerCylinderPtr layer = VRLayerCylinder::Create(aWidth, aHeight, aSurfaceType); + OculusLayerCylinderPtr oculusLayer = OculusLayerCylinder::Create(layer); + m.AddUILayer(oculusLayer, aSurfaceType); return layer; } + VRLayerCubePtr DeviceDelegateOculusVR::CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) { if (!m.layersEnabled) { @@ -1148,17 +1251,18 @@ DeviceDelegateOculusVR::CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint a VRLayerCubePtr layer = VRLayerCube::Create(aWidth, aHeight); m.cubeLayer = OculusLayerCube::Create(layer, aInternalFormat); if (m.ovr) { - m.cubeLayer->Init(); + vrb::RenderContextPtr context = m.context.lock(); + m.cubeLayer->Init(m.java.Env, context); } return layer; } VRLayerEquirectPtr -DeviceDelegateOculusVR::CreateLayerEquirect(const VRLayerQuadPtr &aSource) { +DeviceDelegateOculusVR::CreateLayerEquirect(const VRLayerPtr &aSource) { VRLayerEquirectPtr result = VRLayerEquirect::Create(); - OculusLayerQuadPtr source; - for (const OculusLayerQuadPtr& layer: m.uiLayers) { - if (layer->layer == aSource) { + OculusLayerPtr source; + for (const OculusLayerPtr& layer: m.uiLayers) { + if (layer->GetLayer() == aSource) { source = layer; break; } @@ -1168,7 +1272,8 @@ DeviceDelegateOculusVR::CreateLayerEquirect(const VRLayerQuadPtr &aSource) { } m.equirectLayer = OculusLayerEquirect::Create(result, source); if (m.ovr) { - m.equirectLayer->Init(); + vrb::RenderContextPtr context = m.context.lock(); + m.equirectLayer->Init(m.java.Env, context); } return result; } @@ -1181,7 +1286,7 @@ DeviceDelegateOculusVR::DeleteLayer(const VRLayerPtr& aLayer) { return; } for (int i = 0; i < m.uiLayers.size(); ++i) { - if (m.uiLayers[i]->layer.get() == aLayer.get()) { + if (m.uiLayers[i]->GetLayer() == aLayer) { m.uiLayers.erase(m.uiLayers.begin() + i); return; } @@ -1199,14 +1304,14 @@ DeviceDelegateOculusVR::EnterVR(const crow::BrowserEGLContext& aEGLContext) { m.eyeSwapChains[i]->Init(render, m.renderMode, m.renderWidth, m.renderHeight); } vrb::RenderContextPtr context = m.context.lock(); - for (OculusLayerQuadPtr& layer: m.uiLayers) { + for (OculusLayerPtr& layer: m.uiLayers) { layer->Init(m.java.Env, context); } if (m.cubeLayer) { - m.cubeLayer->Init(); + m.cubeLayer->Init(m.java.Env, context); } if (m.equirectLayer) { - m.equirectLayer->Init(); + m.equirectLayer->Init(m.java.Env, context); } ovrModeParms modeParms = vrapi_DefaultModeParms(&m.java); @@ -1244,8 +1349,8 @@ DeviceDelegateOculusVR::LeaveVR() { for (int i = 0; i < VRAPI_EYE_COUNT; ++i) { m.eyeSwapChains[i]->Destroy(); } - for (OculusLayerQuadPtr& layer: m.uiLayers) { - layer->Destroy(m.java.Env); + for (OculusLayerPtr& layer: m.uiLayers) { + layer->Destroy(); } if (m.cubeLayer) { m.cubeLayer->Destroy(); diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.h b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.h index 3da872c6c..0f38aa9ff 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.h +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.h @@ -42,9 +42,11 @@ class DeviceDelegateOculusVR : public DeviceDelegate { void BindEye(const device::Eye aWhich) override; void EndFrame(const bool aDiscard) override; VRLayerQuadPtr CreateLayerQuad(int32_t aWidth, int32_t aHeight, - VRLayerQuad::SurfaceType aSurfaceType) override; + VRLayerSurface::SurfaceType aSurfaceType) override; + VRLayerCylinderPtr CreateLayerCylinder(int32_t aWidth, int32_t aHeight, + VRLayerSurface::SurfaceType aSurfaceType) override; VRLayerCubePtr CreateLayerCube(int32_t aWidth, int32_t aHeight, GLint aInternalFormat) override; - VRLayerEquirectPtr CreateLayerEquirect(const VRLayerQuadPtr &aSource) override; + VRLayerEquirectPtr CreateLayerEquirect(const VRLayerPtr &aSource) override; void DeleteLayer(const VRLayerPtr& aLayer) override; // Custom methods for NativeActivity render loop based devices. void EnterVR(const crow::BrowserEGLContext& aEGLContext);