Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions docs/Properties.md
Original file line number Diff line number Diff line change
@@ -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.
13 changes: 13 additions & 0 deletions tutorial/src/main/cpp/basic/DepthTestingScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -216,6 +218,9 @@ std::map<std::string, std::any> DepthTestingScene::propertyEvent(std::map<std::s
if ("cullface_event" == eventIdStr) {
parseCullFaceEvent(map);
}
if ("show_depth_event" == eventIdStr) {
parseShowDepthEvent(map);
}
}
return {};
}
Expand Down Expand Up @@ -321,3 +326,11 @@ void DepthTestingScene::parseCullFaceEvent(std::map<std::string, std::any> &even
}
}
}

void DepthTestingScene::parseShowDepthEvent(std::map<std::string, std::any> &event) {
if (auto it = event.find("on"); it != event.end()) {
if (it->second.type() == typeid(bool)) {
showDepth = std::any_cast<bool>(it->second);
}
}
}
2 changes: 2 additions & 0 deletions tutorial/src/main/cpp/basic/DepthTestingScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public :
void parseDepthFuncEvent(std::map<std::string, std::any> &map);

void parseCullFaceEvent(std::map<std::string, std::any> &map);

void parseShowDepthEvent(std::map<std::string, std::any> &map);
};


Expand Down
101 changes: 52 additions & 49 deletions tutorial/src/main/cpp/basic/StencilTestingScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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
)
}
}
}