diff --git a/docs/Properties.md b/docs/Properties.md new file mode 100644 index 00000000..ce2924bd --- /dev/null +++ b/docs/Properties.md @@ -0,0 +1,61 @@ +# UI Properties Documentation + +This document describes the common UI properties used in the application's control panels to interact with the OpenGLES renderer. These properties allow for real-time adjustments of rendering state through a Kotlin-based UI, communicating with the native side via event messages. + +## Common Properties + +### 1. Cull Face (`cullFace`) +Toggles back-face culling to optimize rendering by not drawing the back faces of polygons. + +- **UI Component**: Checkbox +- **Data Type**: `Boolean` +- **Event Details**: + - **Event ID**: `cullface_event` + - **Payload**: `{"on": Boolean}` +- **Native Interaction**: Typically maps to `glEnable(GL_CULL_FACE)` or `glDisable(GL_CULL_FACE)`. + +### 2. Depth Test (`depthTest`) +Toggles the depth testing mechanism, which determines if a pixel should be drawn based on its depth relative to existing pixels in the frame buffer. + +- **UI Component**: Checkbox +- **Data Type**: `Boolean` +- **Event Details**: + - **Event ID**: `depthtest_event` + - **Payload**: `{"on": Boolean}` +- **Native Interaction**: Typically maps to `glEnable(GL_DEPTH_TEST)` or `glDisable(GL_DEPTH_TEST)`. + +### 3. Depth Function (`depthFunc`) +Selects the comparison function used in the depth test. + +- **UI Component**: Selector (Dropdown/Exposed Dropdown Menu) +- **Data Type**: `UInt` (Index) +- **Event Details**: + - **Event ID**: `depthtest_func_event` + - **Payload**: `{"func": Int}` (Index of the selected function) +- **Options**: + | Index | Constant | Description | + | :--- | :--- | :--- | + | 0 | `GL_NEVER` | Never passes. | + | 1 | `GL_LESS` | Passes if the incoming depth value is less than the stored depth value. (Default) | + | 2 | `GL_EQUAL` | Passes if the incoming depth value is equal to the stored depth value. | + | 3 | `GL_LEQUAL` | Passes if the incoming depth value is less than or equal to the stored depth value. | + | 4 | `GL_GREATER` | Passes if the incoming depth value is greater than the stored depth value. | + | 5 | `GL_NOTEQUAL` | Passes if the incoming depth value is not equal to the stored depth value. | + | 6 | `GL_GEQUAL` | Passes if the incoming depth value is greater than or equal to the stored depth value. | + | 7 | `GL_ALWAYS` | Always passes. | + +--- + +## Technical Implementation + +### Kotlin Side (UI) +The properties are managed as `mutableStateOf` in the Activity. When a property is changed in the UI, an event map is created and sent via `NativeHelper.sendCommands(event)`. + +Example: +```kotlin +val event = mapOf("event_id" to "depthtest_event", "on" to it) +NativeHelper.sendCommands(event) +``` + +### Native Side (GLES) +The native side listens for these event IDs and applies the corresponding OpenGL ES state changes. For selectors, the index provided is usually mapped to the corresponding OpenGL constant. diff --git a/tutorial/src/main/cpp/basic/DepthTestingScene.cpp b/tutorial/src/main/cpp/basic/DepthTestingScene.cpp index db978194..f02dd239 100644 --- a/tutorial/src/main/cpp/basic/DepthTestingScene.cpp +++ b/tutorial/src/main/cpp/basic/DepthTestingScene.cpp @@ -132,6 +132,8 @@ void DepthTestingScene::init() { check_gl_error(); m_camera = new TargetCamera(); + m_camera->setNear(3.f); + m_camera->setFar(10.f); } void DepthTestingScene::resize(int width, int height) { @@ -216,6 +218,9 @@ std::map DepthTestingScene::propertyEvent(std::map &even } } } + +void DepthTestingScene::parseShowDepthEvent(std::map &event) { + if (auto it = event.find("on"); it != event.end()) { + if (it->second.type() == typeid(bool)) { + showDepth = std::any_cast(it->second); + } + } +} diff --git a/tutorial/src/main/cpp/basic/DepthTestingScene.h b/tutorial/src/main/cpp/basic/DepthTestingScene.h index 47fd77a4..e807c9f3 100644 --- a/tutorial/src/main/cpp/basic/DepthTestingScene.h +++ b/tutorial/src/main/cpp/basic/DepthTestingScene.h @@ -69,6 +69,8 @@ public : void parseDepthFuncEvent(std::map &map); void parseCullFaceEvent(std::map &map); + + void parseShowDepthEvent(std::map &map); }; diff --git a/tutorial/src/main/cpp/basic/StencilTestingScene.cpp b/tutorial/src/main/cpp/basic/StencilTestingScene.cpp index bf9e38af..32e0ddaa 100644 --- a/tutorial/src/main/cpp/basic/StencilTestingScene.cpp +++ b/tutorial/src/main/cpp/basic/StencilTestingScene.cpp @@ -31,58 +31,61 @@ void StencilTestingScene::init() { // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ float cubeVertices[] = { - // positions // texture Coords - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + // positions // texture Coords + // back face + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // bottom-left + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // bottom-left + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left + // front face + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // top-right + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // top-left + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left + // left face + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right + -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-left + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right + -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-right + // right face + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // bottom-right + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // top-left + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-left + // bottom face + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right + 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, // top-left + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // bottom-left + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // bottom-right + -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // top-right + // top face + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right + 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // top-right + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // bottom-right + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // top-left + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f // bottom-left }; float planeVertices[] = { - // positions // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat) - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, - -5.0f, -0.5f, -0.5f, 0.0f, 2.0f, + // positions // texture Coords + // (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). + // this will cause the floor texture to repeat) + 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, + -5.0f, -0.5f, -5.f, 0.0f, 2.0f, + -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, - 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, - -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, - 5.0f, -0.5f, -5.0f, 2.0f, 2.0f + 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, + 5.0f, -0.5f, -5.0f, 2.0f, 2.0f, + -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, }; // cube VAO glGenVertexArrays(1, &m_cubeVAO); diff --git a/tutorial/src/main/java/com/minininja/learngles/basic/DepthTestingActivity.kt b/tutorial/src/main/java/com/minininja/learngles/basic/DepthTestingActivity.kt index 1e184581..6a47fa97 100644 --- a/tutorial/src/main/java/com/minininja/learngles/basic/DepthTestingActivity.kt +++ b/tutorial/src/main/java/com/minininja/learngles/basic/DepthTestingActivity.kt @@ -36,6 +36,8 @@ class DepthTestingActivity : GLActivity() { private var depthTestOn by mutableStateOf(true) + private var showDepthOn by mutableStateOf(false) + private var depthFuncIndex by mutableStateOf(1) // Default to GL_LESS (index 1) private val depthFuncs = listOf( @@ -134,6 +136,19 @@ class DepthTestingActivity : GLActivity() { }, ) + ControlPanelContent( + title = "Show Depth", + active = showDepthOn, + onActiveChange = { + showDepthOn = it + val event = mapOf("event_id" to "show_depth_event", "on" to it) + glSurfaceView?.queueEvent { + NativeHelper.sendCommands(event) + glSurfaceView?.requestRender() + } + }, + ) + SelectorControlPanelContent( title = "Depth Func", options = depthFuncs, diff --git a/tutorial/src/main/java/com/minininja/learngles/basic/StencilTestingActivity.kt b/tutorial/src/main/java/com/minininja/learngles/basic/StencilTestingActivity.kt index 015d052a..4a279832 100644 --- a/tutorial/src/main/java/com/minininja/learngles/basic/StencilTestingActivity.kt +++ b/tutorial/src/main/java/com/minininja/learngles/basic/StencilTestingActivity.kt @@ -1,5 +1,104 @@ package com.minininja.learngles.basic +import android.util.Log +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp import com.minininja.learngles.GLActivity +import com.minininja.learngles.Layer3DTouchCallback +import com.minininja.learngles.NativeHelper -class StencilTestingActivity : GLActivity() +class StencilTestingActivity : GLActivity() { + private var active by mutableStateOf(true) + + override fun createTouchCallback(): Layer3DTouchCallback { + return object : Layer3DTouchCallback { + override fun onSingleTouch( + prevPoint: Offset, + point: Offset + ) { + if (!active) return + Log.d("StencilTestingActivity", "onSingleTouch: $prevPoint, $point") + val event = mapOf("event_id" to "target_camera_touching_event", + "single_touching" to floatArrayOf(prevPoint.x, prevPoint.y, point.x, point.y)) + NativeHelper.sendCommands(event) + glSurfaceView?.requestRender() + } + + override fun onDoubleTouch( + prevPoint: Offset, + point: Offset, + prevPoint1: Offset, + point1: Offset + ) { + if (!active) return + Log.d("StencilTestingActivity", "onDoubleTouch: $prevPoint -> $point, $prevPoint1 -> $point1") + val event = mapOf("event_id" to "target_camera_touching_event", + "double_touching" to floatArrayOf(prevPoint.x, prevPoint.y, point.x, point.y, + prevPoint1.x, prevPoint1.y, point1.x, point1.y)) + NativeHelper.sendCommands(event) + glSurfaceView?.requestRender() + } + + override fun onLongPress(event: Offset) {} + + override fun onSingleClick(event: Offset) {} + + override fun onDoubleClick(event: Offset) { + if (!active) return + val event = mapOf("event_id" to "target_camera_touching_event", + "reset" to 1) + NativeHelper.sendCommands(event) + Log.d("StencilTestingActivity", "Custom DoubleClick at: $event") + } + + override fun onActionUp(event: Offset) {} + + override fun onTwoFingersClick() {} + + override fun onThreeFingersClick() {} + } + } + + @Composable + override fun ControlPanel() { + ControlPanelContent( + active = active, + onActiveChange = { + active = it + }, + ) + } +} + +@Composable +private fun ControlPanelContent( + active: Boolean, + onActiveChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier.wrapContentSize() + ) { + Row(verticalAlignment = Alignment.CenterVertically, + modifier = modifier.padding(8.dp)) { + Text(text = "Target Camera Events", color = Color.White) + Checkbox( + checked = active, + onCheckedChange = onActiveChange + ) + } + } +}