Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a82d93914e | ||
|
|
389349198f | ||
|
|
225a844e0f | ||
|
|
f018c719a6 | ||
|
|
2a229571ad | ||
|
|
35959b547c | ||
|
|
796007377d | ||
|
|
5c73d0ae75 | ||
|
|
bb90103e74 | ||
|
|
0149bc504d | ||
|
|
3db035520b | ||
|
|
618b59932c | ||
|
|
9ef05ad456 | ||
|
|
c8a0dbb59a | ||
|
|
35a0b045f8 | ||
|
|
a4369c833d | ||
|
|
354f1da708 | ||
|
|
7e47d257d1 | ||
|
|
c3d2b3578d | ||
|
|
783aa06a46 | ||
|
|
faa82ff35a | ||
|
|
3008123d6b | ||
|
|
2d2987066d | ||
|
|
c84ec04efa | ||
|
|
197b45c1d1 | ||
|
|
af9ecf0a61 | ||
|
|
530fb58337 | ||
|
|
6a891021b1 | ||
|
|
0e7c68b50d | ||
|
|
32a32d3d21 | ||
|
|
fca71813d4 | ||
|
|
3618f14531 | ||
|
|
9de3e76a53 | ||
|
|
e472fdbce4 | ||
|
|
c9fcedb40b | ||
|
|
bd8c3e9181 | ||
|
|
26d0aa76f8 | ||
|
|
20f4ec6576 | ||
|
|
d0bc23473c | ||
|
|
c33f6adf62 | ||
|
|
d4efa105b7 | ||
|
|
e8641ce257 | ||
|
|
d7a4bdc3f1 | ||
|
|
e66215295c | ||
|
|
552bb3e6db | ||
|
|
a96da05ab8 | ||
|
|
fb5ee4a9d0 | ||
|
|
da13067b57 | ||
|
|
d48d69c765 | ||
|
|
5098b2af77 | ||
|
|
5576d6b014 | ||
|
|
b072399229 | ||
|
|
4f0ab43d58 | ||
|
|
3f742880b5 | ||
|
|
0704194460 | ||
|
|
56e747f558 | ||
|
|
61c22f2295 | ||
|
|
c4bbaeda86 | ||
|
|
678ffc7503 | ||
|
|
a080a47268 | ||
|
|
82e8104539 | ||
|
|
11bd8e72ef | ||
|
|
03c2a90206 | ||
|
|
c38ab64b6a | ||
|
|
2548da9aed | ||
|
|
2fa08123a0 | ||
|
|
20c3d45b9c | ||
|
|
c8af3226de | ||
|
|
4b669fb1c7 | ||
|
|
340f6d721a | ||
|
|
489f3ff3c9 | ||
|
|
566d3613d1 | ||
|
|
e691cfa9e3 | ||
|
|
a4a1bf07aa | ||
|
|
7ea7d1d5f2 | ||
|
|
686c68c627 | ||
|
|
c652dcfd2a | ||
|
|
01fab5a6e4 | ||
|
|
16a5adcfde | ||
|
|
d550d36637 | ||
|
|
3857c1a9b2 | ||
|
|
2f8bc9239b | ||
|
|
9de934e2bd | ||
|
|
769f1db011 | ||
|
|
da72c58146 | ||
|
|
ef34dd2461 |
59
.github/workflows/presubmit.yml
vendored
@@ -12,7 +12,15 @@ jobs:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout Filament
|
||||
run: |
|
||||
git version
|
||||
git init $GITHUB_WORKSPACE
|
||||
cd $GITHUB_WORKSPACE
|
||||
git remote add origin https://github.com/google/filament
|
||||
git config gc.auto 0
|
||||
git fetch --tags --prune --progress --no-recurse-submodules origin +${GITHUB_REF}:${GITHUB_REF/refs\//refs\/remote\/}
|
||||
git checkout --progress --force ${GITHUB_REF/refs\//refs\/remote\/}
|
||||
- name: Run build script
|
||||
run: |
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
@@ -20,12 +28,39 @@ jobs:
|
||||
env:
|
||||
TARGET: presubmit
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Filament
|
||||
run: |
|
||||
git version
|
||||
git init %GITHUB_WORKSPACE%
|
||||
cd %GITHUB_WORKSPACE%
|
||||
git remote add origin https://github.com/google/filament
|
||||
git config gc.auto 0
|
||||
git fetch --tags --prune --progress --no-recurse-submodules origin +%GITHUB_REF%:%GITHUB_REF:refs/=refs/remote/%
|
||||
git checkout --progress --force %GITHUB_REF:refs/=refs/remote/%
|
||||
shell: cmd
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout Filament
|
||||
run: |
|
||||
git version
|
||||
git init $GITHUB_WORKSPACE
|
||||
cd $GITHUB_WORKSPACE
|
||||
git remote add origin https://github.com/google/filament
|
||||
git config gc.auto 0
|
||||
git fetch --tags --prune --progress --no-recurse-submodules origin +${GITHUB_REF}:${GITHUB_REF/refs\//refs\/remote\/}
|
||||
git checkout --progress --force ${GITHUB_REF/refs\//refs\/remote\/}
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/android && ./build.sh ${TARGET}
|
||||
@@ -37,7 +72,15 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout Filament
|
||||
run: |
|
||||
git version
|
||||
git init $GITHUB_WORKSPACE
|
||||
cd $GITHUB_WORKSPACE
|
||||
git remote add origin https://github.com/google/filament
|
||||
git config gc.auto 0
|
||||
git fetch --tags --prune --progress --no-recurse-submodules origin +${GITHUB_REF}:${GITHUB_REF/refs\//refs\/remote\/}
|
||||
git checkout --progress --force ${GITHUB_REF/refs\//refs\/remote\/}
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && ./build.sh ${TARGET}
|
||||
@@ -49,7 +92,15 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Checkout Filament
|
||||
run: |
|
||||
git version
|
||||
git init $GITHUB_WORKSPACE
|
||||
cd $GITHUB_WORKSPACE
|
||||
git remote add origin https://github.com/google/filament
|
||||
git config gc.auto 0
|
||||
git fetch --tags --prune --progress --no-recurse-submodules origin +${GITHUB_REF}:${GITHUB_REF/refs\//refs\/remote\/}
|
||||
git checkout --progress --force ${GITHUB_REF/refs\//refs\/remote\/}
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && ./build.sh ${TARGET}
|
||||
|
||||
@@ -355,6 +355,28 @@ function(list_licenses OUTPUT MODULES)
|
||||
configure_file(${FILAMENT}/build/licenses.inc.in ${OUTPUT})
|
||||
endfunction(list_licenses)
|
||||
|
||||
set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/linux/combine-static-libs.sh")
|
||||
if (WIN32)
|
||||
set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/windows/combine-static-libs.bat")
|
||||
set(CMAKE_AR "lib.exe")
|
||||
endif()
|
||||
|
||||
# Add a custom command to TARGET that combines the static libraries in DEPS into a single archive.
|
||||
function(combine_static_libs TARGET OUTPUT DEPS)
|
||||
# Loop through the dependent libraries and query their location on disk.
|
||||
set(DEPS_FILES )
|
||||
foreach(DEPENDENCY ${DEPS})
|
||||
list(APPEND DEPS_FILES "$<TARGET_FILE:${DEPENDENCY}>")
|
||||
endforeach()
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES}
|
||||
COMMENT "Combining ${target} dependencies into single shared library"
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# ==================================================================================================
|
||||
# Configuration for CMAKE_CROSSCOMPILING.
|
||||
# ==================================================================================================
|
||||
|
||||
49
README.md
@@ -249,6 +249,28 @@ $ ./build.sh -j release
|
||||
|
||||
If you use CMake directly instead of the build script, pass `-DENABLE_JAVA=OFF` to CMake instead.
|
||||
|
||||
### Filament-specific CMake Options
|
||||
|
||||
The following CMake options are boolean options specific to Filament:
|
||||
|
||||
- `ENABLE_JAVA`: Compile Java projects: requires a JDK and the JAVA_HOME env var
|
||||
- `ENABLE_LTO`: Enable link-time optimizations if supported by the compiler
|
||||
- `FILAMENT_BUILD_FILAMAT`: Build filamat and JNI buildings
|
||||
- `FILAMENT_SUPPORTS_METAL`: Include the Metal backend
|
||||
- `FILAMENT_SUPPORTS_VULKAN`: Include the Vulkan backend
|
||||
- `GENERATE_JS_DOCS`: Build WebGL documentation and tutorials
|
||||
- `INSTALL_BACKEND_TEST`: Install the backend test library so it can be consumed on iOS
|
||||
- `USE_EXTERNAL_GLES3`: Experimental: Compile Filament against OpenGL ES 3
|
||||
|
||||
To turn an option on or off:
|
||||
|
||||
```
|
||||
$ cd <cmake-build-directory>
|
||||
$ cmake . -DOPTION=ON # Relace OPTION with the option name, set to ON / OFF
|
||||
```
|
||||
|
||||
Options can also be set with the CMake GUI.
|
||||
|
||||
### Linux
|
||||
|
||||
Make sure you've installed the following dependencies:
|
||||
@@ -341,6 +363,33 @@ See [ios/samples/README.md](./ios/samples/README.md) for more information.
|
||||
|
||||
### Windows
|
||||
|
||||
#### Building on Windows with the Visual Studio 2019 compiler
|
||||
|
||||
Install the following components:
|
||||
|
||||
- [Visual Studio 2019](https://www.visualstudio.com/downloads)
|
||||
- [Python 3.7](https://www.python.org/ftp/python/3.7.0/python-3.7.0.exe)
|
||||
- [CMake 3.14 or later](https://github.com/Kitware/CMake/releases/download/v3.14.7/cmake-3.14.7-win64-x64.msi)
|
||||
|
||||
Open the `x64 Native Tools Command Prompt for VS 2019`.
|
||||
|
||||
Create a working directory, and run cmake in it:
|
||||
|
||||
```
|
||||
> mkdir out
|
||||
> cd out
|
||||
> cmake ..
|
||||
```
|
||||
|
||||
Then, you should be able to load the generated solution file `TNT.sln` in Visual Studio and build the `material_sandbox` project.
|
||||
|
||||
Run it from the `out` directory with:
|
||||
```
|
||||
> samples\Debug\material_sandbox.exe ..\assets\models\monkey\monkey.obj
|
||||
```
|
||||
|
||||
#### Building on Windows with the Clang compiler
|
||||
|
||||
The following instructions have been tested on a machine running Windows 10. They should take you
|
||||
from a machine with only the operating system to a machine able to build and run Filament.
|
||||
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
This file contains one line summaries of commits that are worthy of mentioning in release notes.
|
||||
A new header is inserted each time a *tag* is created.
|
||||
|
||||
## v1.4.2
|
||||
|
||||
- Cleaned up the validation strategy in Engine (checks for use-after-destroy etc).
|
||||
- OpenGL: Fixed ES 3.0 support on iOS.
|
||||
- OpenGL: Added support for KHR_debug in debug builds.
|
||||
- gltfio: Added Java / Kotlin bindings for Animator.
|
||||
- gltfio: Fixed panic with the Android gltf-bloom demo.
|
||||
- gltfio: Java clients should no longer call Filament#init.
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- Added missing API documentation.
|
||||
- Fixed crash for sandboxed macOS apps using Filament.
|
||||
- Fixed an issue that limited the camera near plane to ~1mm.
|
||||
- Added Android sample for Camera Stream.
|
||||
- Fixed an Xcode assertion when rendering skinned meshes using the Metal backend.
|
||||
- Added support for Core Animation / Metal frame synchronization with Metal backend.
|
||||
- Fixed an issue with culling in `MaterialInstance`.
|
||||
- Fix additional compatibility issues with MSVC, including the Vulkan backend.
|
||||
- matdbg: fixed missing symbol issue when linking against debug builds.
|
||||
- filamat: fixed crash when using the "lite" version of the library.
|
||||
- matinfo: Fix a crash with on Windows.
|
||||
- gltfio: fixed an animation loop bug.
|
||||
- gltfio: added support for sparse accessors.
|
||||
- Add JS binding to unary `Camera::setExposure`.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- API Breakage: Simplified public-facing Fence API.
|
||||
|
||||
@@ -50,57 +50,66 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ff
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS" ${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS" ${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic-functions")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libfilament-jni.map")
|
||||
|
||||
add_library(filament-jni SHARED
|
||||
src/main/cpp/Camera.cpp
|
||||
src/main/cpp/Colors.cpp
|
||||
src/main/cpp/VertexBuffer.cpp
|
||||
src/main/cpp/Engine.cpp
|
||||
src/main/cpp/EntityManager.cpp
|
||||
src/main/cpp/Fence.cpp
|
||||
src/main/cpp/IndexBuffer.cpp
|
||||
src/main/cpp/IndirectLight.cpp
|
||||
src/main/cpp/LightManager.cpp
|
||||
src/main/cpp/Material.cpp
|
||||
src/main/cpp/MaterialInstance.cpp
|
||||
src/main/cpp/MathUtils.cpp
|
||||
src/main/cpp/RenderableManager.cpp
|
||||
src/main/cpp/Renderer.cpp
|
||||
src/main/cpp/RenderTarget.cpp
|
||||
src/main/cpp/Scene.cpp
|
||||
src/main/cpp/SkyBox.cpp
|
||||
src/main/cpp/Stream.cpp
|
||||
src/main/cpp/Texture.cpp
|
||||
src/main/cpp/TextureSampler.cpp
|
||||
src/main/cpp/TransformManager.cpp
|
||||
src/main/cpp/View.cpp
|
||||
# Android specific
|
||||
src/main/cpp/nativewindow/Android.cpp
|
||||
# Private utils
|
||||
src/main/cpp/Filament.cpp
|
||||
# Common utils
|
||||
../common/CallbackUtils.cpp
|
||||
../common/NioUtils.cpp
|
||||
add_library(filament-jni-obj OBJECT
|
||||
src/main/cpp/Camera.cpp
|
||||
src/main/cpp/Colors.cpp
|
||||
src/main/cpp/VertexBuffer.cpp
|
||||
src/main/cpp/Engine.cpp
|
||||
src/main/cpp/EntityManager.cpp
|
||||
src/main/cpp/Fence.cpp
|
||||
src/main/cpp/IndexBuffer.cpp
|
||||
src/main/cpp/IndirectLight.cpp
|
||||
src/main/cpp/LightManager.cpp
|
||||
src/main/cpp/Material.cpp
|
||||
src/main/cpp/MaterialInstance.cpp
|
||||
src/main/cpp/MathUtils.cpp
|
||||
src/main/cpp/RenderableManager.cpp
|
||||
src/main/cpp/Renderer.cpp
|
||||
src/main/cpp/RenderTarget.cpp
|
||||
src/main/cpp/Scene.cpp
|
||||
src/main/cpp/SkyBox.cpp
|
||||
src/main/cpp/Stream.cpp
|
||||
src/main/cpp/Texture.cpp
|
||||
src/main/cpp/TextureSampler.cpp
|
||||
src/main/cpp/TransformManager.cpp
|
||||
src/main/cpp/View.cpp
|
||||
# Android specific
|
||||
src/main/cpp/nativewindow/Android.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(filament-jni
|
||||
filament
|
||||
backend
|
||||
filaflat
|
||||
filabridge
|
||||
geometry
|
||||
ibl
|
||||
utils
|
||||
log
|
||||
GLESv3
|
||||
EGL
|
||||
android
|
||||
jnigraphics
|
||||
)
|
||||
if (NOT DISABLE_FILAMENT_JNI)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-jni.map")
|
||||
|
||||
add_library(filament-jni SHARED
|
||||
$<TARGET_OBJECTS:filament-jni-obj>
|
||||
# Private utils
|
||||
src/main/cpp/Filament.cpp
|
||||
# Common utils
|
||||
../common/CallbackUtils.cpp
|
||||
../common/NioUtils.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(filament-jni
|
||||
filament
|
||||
backend
|
||||
filaflat
|
||||
filabridge
|
||||
geometry
|
||||
ibl
|
||||
utils
|
||||
log
|
||||
GLESv3
|
||||
EGL
|
||||
android
|
||||
jnigraphics
|
||||
)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
target_link_libraries(filament-jni bluevk smol-v)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
target_link_libraries(filament-jni bluevk smol-v)
|
||||
endif()
|
||||
|
||||
@@ -252,6 +252,13 @@ Java_com_google_android_filament_Engine_nDestroyEntity(JNIEnv*, jclass,
|
||||
engine->destroy(entity);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv *env, jclass clazz,
|
||||
jlong nativeEngine) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
engine->flushAndWait();
|
||||
}
|
||||
|
||||
// Managers...
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
|
||||
@@ -47,6 +47,13 @@ Java_com_google_android_filament_Skybox_nBuilderShowSun(JNIEnv *env, jclass type
|
||||
builder->showSun(show);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Skybox_nBuilderIntensity(JNIEnv *env, jclass clazz,
|
||||
jlong nativeSkyBoxBuilder, jfloat intensity) {
|
||||
Skybox::Builder *builder = (Skybox::Builder *) nativeSkyBoxBuilder;
|
||||
builder->intensity(intensity);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Skybox_nBuilderBuild(JNIEnv *env, jclass type,
|
||||
jlong nativeSkyBoxBuilder, jlong nativeEngine) {
|
||||
@@ -68,3 +75,10 @@ Java_com_google_android_filament_Skybox_nGetLayerMask(JNIEnv *env, jclass type,
|
||||
Skybox *skybox = (Skybox *) nativeSkybox;
|
||||
return static_cast<jint>(skybox->getLayerMask());
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_Skybox_nGetIntensity(JNIEnv *env, jclass clazz,
|
||||
jlong nativeSkybox) {
|
||||
Skybox *skybox = (Skybox *) nativeSkybox;
|
||||
return static_cast<jint>(skybox->getIntensity());
|
||||
}
|
||||
|
||||
@@ -19,12 +19,25 @@ package com.google.android.filament;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Size;
|
||||
|
||||
/**
|
||||
* An axis-aligned 3D box represented by its center and half-extent.
|
||||
*
|
||||
* The half-extent is a vector representing the distance from the center to the edge of the box in
|
||||
* each dimension. For example, a box of size 2 units in X, 4 units in Y, and 10 units in Z would
|
||||
* have a half-extent of (1, 2, 5).
|
||||
*/
|
||||
public class Box {
|
||||
private final float[] mCenter = new float[3];
|
||||
private final float[] mHalfExtent = new float[3];
|
||||
|
||||
/**
|
||||
* Default-initializes the 3D box to have a center and half-extent of (0,0,0).
|
||||
*/
|
||||
public Box() { }
|
||||
|
||||
/**
|
||||
* Initializes the 3D box from its center and half-extent.
|
||||
*/
|
||||
public Box(float centerX, float centerY, float centerZ,
|
||||
float halfExtentX, float halfExtentY, float halfExtentZ) {
|
||||
mCenter[0] = centerX;
|
||||
@@ -35,6 +48,13 @@ public class Box {
|
||||
mHalfExtent[2] = halfExtentZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the 3D box from its center and half-extent.
|
||||
*
|
||||
* @param center a float array with XYZ coordinates representing the center of the box
|
||||
* @param halfExtent a float array with XYZ coordinates representing half the size of the box in
|
||||
* each dimension
|
||||
*/
|
||||
public Box(@NonNull @Size(min = 3) float[] center, @NonNull @Size(min = 3) float[] halfExtent) {
|
||||
mCenter[0] = center[0];
|
||||
mCenter[1] = center[1];
|
||||
@@ -44,21 +64,37 @@ public class Box {
|
||||
mHalfExtent[2] = halfExtent[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the center of of the 3D box.
|
||||
*/
|
||||
public void setCenter(float centerX, float centerY, float centerZ) {
|
||||
mCenter[0] = centerX;
|
||||
mCenter[1] = centerY;
|
||||
mCenter[2] = centerZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the half-extent of the 3D box.
|
||||
*/
|
||||
public void setHalfExtent(float halfExtentX, float halfExtentY, float halfExtentZ) {
|
||||
mHalfExtent[0] = halfExtentX;
|
||||
mHalfExtent[1] = halfExtentY;
|
||||
mHalfExtent[2] = halfExtentZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the center of the 3D box.
|
||||
*
|
||||
* @return an XYZ float array of size 3
|
||||
*/
|
||||
@NonNull @Size(min = 3)
|
||||
public float[] getCenter() { return mCenter; }
|
||||
|
||||
/**
|
||||
* Returns the half-extent from the center of the 3D box.
|
||||
*
|
||||
* @return an XYZ float array of size 3
|
||||
*/
|
||||
@NonNull @Size(min = 3)
|
||||
public float[] getHalfExtent() { return mHalfExtent; }
|
||||
}
|
||||
|
||||
@@ -459,7 +459,6 @@ public class Camera {
|
||||
* between 50 and 25600.
|
||||
*
|
||||
* @see LightManager
|
||||
* @see Exposure
|
||||
* @see #setExposure(float)
|
||||
*/
|
||||
public void setExposure(float aperture, float shutterSpeed, float sensitivity) {
|
||||
@@ -477,8 +476,7 @@ public class Camera {
|
||||
* the exposure manually. This can be typically achieved by setting the exposure to
|
||||
* 1.0.
|
||||
*
|
||||
* @see Light
|
||||
* @see Exposure
|
||||
* @see LightManager
|
||||
* @see #setExposure(float, float, float)
|
||||
*/
|
||||
public void setExposure(float exposure) {
|
||||
|
||||
@@ -28,6 +28,9 @@ import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
/**
|
||||
* Utilities to manipulate and convert colors.
|
||||
*/
|
||||
public class Colors {
|
||||
private Colors() {
|
||||
}
|
||||
@@ -37,23 +40,67 @@ public class Colors {
|
||||
public @interface LinearColor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of RGB colors.
|
||||
*/
|
||||
public enum RgbType {
|
||||
/** The color is defined in sRGB space. */
|
||||
SRGB,
|
||||
|
||||
/** The color is defined in linear space. */
|
||||
LINEAR
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of RGBA colors.
|
||||
*/
|
||||
public enum RgbaType {
|
||||
/**
|
||||
* The color is defined in sRGB space and the RGB values have not been premultiplied by the
|
||||
* alpha (for instance, a 50% transparent red is <1,0,0,0.5>).
|
||||
*/
|
||||
SRGB,
|
||||
|
||||
/**
|
||||
* The color is defined in linear space and the RGB values have not been premultiplied by
|
||||
* the alpha (for instance, a 50% transparent red is <1,0,0,0.5>).
|
||||
*/
|
||||
LINEAR,
|
||||
|
||||
/**
|
||||
* The color is defined in sRGB space and the RGB values have been premultiplied by the
|
||||
* alpha (for instance, a 50% transparent red is <0.5,0,0,0.5>).
|
||||
*/
|
||||
PREMULTIPLIED_SRGB,
|
||||
|
||||
/**
|
||||
* The color is defined in linear space and the RGB values have been premultiplied by the
|
||||
* alpha (for instance, a 50% transparent red is <0.5,0,0,0.5>).
|
||||
*/
|
||||
PREMULTIPLIED_LINEAR
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of color conversion to use when converting to/from sRGB and linear spaces.
|
||||
*/
|
||||
public enum Conversion {
|
||||
/** Accurate conversion using the sRGB standard. */
|
||||
ACCURATE,
|
||||
|
||||
/** Fast conversion using a simple gamma 2.2 curve. */
|
||||
FAST
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGB color to linear space, the conversion depends on the specified type.
|
||||
*
|
||||
* @param type the color space of the RGB color values provided
|
||||
* @param r the red component
|
||||
* @param g the green component
|
||||
* @param b the blue component
|
||||
*
|
||||
* @return an RGB float array of size 3 with the result of the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(3)
|
||||
@LinearColor
|
||||
@@ -61,6 +108,14 @@ public class Colors {
|
||||
return toLinear(type, new float[] { r, g, b });
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGB color to linear space, the conversion depends on the specified type.
|
||||
*
|
||||
* @param type the color space of the RGB color values provided
|
||||
* @param rgb an RGB float array of size 3, will be modified
|
||||
*
|
||||
* @return the passed-in <code>rgb</code> array, after applying the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(min = 3)
|
||||
@LinearColor
|
||||
@@ -68,6 +123,17 @@ public class Colors {
|
||||
return (type == RgbType.LINEAR) ? rgb : toLinear(Conversion.ACCURATE, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGBA color to linear space, with pre-multiplied alpha.
|
||||
*
|
||||
* @param type the color space and type of RGBA color values provided
|
||||
* @param r the red component
|
||||
* @param g the green component
|
||||
* @param b the blue component
|
||||
* @param a the alpha component
|
||||
*
|
||||
* @return an RGBA float array of size 4 with the result of the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(4)
|
||||
@LinearColor
|
||||
@@ -75,6 +141,14 @@ public class Colors {
|
||||
return toLinear(type, new float[] { r, g, b, a });
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGBA color to linear space, with pre-multiplied alpha.
|
||||
*
|
||||
* @param type the color space of the RGBA color values provided
|
||||
* @param rgba an RGBA float array of size 4, will be modified
|
||||
*
|
||||
* @return the passed-in <code>rgba</code> array, after applying the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(min = 4)
|
||||
@LinearColor
|
||||
@@ -97,6 +171,15 @@ public class Colors {
|
||||
return rgba;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGB color in sRGB space to an RGB color in linear space.
|
||||
*
|
||||
* @param conversion the conversion algorithm to use
|
||||
* @param rgb an RGB float array of at least size 3, will be modified
|
||||
*
|
||||
* @return the passed-in <code>rgb</code> array, after applying the conversion. The alpha
|
||||
* channel, if present, is left unmodified.
|
||||
*/
|
||||
@NonNull
|
||||
@LinearColor
|
||||
public static float[] toLinear(@NonNull Conversion conversion, @NonNull @Size(min = 3) float[] rgb) {
|
||||
@@ -116,6 +199,14 @@ public class Colors {
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a correlated color temperature to a linear RGB color in sRGB space. The temperature
|
||||
* must be expressed in Kelvin and must be in the range 1,000K to 15,000K.
|
||||
*
|
||||
* @param temperature the temperature, in Kelvin
|
||||
*
|
||||
* @return an RGB float array of size 3 with the result of the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(3)
|
||||
@LinearColor
|
||||
@@ -125,6 +216,14 @@ public class Colors {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a CIE standard illuminant series D to a linear RGB color in sRGB space. The
|
||||
* temperature must be expressed in Kelvin and must be in the range 4,000K to 25,000K.
|
||||
*
|
||||
* @param temperature the temperature, in Kelvin
|
||||
*
|
||||
* @return an RGB float array of size 3 with the result of the conversion
|
||||
*/
|
||||
@NonNull
|
||||
@Size(3)
|
||||
@LinearColor
|
||||
|
||||
@@ -582,9 +582,14 @@ public class Engine {
|
||||
* Kicks the hardware thread (e.g.: the OpenGL, Vulkan or Metal thread) and blocks until
|
||||
* all commands to this point are executed. Note that this doesn't guarantee that the
|
||||
* hardware is actually finished.
|
||||
*
|
||||
* <p>This is typically used right after destroying the <code>SwapChain</code>,
|
||||
* in cases where a guarantee about the SwapChain destruction is needed in a timely fashion,
|
||||
* such as when responding to Android's
|
||||
* {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.</p>
|
||||
*/
|
||||
public void flushAndWait() {
|
||||
Fence.waitAndDestroy(createFence(), Fence.Mode.FLUSH);
|
||||
nFlushAndWait(getNativeObject());
|
||||
}
|
||||
|
||||
@UsedByReflection("TextureHelper.java")
|
||||
@@ -626,6 +631,7 @@ public class Engine {
|
||||
private static native void nDestroyTexture(long nativeEngine, long nativeTexture);
|
||||
private static native void nDestroyRenderTarget(long nativeEngine, long nativeTarget);
|
||||
private static native void nDestroyEntity(long nativeEngine, int entity);
|
||||
private static native void nFlushAndWait(long nativeEngine);
|
||||
private static native long nGetTransformManager(long nativeEngine);
|
||||
private static native long nGetLightManager(long nativeEngine);
|
||||
private static native long nGetRenderableManager(long nativeEngine);
|
||||
|
||||
@@ -23,6 +23,17 @@ import android.support.annotation.Nullable;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
/**
|
||||
* A buffer containing vertex indices into a <code>VertexBuffer</code>. Indices can be 16 or 32 bit.
|
||||
* The buffer itself is a GPU resource, therefore mutating the data can be relatively slow.
|
||||
* Typically these buffers are constant.
|
||||
*
|
||||
* It is possible, and even encouraged, to use a single index buffer for several
|
||||
* <code>Renderables</code>.
|
||||
*
|
||||
* @see VertexBuffer
|
||||
* @see RenderableManager
|
||||
*/
|
||||
public class IndexBuffer {
|
||||
private long mNativeObject;
|
||||
|
||||
@@ -36,8 +47,14 @@ public class IndexBuffer {
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
private final long mNativeBuilder;
|
||||
|
||||
/**
|
||||
* Type of the index buffer.
|
||||
*/
|
||||
public enum IndexType {
|
||||
/** 16-bit indices */
|
||||
USHORT,
|
||||
|
||||
/** 32-bit indices */
|
||||
UINT,
|
||||
}
|
||||
|
||||
@@ -46,18 +63,45 @@ public class IndexBuffer {
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of the index buffer in elements.
|
||||
*
|
||||
* @param indexCount number of indices the <code>IndexBuffer</code> can hold
|
||||
*
|
||||
* @return this <code>Builder</code> object for chaining calls
|
||||
*/
|
||||
@NonNull
|
||||
public Builder indexCount(@IntRange(from = 1) int indexCount) {
|
||||
nBuilderIndexCount(mNativeBuilder, indexCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the index buffer, 16-bit or 32-bit.
|
||||
*
|
||||
* @param indexType type of indices stored in the <code>IndexBuffer</code>
|
||||
*
|
||||
* @return this <code>Builder</code> object for chaining calls
|
||||
*/
|
||||
@NonNull
|
||||
public Builder bufferType(@NonNull IndexType indexType) {
|
||||
nBuilderBufferType(mNativeBuilder, indexType.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the <code>IndexBuffer</code> object. After creation, the index buffer
|
||||
* is uninitialized. Use {@link #setBuffer} to initialized the <code>IndexBuffer</code>.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this <code>IndexBuffer</code>
|
||||
* with
|
||||
*
|
||||
* @return the newly created <code>IndexBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the IndexBuffer could not be created
|
||||
*
|
||||
* @see #setBuffer
|
||||
*/
|
||||
@NonNull
|
||||
public IndexBuffer build(@NonNull Engine engine) {
|
||||
long nativeIndexBuffer = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -85,24 +129,69 @@ public class IndexBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of this <code>IndexBuffer</code> in elements.
|
||||
*
|
||||
* @return the number of indices the <code>IndexBuffer</code> holds
|
||||
*/
|
||||
@IntRange(from = 0)
|
||||
public int getIndexCount() {
|
||||
return nGetIndexCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously copy-initializes this <code>IndexBuffer</code> from the data provided.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>IndexBuffer</code> with
|
||||
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
|
||||
* <code>IndexBuffer</code>. <code>buffer</code> should contain raw,
|
||||
* untyped data that will be interpreted as either 16-bit or 32-bits
|
||||
* indices based on the <code>IndexType</code> of this
|
||||
* <code>IndexBuffer</code>.
|
||||
*/
|
||||
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer) {
|
||||
setBuffer(engine, buffer, 0, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously copy-initializes a region of this <code>IndexBuffer</code> from the data
|
||||
* provided.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>IndexBuffer</code> with
|
||||
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
|
||||
* <code>IndexBuffer</code>. <code>buffer</code> should contain raw,
|
||||
* untyped data that will be interpreted as either 16-bit or 32-bits
|
||||
* indices based on the <code>IndexType</code> of this
|
||||
* <code>IndexBuffer</code>.
|
||||
* @param destOffsetInBytes offset in <i>bytes</i> into the <code>IndexBuffer</code>
|
||||
* @param count number of buffer elements to consume, defaults to
|
||||
* <code>buffer.remaining()</code>
|
||||
*/
|
||||
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer,
|
||||
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count) {
|
||||
setBuffer(engine, buffer, destOffsetInBytes, count, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid handler types:
|
||||
* - Android: Handler, Executor
|
||||
* - Other: Executor
|
||||
* Asynchronously copy-initializes a region of this <code>IndexBuffer</code> from the data
|
||||
* provided.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>IndexBuffer</code> with
|
||||
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
|
||||
* <code>IndexBuffer</code>. <code>buffer</code> should contain raw,
|
||||
* untyped data that will be interpreted as either 16-bit or 32-bits
|
||||
* indices based on the <code>IndexType</code> of this
|
||||
* <code>IndexBuffer</code>.
|
||||
* @param destOffsetInBytes offset in <i>bytes</i> into the <code>IndexBuffer</code>
|
||||
* @param count number of buffer elements to consume, defaults to
|
||||
* <code>buffer.remaining()</code>
|
||||
* @param handler an {@link java.util.concurrent.Executor Executor}. On Android this
|
||||
* can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback a callback executed by <code>handler</code> when <code>buffer</code>
|
||||
* is no longer needed.
|
||||
*/
|
||||
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer,
|
||||
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count,
|
||||
|
||||
@@ -23,6 +23,63 @@ import android.support.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByReflection;
|
||||
|
||||
/**
|
||||
* <code>IndirectLight</code> is used to simulate environment lighting, a form of global illumination.
|
||||
*
|
||||
* <p>Environment lighting has a two components:</p>
|
||||
* <ol>
|
||||
* <li>irradiance</li>
|
||||
* <li>reflections (specular component)</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>Environments are usually captured as high-resolution HDR equirectangular images and processed
|
||||
* by the <b>cmgen</b> tool to generate the data needed by {@link IndirectLight}.</p>
|
||||
*
|
||||
* <p>Currently {@link IndirectLight} is intended to be used for "distant probes", that is, to represent
|
||||
* global illumination from a distant (i.e. at infinity) environment, such as the sky or distant
|
||||
* mountains. Only a single {@link IndirectLight} can be used in a {@link Scene}.
|
||||
* This limitation will be lifted in the future.</p>
|
||||
*
|
||||
*
|
||||
* <h1>Creation and destruction</h1>
|
||||
*
|
||||
* <p>An {@link IndirectLight} object is created using the {@link IndirectLight.Builder} and
|
||||
* destroyed by calling {@link Engine#destroyIndirectLight}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* Engine engine = Engine.create();
|
||||
*
|
||||
* Scene scene = engine.createScene();
|
||||
*
|
||||
* IndirectLight environment = new IndirectLight.Builder()
|
||||
* .reflections(cubemap)
|
||||
* .irradiance(numBands, sphericalHarmonicsCoefficients)
|
||||
* .build(engine);
|
||||
*
|
||||
* scene.setIndirectLight(environment);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <h1>Irradiance</h1>
|
||||
*
|
||||
* <p>The irradiance represents the light that comes from the environment and shines an
|
||||
* object's surface. It is represented as
|
||||
* <a href="https://en.wikipedia.org/wiki/Spherical_harmonics">Spherical Harmonics</a> (SH) of 1, 2 or
|
||||
* 3 bands, respectively 1, 4 or 9 coefficients.</p>
|
||||
*
|
||||
* <p>Use the <b>cmgen</b> tool to generate the Spherical Harmonics for a given environment.</p>
|
||||
*
|
||||
*
|
||||
* <h1>Reflections</h1>
|
||||
*
|
||||
* <p>The reflections on object surfaces (specular component) is calculated from a specially
|
||||
* filtered cubemap pyramid generated by the <b>cmgen</b> tool.</p>
|
||||
*
|
||||
* @see Scene
|
||||
* @see LightManager
|
||||
* @see Texture
|
||||
* @see Skybox
|
||||
*/
|
||||
public class IndirectLight {
|
||||
long mNativeObject;
|
||||
|
||||
@@ -31,22 +88,97 @@ public class IndirectLight {
|
||||
mNativeObject = indirectLight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct an <code>IndirectLight</code> object instance.
|
||||
*/
|
||||
public static class Builder {
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
private final long mNativeBuilder;
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct an <code>IndirectLight</code> object instance.
|
||||
*/
|
||||
public Builder() {
|
||||
mNativeBuilder = nCreateBuilder();
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reflections cubemap mipmap chain.
|
||||
*
|
||||
* @param cubemap A mip-mapped cubemap generated by <b>cmgen</b>. Each cubemap level
|
||||
* encodes the irradiance for a roughness level.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
public Builder reflections(@NonNull Texture cubemap) {
|
||||
nBuilderReflections(mNativeBuilder, cubemap.getNativeObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the irradiance as Spherical Harmonics.
|
||||
*
|
||||
* <p>The irradiance coefficients must be pre-convolved by <code>< n &sdot l ></code> and
|
||||
* pre-multiplied by the Lambertian diffuse BRDF <code>1/&pi</code> and
|
||||
* specified as Spherical Harmonics coefficients.</p>
|
||||
*
|
||||
* <p>Additionally, these Spherical Harmonics coefficients must be pre-scaled by the
|
||||
* reconstruction factors A<sup>l,m</sup>.</p>
|
||||
*
|
||||
* <p>The final coefficients can be generated using the <code>cmgen</code> tool.</p>
|
||||
*
|
||||
* <p>The index in the <code>sh</code> array is given by:
|
||||
* <br><code>index(l, m) = 3 × (l * (l + 1) + m)</code>
|
||||
* <br><code>sh[index(l,m) + 0] = L<sub>R</sub><sup>l,m</sup>
|
||||
* × 1/&pi
|
||||
* × A<sup>l,m</sup>
|
||||
* × C<sup>l</sup> </code>
|
||||
* <br><code>sh[index(l,m) + 1] = L<sub>G</sub><sup>l,m</sup>
|
||||
* × 1/&pi
|
||||
* × A<sup>l,m</sup>
|
||||
* × C<sup>l</sup> </code>
|
||||
* <br><code>sh[index(l,m) + 2] = L<sub>B</sub><sup>l,m</sup>
|
||||
* × 1/&pi
|
||||
* × A<sup>l,m</sup>
|
||||
* × C<sup>l</sup> </code>
|
||||
* </p>
|
||||
*
|
||||
* <center>
|
||||
* <table border="1" cellpadding="3">
|
||||
* <tr><th> index </th><th> l </th><th> m </th><th> A<sup>l,m</sup> </th><th> C<sup>l</sup> </th>
|
||||
* <th> 1/&pi × A<sup>l,m</sup> × C<sup>l</sup></th></tr>
|
||||
* <tr align="right"><td>0</td><td>0</td><td> 0</td><td> 0.282095</td><td>3.1415926</td><td> 0.282095</td></tr>
|
||||
* <tr align="right"><td>1</td><td>1</td><td>-1</td><td>-0.488602</td><td>2.0943951</td><td>-0.325735</td></tr>
|
||||
* <tr align="right"><td>2</td><td>1</td><td> 0</td><td> 0.488602</td><td>2.0943951</td><td> 0.325735</td></tr>
|
||||
* <tr align="right"><td>3</td><td>1</td><td> 1</td><td>-0.488602</td><td>2.0943951</td><td>-0.325735</td></tr>
|
||||
* <tr align="right"><td>4</td><td>2</td><td>-2</td><td> 1.092548</td><td>0.785398 </td><td> 0.273137</td></tr>
|
||||
* <tr align="right"><td>5</td><td>2</td><td>-1</td><td>-1.092548</td><td>0.785398 </td><td>-0.273137</td></tr>
|
||||
* <tr align="right"><td>6</td><td>2</td><td> 0</td><td> 0.315392</td><td>0.785398 </td><td> 0.078848</td></tr>
|
||||
* <tr align="right"><td>7</td><td>2</td><td> 1</td><td>-1.092548</td><td>0.785398 </td><td>-0.273137</td></tr>
|
||||
* <tr align="right"><td>8</td><td>2</td><td> 2</td><td> 0.546274</td><td>0.785398 </td><td> 0.136569</td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
*
|
||||
*
|
||||
* <p>Only 1, 2 or 3 bands are allowed.</p>
|
||||
*
|
||||
* <p>Because the coefficients are pre-scaled, <code>sh[0]</code> is the environment's
|
||||
* average irradiance.</p>
|
||||
*
|
||||
* @param bands Number of spherical harmonics bands. Must be 1, 2 or 3.
|
||||
* @param sh Array containing the spherical harmonics coefficients.
|
||||
* The size of the array must be <code>3 × bands<sup>2</sup></code>
|
||||
* (i.e. 1, 4 or 9 <code>float3</code> coefficients respectively).
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException if the <code>sh</code> array length is smaller
|
||||
* than 3 × bands<sup>2</sup>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder irradiance(@IntRange(from=1, to=3) int bands, @NonNull float[] sh) {
|
||||
switch (bands) {
|
||||
@@ -65,6 +197,44 @@ public class IndirectLight {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the irradiance from the radiance expressed as Spherical Harmonics.
|
||||
*
|
||||
* <p>The radiance must be specified as Spherical Harmonics coefficients L<sup>l,m</sup>, where
|
||||
* each coefficient is comprised of three floats for red, green and blue components, respectively</p>
|
||||
*
|
||||
* <p>The index in the <code>sh</code> array is given by:
|
||||
* <br><code>index(l, m) = 3 × (l * (l + 1) + m)</code>
|
||||
* <br><code>sh[index(l,m) + 0] = L<sub>R</sub><sup>l,m</sup></code>
|
||||
* <br><code>sh[index(l,m) + 1] = L<sub>G</sub><sup>l,m</sup></code>
|
||||
* <br><code>sh[index(l,m) + 2] = L<sub>B</sub><sup>l,m</sup></code>
|
||||
* </p>
|
||||
*
|
||||
* <center>
|
||||
* <table border="1" cellpadding="3">
|
||||
* <tr><th> index </th><th> l </th><th> m </th>
|
||||
* <tr align="right"><td>0</td><td>0</td><td> 0</td>
|
||||
* <tr align="right"><td>1</td><td>1</td><td>-1</td>
|
||||
* <tr align="right"><td>2</td><td>1</td><td> 0</td>
|
||||
* <tr align="right"><td>3</td><td>1</td><td> 1</td>
|
||||
* <tr align="right"><td>4</td><td>2</td><td>-2</td>
|
||||
* <tr align="right"><td>5</td><td>2</td><td>-1</td>
|
||||
* <tr align="right"><td>6</td><td>2</td><td> 0</td>
|
||||
* <tr align="right"><td>7</td><td>2</td><td> 1</td>
|
||||
* <tr align="right"><td>8</td><td>2</td><td> 2</td>
|
||||
* </table>
|
||||
* </center>
|
||||
*
|
||||
* @param bands Number of spherical harmonics bands. Must be 1, 2 or 3.
|
||||
* @param sh Array containing the spherical harmonics coefficients.
|
||||
* The size of the array must be 3 × <code>bands<sup>2</sup></code>
|
||||
* (i.e. 1, 4 or 9 <code>float3</code> coefficients respectively).
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @exception ArrayIndexOutOfBoundsException if the <code>sh</code> array length is smaller
|
||||
* than 3 × bands<sup>2</sup>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder radiance(@IntRange(from=1, to=3) int bands, @NonNull float[] sh) {
|
||||
switch (bands) {
|
||||
@@ -83,18 +253,52 @@ public class IndirectLight {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the irradiance as a cubemap.
|
||||
* <p></p>
|
||||
* The irradiance can alternatively be specified as a cubemap instead of Spherical
|
||||
* Harmonics coefficients. It may or may not be more efficient, depending on your
|
||||
* hardware (essentially, it's trading ALU for bandwidth).
|
||||
* <p></p>
|
||||
* This irradiance cubemap can be generated with the <code>cmgen</code> tool.
|
||||
*
|
||||
* @param cubemap Cubemap representing the Irradiance pre-convolved by
|
||||
* <code>< n &sdot l ></code>.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @see #irradiance(int bands, float[] sh)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder irradiance(@NonNull Texture cubemap) {
|
||||
nIrradianceAsTexture(mNativeBuilder, cubemap.getNativeObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Environment intensity (optional).
|
||||
*
|
||||
* <p>Because the environment is encoded usually relative to some reference, the
|
||||
* range can be adjusted with this method.</p>
|
||||
*
|
||||
* @param envIntensity Scale factor applied to the environment and irradiance such that
|
||||
* the result is in cd/m^2 (lux) units (default = 30000)
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder intensity(float envIntensity) {
|
||||
nIntensity(mNativeBuilder, envIntensity);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the rigid-body transformation to apply to the IBL.
|
||||
*
|
||||
* @param rotation 3x3 rotation matrix. Must be a rigid-body transform.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder rotation(@NonNull @Size(min = 9) float[] rotation) {
|
||||
nRotation(mNativeBuilder,
|
||||
@@ -104,6 +308,15 @@ public class IndirectLight {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the IndirectLight object and returns a pointer to it.
|
||||
*
|
||||
* @param engine The {@link Engine} to associate this <code>IndirectLight</code> with.
|
||||
*
|
||||
* @return A newly created <code>IndirectLight</code>
|
||||
*
|
||||
* @exception IllegalStateException if a parameter to a builder function was invalid.
|
||||
*/
|
||||
@NonNull
|
||||
public IndirectLight build(@NonNull Engine engine) {
|
||||
long nativeIndirectLight = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -128,14 +341,31 @@ public class IndirectLight {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the environment's intensity.
|
||||
*
|
||||
* <p>Because the environment is encoded usually relative to some reference, the
|
||||
* range can be adjusted with this method.</p>
|
||||
*
|
||||
* @param intensity Scale factor applied to the environment and irradiance such that
|
||||
* the result is in cd/m^2 units (default = 30000)
|
||||
*/
|
||||
public void setIntensity(float intensity) {
|
||||
nSetIntensity(getNativeObject(), intensity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment's intensity in cd/m<sup>2</sup>.
|
||||
*/
|
||||
public float getIntensity() {
|
||||
return nGetIntensity(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rigid-body transformation to apply to the IBL.
|
||||
*
|
||||
* @param rotation 3x3 rotation matrix. Must be a rigid-body transform.
|
||||
*/
|
||||
public void setRotation(@NonNull @Size(min = 9) float[] rotation) {
|
||||
Asserts.assertMat3fIn(rotation);
|
||||
nSetRotation(getNativeObject(),
|
||||
@@ -144,6 +374,14 @@ public class IndirectLight {
|
||||
rotation[6], rotation[7], rotation[8]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rigid-body transformation applied to the IBL.
|
||||
*
|
||||
* @param rotation an array of 9 floats to receive the rigid-body transformation applied to
|
||||
* the IBL or <code>null</code>
|
||||
* @return the <code>rotation</code> paramter if it was provided, or a newly allocated float
|
||||
* array containing the rigid-body transformation applied to the IBL
|
||||
*/
|
||||
@NonNull @Size(min = 9)
|
||||
public float[] getRotation(@Nullable @Size(min = 9) float[] rotation) {
|
||||
rotation = Asserts.assertMat3f(rotation);
|
||||
@@ -151,6 +389,27 @@ public class IndirectLight {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to estimate the direction of the dominant light in the environment.
|
||||
*
|
||||
* <p>This assumes that there is only a single dominant light (such as the sun in outdoors
|
||||
* environments), if it's not the case the direction returned will be an average of the
|
||||
* various lights based on their intensity.</p>
|
||||
*
|
||||
* <p>If there are no clear dominant light, as is often the case with low dynamic range (LDR)
|
||||
* environments, this method may return a wrong or unexpected direction.</p>
|
||||
*
|
||||
* <p>The dominant light direction can be used to set a directional light's direction,
|
||||
* for instance to produce shadows that match the environment.</p>
|
||||
*
|
||||
* @param direction an array of 3 floats to receive a unit vector representing the direction of
|
||||
* the dominant light or <code>null</code>
|
||||
* @return the <code>direction</code> paramter if it was provided, or a newly allocated float
|
||||
* array containing a unit vector representing the direction of the dominant light
|
||||
*
|
||||
* @see LightManager.Builder#direction
|
||||
* @see #getColorEstimate
|
||||
*/
|
||||
@NonNull @Size(min = 3)
|
||||
public float[] getDirectionEstimate(@Nullable @Size(min = 3) float[] direction) {
|
||||
direction = Asserts.assertFloat3(direction);
|
||||
@@ -158,6 +417,26 @@ public class IndirectLight {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to estimate the color and relative intensity of the environment in a given direction.
|
||||
*
|
||||
* <p>This can be used to set the color and intensity of a directional light. In this case
|
||||
* make sure to multiply this relative intensity by the the intensity of this indirect light.</p>
|
||||
*
|
||||
* @param colorIntensity an array of 4 floats to receive the result or <code>null</code>
|
||||
* @param x the x coordinate of a unit vector representing the direction of the light
|
||||
* @param y the x coordinate of a unit vector representing the direction of the light
|
||||
* @param z the x coordinate of a unit vector representing the direction of the light
|
||||
*
|
||||
* @return A vector of 4 floats where the first 3 components represent the linear color and
|
||||
* the 4th component represents the intensity of the dominant light
|
||||
*
|
||||
* @see LightManager.Builder#color
|
||||
* @see LightManager.Builder#intensity
|
||||
* @see #getDirectionEstimate
|
||||
* @see #getIntensity
|
||||
* @see #setIntensity
|
||||
*/
|
||||
@NonNull @Size(min = 4)
|
||||
public float[] getColorEstimate(@Nullable @Size(min = 4) float[] colorIntensity, float x, float y, float z) {
|
||||
colorIntensity = Asserts.assertFloat4(colorIntensity);
|
||||
|
||||
@@ -29,45 +29,157 @@ import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A Filament Material defines the visual appearance of an object. Materials function as a
|
||||
* templates from which {@link MaterialInstance}s can be spawned. Use {@link Builder} to construct
|
||||
* a Material object.
|
||||
*
|
||||
* @see <a href="https://google.github.io/filament/Materials.html">Filament Materials Guide</a>
|
||||
*/
|
||||
public class Material {
|
||||
private long mNativeObject;
|
||||
private final MaterialInstance mDefaultInstance;
|
||||
|
||||
private Set<VertexBuffer.VertexAttribute> mRequiredAttributes;
|
||||
|
||||
/** Supported shading models */
|
||||
public enum Shading {
|
||||
/**
|
||||
* No lighting applied, emissive possible
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels/unlitmodel">
|
||||
* Unlit model</a>
|
||||
*/
|
||||
UNLIT,
|
||||
|
||||
/**
|
||||
* Default, standard lighting
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels/litmodel">
|
||||
* Lit model</a>
|
||||
*/
|
||||
LIT,
|
||||
|
||||
/**
|
||||
* Subsurface lighting model
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels/subsurfacemodel">
|
||||
* Subsurface model</a>
|
||||
*/
|
||||
SUBSURFACE,
|
||||
|
||||
/**
|
||||
* Cloth lighting model
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels/clothmodel">
|
||||
* Cloth model</a>
|
||||
*/
|
||||
CLOTH,
|
||||
|
||||
/**
|
||||
* Legacy lighting model
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels/specularglossiness">
|
||||
* Specular glossiness</a>
|
||||
*/
|
||||
SPECULAR_GLOSSINESS
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute interpolation types in the fragment shader
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:interpolation">
|
||||
* Vertex and attributes: interpolation</a>
|
||||
*/
|
||||
public enum Interpolation {
|
||||
/** Default, smooth interpolation */
|
||||
SMOOTH,
|
||||
|
||||
/** Flat interpolation */
|
||||
FLAT
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported blending modes
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/blendingandtransparency:blending">
|
||||
* Blending and transparency: blending</a>
|
||||
*/
|
||||
public enum BlendingMode {
|
||||
/** Material is opaque. */
|
||||
OPAQUE,
|
||||
|
||||
/**
|
||||
* Material is transparent and color is alpha-pre-multiplied.
|
||||
* Affects diffuse lighting only.
|
||||
*/
|
||||
TRANSPARENT,
|
||||
|
||||
/** Material is additive (e.g.: hologram). */
|
||||
ADD,
|
||||
MODULATE,
|
||||
|
||||
/** Material is masked (i.e. alpha tested). */
|
||||
MASKED,
|
||||
FADE
|
||||
|
||||
/**
|
||||
* Material is transparent and color is alpha-pre-multiplied.
|
||||
* Affects specular lighting.
|
||||
*/
|
||||
FADE,
|
||||
|
||||
/** Material darkens what's behind it. */
|
||||
MULTIPLY,
|
||||
|
||||
/** Material brightens what's behind it. */
|
||||
SCREEN,
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported types of vertex domains
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:vertexdomain">
|
||||
* Vertex and attributes: vertexDomain</a>
|
||||
*/
|
||||
public enum VertexDomain {
|
||||
/** Vertices are in object space, default. */
|
||||
OBJECT,
|
||||
|
||||
/** Vertices are in world space. */
|
||||
WORLD,
|
||||
|
||||
/** Vertices are in view space. */
|
||||
VIEW,
|
||||
|
||||
/** Vertices are in normalized device space. */
|
||||
DEVICE
|
||||
}
|
||||
|
||||
/**
|
||||
* Face culling Mode
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||
* Rasterization: culling</a>
|
||||
*/
|
||||
public enum CullingMode {
|
||||
/** No culling. Front and back faces are visible. */
|
||||
NONE,
|
||||
|
||||
/** Front face culling. Only back faces are visible. */
|
||||
FRONT,
|
||||
|
||||
/** Back face culling. Only front faces are visible. */
|
||||
BACK,
|
||||
|
||||
/** Front and back culling. Geometry is not visible. */
|
||||
FRONT_AND_BACK
|
||||
}
|
||||
|
||||
@@ -145,6 +257,13 @@ public class Material {
|
||||
private Buffer mBuffer;
|
||||
private int mSize;
|
||||
|
||||
/**
|
||||
* Specifies the material data. The material data is a binary blob produced by
|
||||
* libfilamat or by matc.
|
||||
*
|
||||
* @param buffer buffer containing material data
|
||||
* @param size size of the material data in bytes
|
||||
*/
|
||||
@NonNull
|
||||
public Builder payload(@NonNull Buffer buffer, @IntRange(from = 0) int size) {
|
||||
mBuffer = buffer;
|
||||
@@ -152,6 +271,15 @@ public class Material {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the Material object.
|
||||
*
|
||||
* @param engine reference to the Engine instance to associate this Material with
|
||||
*
|
||||
* @return the newly created object
|
||||
*
|
||||
* @exception IllegalStateException if the material could not be created
|
||||
*/
|
||||
@NonNull
|
||||
public Material build(@NonNull Engine engine) {
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(), mBuffer, mSize);
|
||||
@@ -160,6 +288,12 @@ public class Material {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this material. Material instances should be freed using
|
||||
* {@link Engine#destroyMaterialInstance(MaterialInstance)}.
|
||||
*
|
||||
* @return the new instance
|
||||
*/
|
||||
@NonNull
|
||||
public MaterialInstance createInstance() {
|
||||
long nativeInstance = nCreateInstance(getNativeObject());
|
||||
@@ -167,63 +301,163 @@ public class Material {
|
||||
return new MaterialInstance(this, nativeInstance);
|
||||
}
|
||||
|
||||
/** Returns the material's default instance. */
|
||||
@NonNull
|
||||
public MaterialInstance getDefaultInstance() {
|
||||
return mDefaultInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this material. The material name is used for debugging purposes.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:name">
|
||||
* General: name</a>
|
||||
*/
|
||||
public String getName() {
|
||||
return nGetName(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shading model of this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialmodels">
|
||||
* Material Models</a>
|
||||
*/
|
||||
public Shading getShading() {
|
||||
return Shading.values()[nGetShading(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interpolation mode of this material. This affects how variables are interpolated.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:interpolation">
|
||||
* Vertex and attributes: interpolation</a>
|
||||
*/
|
||||
public Interpolation getInterpolation() {
|
||||
return Interpolation.values()[nGetInterpolation(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the blending mode of this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/blendingandtransparency:blending">
|
||||
* Blending and transparency: blending</a>
|
||||
*/
|
||||
public BlendingMode getBlendingMode() {
|
||||
return BlendingMode.values()[nGetBlendingMode(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex domain of this material.
|
||||
*
|
||||
* @se
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:vertexdomain">
|
||||
* Vertex and attributes: vertexDomain</a>
|
||||
* @return
|
||||
*/
|
||||
public VertexDomain getVertexDomain() {
|
||||
return VertexDomain.values()[nGetVertexDomain(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default culling mode of this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||
* Rasterization: culling</a>
|
||||
*/
|
||||
public CullingMode getCullingMode() {
|
||||
return CullingMode.values()[nGetCullingMode(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this material will write to the color buffer.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:colorwrite">
|
||||
* Rasterization: colorWrite</a>
|
||||
*/
|
||||
public boolean isColorWriteEnabled() {
|
||||
return nIsColorWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this material will write to the depth buffer.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthwrite">
|
||||
* Rasterization: depthWrite</a>
|
||||
*/
|
||||
public boolean isDepthWriteEnabled() {
|
||||
return nIsDepthWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this material will use depth testing.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthculling">
|
||||
* Rasterization: depthCulling</a>
|
||||
*/
|
||||
public boolean isDepthCullingEnabled() {
|
||||
return nIsDepthCullingEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this material is double-sided.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:doublesided">
|
||||
* Rasterization: doubleSided</a>
|
||||
*/
|
||||
public boolean isDoubleSided() {
|
||||
return nIsDoubleSided(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alpha mask threshold used when the blending mode is set to masked.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/blendingandtransparency:maskthreshold">
|
||||
* Blending and transparency: maskThreshold</a>
|
||||
*/
|
||||
public float getMaskThreshold() {
|
||||
return nGetMaskThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the screen-space variance for specular-antialiasing. This value is between 0 and 1.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance">
|
||||
* Anti-aliasing: specularAntiAliasingVariance</a>
|
||||
*/
|
||||
public float getSpecularAntiAliasingVariance() {
|
||||
return nGetSpecularAntiAliasingVariance(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clamping threshold for specular-antialiasing. This value is between 0 and 1.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold">
|
||||
* Anti-aliasing: specularAntiAliasingThreshold</a>
|
||||
*/
|
||||
public float getSpecularAntiAliasingThreshold() {
|
||||
return nGetSpecularAntiAliasingThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of {@link VertexBuffer.VertexAttribute}s that are required by this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:requires">
|
||||
* Vertex and attributes: requires</a>
|
||||
*/
|
||||
public Set<VertexBuffer.VertexAttribute> getRequiredAttributes() {
|
||||
if (mRequiredAttributes == null) {
|
||||
int bitSet = nGetRequiredAttributes(getNativeObject());
|
||||
@@ -239,14 +473,38 @@ public class Material {
|
||||
return mRequiredAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bit set representing the set of {@link VertexBuffer.VertexAttribute}s that are
|
||||
* required by this material. Use {@link #getRequiredAttributes()} to get these as a Set object.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/vertexandattributes:requires">
|
||||
* Vertex and attributes: requires</a>
|
||||
*/
|
||||
int getRequiredAttributesAsInt() {
|
||||
return nGetRequiredAttributes(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of parameters declared by this material.
|
||||
* The returned value can be 0.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:parameters">
|
||||
* General: parameters</a>
|
||||
*/
|
||||
public int getParameterCount() {
|
||||
return nGetParameterCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Parameter objects representing this material's parameters.
|
||||
* The list may be empty if the material has no declared parameters.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:parameters">
|
||||
* General: parameters</a>
|
||||
*/
|
||||
public List<Parameter> getParameters() {
|
||||
int count = getParameterCount();
|
||||
List<Parameter> parameters = new ArrayList<>(count);
|
||||
@@ -254,86 +512,308 @@ public class Material {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a parameter of the given name exists on this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:parameters">
|
||||
* General: parameters</a>
|
||||
*/
|
||||
public boolean hasParameter(@NonNull String name) {
|
||||
return nHasParameter(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, boolean x) {
|
||||
mDefaultInstance.setParameter(name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, float x) {
|
||||
mDefaultInstance.setParameter(name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an int parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, int x) {
|
||||
mDefaultInstance.setParameter(name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool2 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, boolean x, boolean y) {
|
||||
mDefaultInstance.setParameter(name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float2 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, float x, float y) {
|
||||
mDefaultInstance.setParameter(name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an int2 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, int x, int y) {
|
||||
mDefaultInstance.setParameter(name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool3 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, boolean x, boolean y, boolean z) {
|
||||
mDefaultInstance.setParameter(name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float3 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, float x, float y, float z) {
|
||||
mDefaultInstance.setParameter(name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a int3 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, int x, int y, int z) {
|
||||
mDefaultInstance.setParameter(name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool4 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, boolean x, boolean y, boolean z, boolean w) {
|
||||
mDefaultInstance.setParameter(name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float4 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, float x, float y, float z, float w) {
|
||||
mDefaultInstance.setParameter(name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a int4 parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, int x, int y, int z, int w) {
|
||||
mDefaultInstance.setParameter(name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bool parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 bool4s:
|
||||
* <pre>{@code
|
||||
* boolean[] a = new boolean[4 * 4];
|
||||
* material.setDefaultParameter("param", MaterialInstance.BooleanElement.BOOL4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* boolean[] a = new boolean[4 * 3];
|
||||
* material.setDefaultParameter("param", MaterialInstance.BooleanElement.BOOL4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name,
|
||||
@NonNull MaterialInstance.BooleanElement type, @NonNull @Size(min = 1) boolean[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
mDefaultInstance.setParameter(name, type, v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an int parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 int4s:
|
||||
* <pre>{@code
|
||||
* int[] a = new int[4 * 4];
|
||||
* material.setDefaultParameter("param", MaterialInstance.IntElement.INT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* int[] a = new int[4 * 3];
|
||||
* material.setDefaultParameter("param", MaterialInstance.IntElement.INT4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name,
|
||||
@NonNull MaterialInstance.IntElement type, @NonNull @Size(min = 1) int[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
mDefaultInstance.setParameter(name, type, v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a float parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 float4s:
|
||||
* <pre>{@code
|
||||
* float[] a = new float[4 * 4];
|
||||
* material.setDefaultParameter("param", MaterialInstance.FloatElement.FLOAT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* float[] a = new float[4 * 3];
|
||||
* material.setDefaultParameter("param", MaterialInstance.FloatElement.FLOAT4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name,
|
||||
@NonNull MaterialInstance.FloatElement type, @NonNull @Size(min = 1) float[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
mDefaultInstance.setParameter(name, type, v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the given parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material color parameter
|
||||
* @param type whether the color is specified in the linear or sRGB space
|
||||
* @param r red component
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, @NonNull Colors.RgbType type,
|
||||
float r, float g, float b) {
|
||||
mDefaultInstance.setParameter(name, type, r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the given parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material color parameter
|
||||
* @param type whether the color is specified in the linear or sRGB space
|
||||
* @param r red component
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
* @param a alpha component
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name, @NonNull Colors.RgbaType type,
|
||||
float r, float g, float b, float a) {
|
||||
mDefaultInstance.setParameter(name, type, r, g, b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a texture and sampler parameter on this material's default instance.
|
||||
*
|
||||
* @param name The name of the material texture parameter
|
||||
* @param texture The texture to set as parameter
|
||||
* @param sampler The sampler to be used with this texture
|
||||
*
|
||||
* @see Material#getDefaultInstance()
|
||||
*/
|
||||
public void setDefaultParameter(@NonNull String name,
|
||||
@NonNull Texture texture, @NonNull TextureSampler sampler) {
|
||||
mDefaultInstance.setParameter(name, texture, sampler);
|
||||
|
||||
@@ -58,6 +58,7 @@ public class MaterialInstance {
|
||||
mNativeObject = nativeMaterialInstance;
|
||||
}
|
||||
|
||||
/** @return the {@link Material} associated with this instance */
|
||||
@NonNull
|
||||
public Material getMaterial() {
|
||||
if (mMaterial == null) {
|
||||
@@ -66,118 +67,365 @@ public class MaterialInstance {
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x) {
|
||||
nSetParameterBool(getNativeObject(), name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x) {
|
||||
nSetParameterFloat(getNativeObject(), name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an int parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the material parameter
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x) {
|
||||
nSetParameterInt(getNativeObject(), name, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool2 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y) {
|
||||
nSetParameterBool2(getNativeObject(), name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float2 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y) {
|
||||
nSetParameterFloat2(getNativeObject(), name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an int2 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y) {
|
||||
nSetParameterInt2(getNativeObject(), name, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool3 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y, boolean z) {
|
||||
nSetParameterBool3(getNativeObject(), name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float3 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y, float z) {
|
||||
nSetParameterFloat3(getNativeObject(), name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a int3 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y, int z) {
|
||||
nSetParameterInt3(getNativeObject(), name, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a bool4 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, boolean x, boolean y, boolean z, boolean w) {
|
||||
nSetParameterBool4(getNativeObject(), name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a float4 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, float x, float y, float z, float w) {
|
||||
nSetParameterFloat4(getNativeObject(), name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a int4 parameter.
|
||||
*
|
||||
* @param name the name of the material parameter
|
||||
* @param x the value of the first component
|
||||
* @param y the value of the second component
|
||||
* @param z the value of the third component
|
||||
* @param w the value of the fourth component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, int x, int y, int z, int w) {
|
||||
nSetParameterInt4(getNativeObject(), name, x, y, z, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a texture and sampler parameter on this material's default instance.
|
||||
*
|
||||
* @param name The name of the material texture parameter
|
||||
* @param texture The texture to set as parameter
|
||||
* @param sampler The sampler to be used with this texture
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull Texture texture, @NonNull TextureSampler sampler) {
|
||||
nSetParameterTexture(getNativeObject(), name, texture.getNativeObject(), sampler.mSampler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a bool parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 bool4s:
|
||||
* <pre>{@code
|
||||
* boolean[] a = new boolean[4 * 4];
|
||||
* instance.setParameter("param", MaterialInstance.BooleanElement.BOOL4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* boolean[] a = new boolean[4 * 3];
|
||||
* instance.setParameter("param", MaterialInstance.BooleanElement.BOOL4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull BooleanElement type, @NonNull boolean[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
nSetBooleanParameterArray(getNativeObject(), name, type.ordinal(), v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an int parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 int4s:
|
||||
* <pre>{@code
|
||||
* int[] a = new int[4 * 4];
|
||||
* instance.setParameter("param", MaterialInstance.IntElement.INT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* int[] a = new int[4 * 3];
|
||||
* instance.setParameter("param", MaterialInstance.IntElement.INT4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull IntElement type, @NonNull int[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
nSetIntParameterArray(getNativeObject(), name, type.ordinal(), v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a float parameter array by name.
|
||||
*
|
||||
* @param name name of the parameter array as defined by this Material
|
||||
* @param type the number of components for each individual parameter
|
||||
* @param v array of values to set to the named parameter array
|
||||
* @param offset the number of elements to skip
|
||||
* @param count the number of elements in the parameter array to set
|
||||
*
|
||||
* <p>For example, to set a parameter array of 4 float4s:
|
||||
* <pre>{@code
|
||||
* float[] a = new float[4 * 4];
|
||||
* material.setDefaultParameter("param", MaterialInstance.FloatElement.FLOAT4, a, 0, 4);
|
||||
* }</pre>
|
||||
* To only set the last 3 elements, specify an offset of 1 and a count of 3:
|
||||
* <pre>{@code
|
||||
* float[] a = new float[4 * 3];
|
||||
* material.setDefaultParameter("param", MaterialInstance.FloatElement.FLOAT4, a, 1, 3);
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public void setParameter(@NonNull String name,
|
||||
@NonNull FloatElement type, @NonNull float[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count) {
|
||||
nSetFloatParameterArray(getNativeObject(), name, type.ordinal(), v, offset, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the given parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material color parameter
|
||||
* @param type whether the color is specified in the linear or sRGB space
|
||||
* @param r red component
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, @NonNull Colors.RgbType type,
|
||||
float r, float g, float b) {
|
||||
float[] color = Colors.toLinear(type, r, g, b);
|
||||
nSetParameterFloat3(getNativeObject(), name, color[0], color[1], color[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the given parameter on this material's default instance.
|
||||
*
|
||||
* @param name the name of the material color parameter
|
||||
* @param type whether the color is specified in the linear or sRGB space
|
||||
* @param r red component
|
||||
* @param g green component
|
||||
* @param b blue component
|
||||
* @param a alpha component
|
||||
*/
|
||||
public void setParameter(@NonNull String name, @NonNull Colors.RgbaType type,
|
||||
float r, float g, float b, float a) {
|
||||
float[] color = Colors.toLinear(type, r, g, b, a);
|
||||
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a custom scissor rectangle; by default this encompasses the View.
|
||||
*
|
||||
* @param left left coordinate of the scissor box
|
||||
* @param bottom bottom coordinate of the scissor box
|
||||
* @param width width of the scissor box
|
||||
* @param height height of the scissor box
|
||||
*/
|
||||
public void setScissor(@IntRange(from = 0) int left, @IntRange(from = 0) int bottom,
|
||||
@IntRange(from = 0) int width, @IntRange(from = 0) int height) {
|
||||
nSetScissor(getNativeObject(), left, bottom, width, height);
|
||||
}
|
||||
|
||||
/** Returns the scissor rectangle to its default setting, which encompasses the View. */
|
||||
public void unsetScissor() {
|
||||
nUnsetScissor(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a polygon offset that will be applied to all renderables drawn with this material
|
||||
* instance.
|
||||
*
|
||||
* The value of the offset is scale * dz + r * constant, where dz is the change in depth
|
||||
* relative to the screen area of the triangle, and r is the smallest value that is guaranteed
|
||||
* to produce a resolvable offset for a given implementation. This offset is added before the
|
||||
* depth test.
|
||||
*
|
||||
* @warning using a polygon offset other than zero has a significant negative performance
|
||||
* impact, as most implementations have to disable early depth culling. DO NOT USE unless
|
||||
* absolutely necessary.
|
||||
*
|
||||
* @param scale scale factor used to create a variable depth offset for each triangle
|
||||
* @param constant scale factor used to create a constant depth offset for each triangle
|
||||
*/
|
||||
public void setPolygonOffset(float scale, float constant) {
|
||||
nSetPolygonOffset(getNativeObject(), scale, constant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the minimum alpha value a fragment must have to not be discarded when the blend
|
||||
* mode is MASKED. Defaults to 0.4 if it has not been set in the parent Material. The specified
|
||||
* value should be between 0 and 1 and will be clamped if necessary.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/blendingandtransparency:maskthreshold">
|
||||
* Blending and transparency: maskThreshold</a>
|
||||
*/
|
||||
public void setMaskThreshold(float threshold) {
|
||||
nSetMaskThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing. The default value is set to 0.15. The specified value should be between
|
||||
* 0 and 1 and will be clamped if necessary.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/anti-aliasing:specularantialiasingvariance">
|
||||
* Anti-aliasing: specularAntiAliasingVariance</a>
|
||||
*/
|
||||
public void setSpecularAntiAliasingVariance(float variance) {
|
||||
nSetSpecularAntiAliasingVariance(getNativeObject(), variance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
|
||||
* and 1 and will be clamped if necessary.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/anti-aliasing:specularantialiasingthreshold">
|
||||
* Anti-aliasing: specularAntiAliasingThreshold</a>
|
||||
*/
|
||||
public void setSpecularAntiAliasingThreshold(float threshold) {
|
||||
nSetSpecularAntiAliasingThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
|
||||
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
|
||||
* automatically disabled.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:doublesided">
|
||||
* Rasterization: doubleSided</a>
|
||||
*/
|
||||
public void setDoubleSided(boolean doubleSided) {
|
||||
nSetDoubleSided(getNativeObject(), doubleSided);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default triangle culling state that was set on the material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||
* Rasterization: culling</a>
|
||||
*/
|
||||
public void setCullingMode(Material.CullingMode mode) {
|
||||
nSetCullingMode(getNativeObject(), mode.ordinal());
|
||||
}
|
||||
|
||||
@@ -23,6 +23,29 @@ import android.support.annotation.Size;
|
||||
public final class MathUtils {
|
||||
private MathUtils() { }
|
||||
|
||||
/**
|
||||
* Packs the tangent frame represented by the specified tangent, bitangent, and normal into a
|
||||
* quaternion.
|
||||
*
|
||||
* <p>
|
||||
* Reflection is preserved by encoding it as the sign of the w component in the resulting
|
||||
* quaternion. Since -0 cannot always be represented on the GPU, this function computes a bias
|
||||
* to ensure values are always either positive or negative, never 0. The bias is computed based
|
||||
* on a per-element storage size of 2 bytes, making the resulting quaternion suitable for
|
||||
* storage into an SNORM16 vector.
|
||||
* </p>
|
||||
*
|
||||
* @param tangentX the X component of the tangent
|
||||
* @param tangentY the Y component of the tangent
|
||||
* @param tangentZ the Z component of the tangent
|
||||
* @param bitangentX the X component of the bitangent
|
||||
* @param bitangentY the Y component of the bitangent
|
||||
* @param bitangentZ the Z component of the bitangent
|
||||
* @param normalX the X component of the normal
|
||||
* @param normalY the Y component of the normal
|
||||
* @param normalZ the Z component of the normal
|
||||
* @param quaternion a float array of at least size 4 for the quaternion result to be stored
|
||||
*/
|
||||
public static void packTangentFrame(
|
||||
float tangentX, float tangentY, float tangentZ,
|
||||
float bitangentX, float bitangentY, float bitangentZ,
|
||||
@@ -34,6 +57,30 @@ public final class MathUtils {
|
||||
normalX, normalY, normalZ, quaternion, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packs the tangent frame represented by the specified tangent, bitangent, and normal into a
|
||||
* quaternion.
|
||||
*
|
||||
* <p>
|
||||
* Reflection is preserved by encoding it as the sign of the w component in the resulting
|
||||
* quaternion. Since -0 cannot always be represented on the GPU, this function computes a bias
|
||||
* to ensure values are always either positive or negative, never 0. The bias is computed based
|
||||
* on a per-element storage size of 2 bytes, making the resulting quaternion suitable for
|
||||
* storage into an SNORM16 vector.
|
||||
* </p>
|
||||
*
|
||||
* @param tangentX the X component of the tangent
|
||||
* @param tangentY the Y component of the tangent
|
||||
* @param tangentZ the Z component of the tangent
|
||||
* @param bitangentX the X component of the bitangent
|
||||
* @param bitangentY the Y component of the bitangent
|
||||
* @param bitangentZ the Z component of the bitangent
|
||||
* @param normalX the X component of the normal
|
||||
* @param normalY the Y component of the normal
|
||||
* @param normalZ the Z component of the normal
|
||||
* @param quaternion a float array of at least size 4 for the quaternion result to be stored
|
||||
* @param offset offset, in elements, into the quaternion array to store the results
|
||||
*/
|
||||
public static void packTangentFrame(
|
||||
float tangentX, float tangentY, float tangentZ,
|
||||
float bitangentX, float bitangentY, float bitangentZ,
|
||||
|
||||
@@ -20,6 +20,16 @@ import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An offscreen render target that can be associated with a {@link View} and contains
|
||||
* weak references to a set of attached {@link Texture} objects.
|
||||
*
|
||||
* <p>
|
||||
* Clients are responsible for the lifetime of all associated <code>Texture</code> attachments.
|
||||
* </p>
|
||||
*
|
||||
* @see View
|
||||
*/
|
||||
public class RenderTarget {
|
||||
private long mNativeObject;
|
||||
private final Texture[] mTextures = new Texture[2];
|
||||
@@ -37,11 +47,17 @@ public class RenderTarget {
|
||||
return mNativeObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* An attachment point is a slot that can be assigned to a {@link Texture}.
|
||||
*/
|
||||
public enum AttachmentPoint {
|
||||
COLOR,
|
||||
DEPTH,
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs <code>RenderTarget</code> objects using a builder pattern.
|
||||
*/
|
||||
public static class Builder {
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
@@ -53,6 +69,15 @@ public class RenderTarget {
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a texture to a given attachment point.
|
||||
*
|
||||
* <p>All RenderTargets must have a non-null <code>COLOR</code> attachment.</p>
|
||||
*
|
||||
* @param attachment The attachment point of the texture.
|
||||
* @param texture The associated texture object.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder texture(@NonNull AttachmentPoint attachment, @Nullable Texture texture) {
|
||||
mTextures[attachment.ordinal()] = texture;
|
||||
@@ -60,24 +85,51 @@ public class RenderTarget {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mipmap level for a given attachment point.
|
||||
*
|
||||
* @param attachment The attachment point of the texture.
|
||||
* @param level The associated mipmap level, 0 by default.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder mipLevel(@NonNull AttachmentPoint attachment, @IntRange(from = 0) int level) {
|
||||
nBuilderMipLevel(mNativeBuilder, attachment.ordinal(), level);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cubemap face for a given attachment point.
|
||||
*
|
||||
* @param attachment The attachment point.
|
||||
* @param face The associated cubemap face.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder face(@NonNull AttachmentPoint attachment, Texture.CubemapFace face) {
|
||||
nBuilderFace(mNativeBuilder, attachment.ordinal(), face.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the layer for a given attachment point (for 3D textures).
|
||||
*
|
||||
* @param attachment The attachment point.
|
||||
* @param layer The associated cubemap layer.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder layer(@NonNull AttachmentPoint attachment, @IntRange(from = 0) int layer) {
|
||||
nBuilderLayer(mNativeBuilder, attachment.ordinal(), layer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the RenderTarget object and returns a pointer to it.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occurred.
|
||||
*/
|
||||
@NonNull
|
||||
public RenderTarget build(@NonNull Engine engine) {
|
||||
long nativeRenderTarget = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -105,20 +157,45 @@ public class RenderTarget {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the texture set on the given attachment point.
|
||||
*
|
||||
* @param attachment Attachment point
|
||||
* @return A Texture object or nullptr if no texture is set for this attachment point
|
||||
*/
|
||||
@Nullable
|
||||
public Texture getTexture(@NonNull AttachmentPoint attachment) {
|
||||
return mTextures[attachment.ordinal()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mipmap level set on the given attachment point.
|
||||
*
|
||||
* @param attachment Attachment point
|
||||
* @return the mipmap level set on the given attachment point
|
||||
*/
|
||||
@IntRange(from = 0)
|
||||
public int getMipLevel(@NonNull AttachmentPoint attachment) {
|
||||
return nGetMipLevel(getNativeObject(), attachment.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the face of a cubemap set on the given attachment point.
|
||||
*
|
||||
* @param attachment Attachment point
|
||||
* @return A cubemap face identifier. This is only relevant if the attachment's texture is
|
||||
* a cubemap.
|
||||
*/
|
||||
public Texture.CubemapFace getFace(AttachmentPoint attachment) {
|
||||
return Texture.CubemapFace.values()[nGetFace(getNativeObject(), attachment.ordinal())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the texture-layer set on the given attachment point.
|
||||
*
|
||||
* @param attachment Attachment point
|
||||
* @return A texture layer. This is only relevant if the attachment's texture is a 3D texture.
|
||||
*/
|
||||
@IntRange(from = 0)
|
||||
public int getLayer(@NonNull AttachmentPoint attachment) {
|
||||
return nGetLayer(getNativeObject(), attachment.ordinal());
|
||||
|
||||
@@ -23,12 +23,51 @@ import java.nio.Buffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
|
||||
/**
|
||||
* A <code>Renderer</code> instance represents an operating system's window.
|
||||
*
|
||||
* <p>
|
||||
* Typically, applications create a <code>Renderer</code> per window. The <code>Renderer</code> generates
|
||||
* drawing commands for the render thread and manages frame latency.
|
||||
* <br>
|
||||
* A Renderer generates drawing commands from a View, itself containing a Scene description.
|
||||
* </p>
|
||||
*
|
||||
* <h1>Creation and Destruction</h1>
|
||||
*
|
||||
* <p>A <code>Renderer</code> is created using {@link Engine#createRenderer} and destroyed
|
||||
* using {@link Engine#destroyRenderer}.</p>
|
||||
*
|
||||
* @see Engine
|
||||
* @see View
|
||||
*/
|
||||
public class Renderer {
|
||||
private final Engine mEngine;
|
||||
private long mNativeObject;
|
||||
|
||||
/**
|
||||
* Indicates that the <code>dstSwapChain</code> passed into {@link #copyFrame} should be
|
||||
* committed after the frame has been copied.
|
||||
*
|
||||
* @see #copyFrame
|
||||
*/
|
||||
public static final int MIRROR_FRAME_FLAG_COMMIT = 0x1;
|
||||
|
||||
/**
|
||||
* Indicates that the presentation time should be set on the <code>dstSwapChain</code>
|
||||
* passed into {@link #copyFrame} to the monotonic clock time when the frame is
|
||||
* copied.
|
||||
*
|
||||
* @see #copyFrame
|
||||
*/
|
||||
public static final int MIRROR_FRAME_FLAG_SET_PRESENTATION_TIME = 0x2;
|
||||
|
||||
/**
|
||||
* Indicates that the <code>dstSwapChain</code> passed into {@link #copyFrame} should be
|
||||
* cleared to black before the frame is copied into the specified viewport.
|
||||
*
|
||||
* @see #copyFrame
|
||||
*/
|
||||
public static final int MIRROR_FRAME_FLAG_CLEAR = 0x4;
|
||||
|
||||
Renderer(@NonNull Engine engine, long nativeRenderer) {
|
||||
@@ -36,25 +75,128 @@ public class Renderer {
|
||||
mNativeObject = nativeRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Engine} that created this <code>Renderer</code>.
|
||||
*
|
||||
* @return {@link Engine} instance this <code>Renderer</code> is associated to.
|
||||
*/
|
||||
@NonNull
|
||||
public Engine getEngine() {
|
||||
return mEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a frame for this <code>Renderer</code>.
|
||||
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
|
||||
* drawn. The goal of this is to skip frames when the GPU falls behind in order to keep the frame
|
||||
* latency low.</p>
|
||||
*
|
||||
* <p>If a given frame takes too much time in the GPU, the CPU will get ahead of the GPU. The
|
||||
* display will draw the same frame twice producing a stutter. At this point, the CPU is
|
||||
* ahead of the GPU and depending on how many frames are buffered, latency increases.
|
||||
* beginFrame() attempts to detect this situation and returns <code>false</code> in that case,
|
||||
* indicating to the caller to skip the current frame.</p>
|
||||
*
|
||||
* <p>All calls to render() must happen <b>after</b> beginFrame().</p>
|
||||
*
|
||||
* @param swapChain the {@link SwapChain} instance to use
|
||||
*
|
||||
* @return <code>false</code> if the current frame must be skipped<br>
|
||||
* When skipping a frame, the whole frame is canceled, and {@link #endFrame} must not
|
||||
* be called.
|
||||
*
|
||||
* @see #endFrame
|
||||
* @see #render
|
||||
*/
|
||||
public boolean beginFrame(@NonNull SwapChain swapChain) {
|
||||
return nBeginFrame(getNativeObject(), swapChain.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the current frame and schedules it for display.
|
||||
* <p>
|
||||
* <code>endFrame()</code> schedules the current frame to be displayed on the
|
||||
* <code>Renderer</code>'s window.
|
||||
* </p>
|
||||
*
|
||||
* <br><p>All calls to render() must happen <b>before</b> endFrame().</p>
|
||||
*
|
||||
* @see #beginFrame
|
||||
* @see #render
|
||||
*/
|
||||
public void endFrame() {
|
||||
nEndFrame(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a {@link View} into this <code>Renderer</code>'s window.
|
||||
*
|
||||
* <p>
|
||||
* This is filament's main rendering method, most of the CPU-side heavy lifting is performed
|
||||
* here. The purpose of the <code>render()</code> function is to generate render commands which
|
||||
* are asynchronously executed by the {@link Engine}'s render thread.
|
||||
* </p>
|
||||
*
|
||||
* <p><code>render()</code> generates commands for each of the following stages:</p>
|
||||
* <ul>
|
||||
* <li>Shadow map pass, if needed (currently only a single shadow map is supported)</li>
|
||||
* <li>Depth pre-pass</li>
|
||||
* <li>SSAO pass, if enabled</li>
|
||||
* <li>Color pass</li>
|
||||
* <li>Post-processing pass</li>
|
||||
* </ul>
|
||||
*
|
||||
* A typical render loop looks like this:
|
||||
*
|
||||
* <pre>
|
||||
* void renderLoop(Renderer renderer, SwapChain swapChain) {
|
||||
* do {
|
||||
* // typically we wait for VSYNC and user input events
|
||||
* if (renderer.beginFrame(swapChain)) {
|
||||
* renderer.render(mView);
|
||||
* renderer.endFrame();
|
||||
* }
|
||||
* } while (!quit());
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <ul>
|
||||
*<li><code>render()</code> must be called <b>after</b> {@link #beginFrame} and <b>before</b>
|
||||
*{@link #endFrame}.</li>
|
||||
*
|
||||
*<li><code>render()</code> must be called from the {@link Engine}'s main thread
|
||||
*(or external synchronization must be provided). In particular, calls to <code>render()</code>
|
||||
*on different <code>Renderer</code> instances <b>must</b> be synchronized.</li>
|
||||
*
|
||||
*<li><code>render()</code> performs potentially heavy computations and cannot be multi-threaded.
|
||||
*However, internally, it is highly multi-threaded to both improve performance and mitigate
|
||||
*the call's latency.</li>
|
||||
*
|
||||
*<li><code>render()</code> is typically called once per frame (but not necessarily).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param view the {@link View} to render
|
||||
*
|
||||
* @see #beginFrame
|
||||
* @see #endFrame
|
||||
* @see View
|
||||
*
|
||||
*/
|
||||
public void render(@NonNull View view) {
|
||||
nRender(getNativeObject(), view.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method MUST be called before endFrame.
|
||||
* Copies the currently rendered {@link View} to the indicated {@link SwapChain}, using the
|
||||
* indicated source and destination rectangle.
|
||||
*
|
||||
* <p><code>copyFrame()</code> should be called after a frame is rendered using {@link #render}
|
||||
* but before {@link #endFrame} is called.</p>
|
||||
*
|
||||
* @param dstSwapChain the {@link SwapChain} into which the frame should be copied
|
||||
* @param dstViewport the destination rectangle in which to draw the view
|
||||
* @param srcViewport the source rectangle to be copied
|
||||
* @param flags one or more <code>CopyFrameFlag</code> behavior configuration flags
|
||||
*/
|
||||
public void copyFrame(
|
||||
@NonNull SwapChain dstSwapChain, @NonNull Viewport dstViewport,
|
||||
@@ -73,7 +215,68 @@ public class Renderer {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method MUST be called before endFrame.
|
||||
* Reads back the content of the {@link SwapChain} associated with this <code>Renderer</code>.
|
||||
*
|
||||
*<pre>
|
||||
*
|
||||
* Framebuffer as seen on User buffer (PixelBufferDescriptor)
|
||||
* screen
|
||||
* +--------------------+
|
||||
* | | .stride .alignment
|
||||
* | | ----------------------->-->
|
||||
* | | O----------------------+--+ low addresses
|
||||
* | | | | | |
|
||||
* | w | | | .top | |
|
||||
* | <---------> | | V | |
|
||||
* | +---------+ | | +---------+ | |
|
||||
* | | ^ | | ======> | | | | |
|
||||
* | x | h| | | |.left| | | |
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | ^ | | | |
|
||||
* | y | | +----------------------+--+ high addresses
|
||||
* O------------+-------+
|
||||
*
|
||||
*</pre>
|
||||
*
|
||||
*
|
||||
* <p>Typically <code>readPixels</code> will be called after {@link #render} and before
|
||||
* {@link #endFrame}.</p>
|
||||
* <br>
|
||||
* <p>After calling this method, the callback associated with <code>buffer</code>
|
||||
* will be invoked on the main thread, indicating that the read-back has completed.
|
||||
* Typically, this will happen after multiple calls to {@link #beginFrame},
|
||||
* {@link #render}, {@link #endFrame}.</p>
|
||||
* <br>
|
||||
* <p><code>readPixels</code> is intended for debugging and testing.
|
||||
* It will impact performance significantly.</p>
|
||||
*
|
||||
* @param xoffset left offset of the sub-region to read back
|
||||
* @param yoffset bottom offset of the sub-region to read back
|
||||
* @param width width of the sub-region to read back
|
||||
* @param height height of the sub-region to read back
|
||||
* @param buffer client-side buffer where the read-back will be written
|
||||
*
|
||||
* <p>
|
||||
* The following format are always supported:
|
||||
* <li>{@link Texture.Format#RGBA}</li>
|
||||
* <li>{@link Texture.Format#RGBA_INTEGER}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The following types are always supported:
|
||||
* <li>{@link Texture.Type#UBYTE}</li>
|
||||
* <li>{@link Texture.Type#UINT}</li>
|
||||
* <li>{@link Texture.Type#INT}</li>
|
||||
* <li>{@link Texture.Type#FLOAT}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>Other combination of format/type may be supported. If a combination is
|
||||
* not supported, this operation may fail silently. Use a DEBUG build
|
||||
* to get some logs about the failure.</p>
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*/
|
||||
public void readPixels(
|
||||
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
|
||||
@@ -96,11 +299,67 @@ public class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
double getUserTime() {
|
||||
/**
|
||||
* Returns a timestamp (in seconds) for the last call to {@link #beginFrame}. This value is
|
||||
* constant for all {@link View views} rendered during a frame. The epoch is set with
|
||||
* {@link #resetUserTime}.
|
||||
* <br>
|
||||
* <p>In materials, this value can be queried using <code>vec4 getUserTime()</code>. The value
|
||||
* returned is a <code>highp vec4</code> encoded as follows:</p>
|
||||
* <pre>
|
||||
* time.x = (float)Renderer.getUserTime();
|
||||
* time.y = Renderer.getUserTime() - time.x;
|
||||
* </pre>
|
||||
*
|
||||
* It follows that the following invariants are true:
|
||||
* <pre>
|
||||
* (double)time.x + (double)time.y == Renderer.getUserTime()
|
||||
* time.x == (float)Renderer.getUserTime()
|
||||
* </pre>
|
||||
*
|
||||
* This encoding allows the shader code to perform high precision (i.e. double) time
|
||||
* calculations when needed despite the lack of double precision in the shader, e.g.:
|
||||
* <br>
|
||||
* To compute <code>(double)time * vertex</code> in the material, use the following construct:
|
||||
* <pre>
|
||||
* vec3 result = time.x * vertex + time.y * vertex;
|
||||
* </pre>
|
||||
*
|
||||
* Most of the time, high precision computations are not required, but be aware that the
|
||||
* precision of <code>time.x</code> rapidly diminishes as time passes:
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr align="center"><th> time </th><th> precision </th></tr>
|
||||
* <tr align="center"><td> 16.7s </td><td> us </td></tr>
|
||||
* <tr align="center"><td> 4h39.7s </td><td> ms </td></tr>
|
||||
* <tr align="center"><td> 77h </td><td> 1/60s </td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
* <p>
|
||||
*
|
||||
* In other words, it is only possible to get microsecond accuracy for about 16s or millisecond
|
||||
* accuracy for just under 5h. This problem can be mitigated by calling {@link #resetUserTime},
|
||||
* or using high precision time as described above.
|
||||
*
|
||||
* @return the time in seconds since {@link #resetUserTime} was last called
|
||||
*
|
||||
* @see #resetUserTime
|
||||
*/
|
||||
public double getUserTime() {
|
||||
return nGetUserTime(getNativeObject());
|
||||
}
|
||||
|
||||
void resetUserTime() {
|
||||
/**
|
||||
* Sets the user time epoch to now, i.e. resets the user time to zero.
|
||||
* <br>
|
||||
* <p>Use this method used to keep the precision of time high in materials, in practice it should
|
||||
* be called at least when the application is paused, e.g.
|
||||
* {@link android.app.Activity#onPause() Activity.onPause} in Android.</p>
|
||||
*
|
||||
* @see #getUserTime
|
||||
*/
|
||||
public void resetUserTime() {
|
||||
nResetUserTime(getNativeObject());
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,28 @@ package com.google.android.filament;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A <code>Scene</code> is a flat container of {@link RenderableManager} and {@link LightManager}
|
||||
* components.
|
||||
* <br>
|
||||
* <p>A <code>Scene</code> doesn't provide a hierarchy of objects, i.e.: it's not a scene-graph.
|
||||
* However, it manages the list of objects to render and the list of lights. These can
|
||||
* be added or removed from a <code>Scene</code> at any time.
|
||||
* Moreover clients can use {@link TransformManager} to create a graph of transforms.</p>
|
||||
* <br>
|
||||
* <p>A {@link RenderableManager} component <b>must</b> be added to a <code>Scene</code> in order
|
||||
* to be rendered, and the <code>Scene</code> must be provided to a {@link View}.</p>
|
||||
*
|
||||
* <h1>Creation and Destruction</h1>
|
||||
*
|
||||
* A <code>Scene</code> is created using {@link Engine#createScene} and destroyed using
|
||||
* {@link Engine#destroyScene(Scene)}.
|
||||
*
|
||||
* @see View
|
||||
* @see LightManager
|
||||
* @see RenderableManager
|
||||
* @see TransformManager
|
||||
*/
|
||||
public class Scene {
|
||||
private long mNativeObject;
|
||||
private @Nullable Skybox mSkybox;
|
||||
@@ -27,35 +49,78 @@ public class Scene {
|
||||
mNativeObject = nativeScene;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Skybox} or <code>null</code> if none is set
|
||||
* @see #setSkybox(Skybox)
|
||||
*/
|
||||
@Nullable
|
||||
public Skybox getSkybox() {
|
||||
return mSkybox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Skybox}.
|
||||
*
|
||||
* The {@link Skybox} is drawn last and covers all pixels not touched by geometry.
|
||||
*
|
||||
* @param skybox the {@link Skybox} to use to fill untouched pixels,
|
||||
* or <code>null</code> to unset the {@link Skybox}.
|
||||
*/
|
||||
public void setSkybox(@Nullable Skybox skybox) {
|
||||
mSkybox = skybox;
|
||||
nSetSkybox(getNativeObject(), mSkybox != null ? mSkybox.getNativeObject() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link IndirectLight} or <code>null</code> if none is set
|
||||
* @see #setIndirectLight(IndirectLight)
|
||||
*/
|
||||
@Nullable
|
||||
public IndirectLight getIndirectLight() {
|
||||
return mIndirectLight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link IndirectLight} to use when rendering the <code>Scene</code>.
|
||||
*
|
||||
* Currently, a <code>Scene</code> may only have a single {@link IndirectLight}.
|
||||
* This call replaces the current {@link IndirectLight}.
|
||||
*
|
||||
* @param ibl the {@link IndirectLight} to use when rendering the <code>Scene</code>
|
||||
* or <code>null</code> to unset.
|
||||
*/
|
||||
public void setIndirectLight(@Nullable IndirectLight ibl) {
|
||||
mIndirectLight = ibl;
|
||||
nSetIndirectLight(getNativeObject(),
|
||||
mIndirectLight != null ? mIndirectLight.getNativeObject() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link Entity} to the <code>Scene</code>.
|
||||
*
|
||||
* @param entity the entity is ignored if it doesn't have a {@link RenderableManager} component
|
||||
* or {@link LightManager} component.<br>
|
||||
* A given {@link Entity} object can only be added once to a <code>Scene</code>.
|
||||
*/
|
||||
public void addEntity(@Entity int entity) {
|
||||
nAddEntity(getNativeObject(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of entities to the <code>Scene</code>.
|
||||
*
|
||||
* @param entities array containing entities to add to the <code>Scene</code>.
|
||||
*/
|
||||
public void addEntities(@Entity int[] entities) {
|
||||
nAddEntities(getNativeObject(), entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an {@link Entity} from the <code>Scene</code>.
|
||||
*
|
||||
* @param entity the {@link Entity} to remove from the <code>Scene</code>. If the specified
|
||||
* <code>entity</code> doesn't exist, this call is ignored.
|
||||
*/
|
||||
public void removeEntity(@Entity int entity) {
|
||||
nRemove(getNativeObject(), entity);
|
||||
}
|
||||
@@ -67,10 +132,20 @@ public class Scene {
|
||||
removeEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>..
|
||||
*/
|
||||
public int getRenderableCount() {
|
||||
return nGetRenderableCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link LightManager} components in the <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link LightManager} components in the <code>Scene</code>..
|
||||
*/
|
||||
public int getLightCount() {
|
||||
return nGetLightCount(getNativeObject());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,31 @@ import android.support.annotation.NonNull;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByReflection;
|
||||
|
||||
/**
|
||||
* Skybox
|
||||
* <p>When added to a {@link Scene}, the <code>Skybox</code> fills all untouched pixels.</p>
|
||||
*
|
||||
* <h1>Creation and destruction</h1>
|
||||
*
|
||||
* A <code>Skybox</code> object is created using the {@link Skybox.Builder} and destroyed by calling
|
||||
* {@link Engine#destroySkybox}.<br>
|
||||
* <pre>
|
||||
* Engine engine = Engine.create();
|
||||
*
|
||||
* Scene scene = engine.createScene();
|
||||
*
|
||||
* Skybox skybox = new Skybox.Builder()
|
||||
* .environment(cubemap)
|
||||
* .build(engine);
|
||||
*
|
||||
* scene.setSkybox(skybox);
|
||||
* </pre>
|
||||
*
|
||||
* Currently only {@link Texture} based sky boxes are supported.
|
||||
*
|
||||
* @see Scene
|
||||
* @see IndirectLight
|
||||
*/
|
||||
public class Skybox {
|
||||
private long mNativeObject;
|
||||
|
||||
@@ -29,28 +54,88 @@ public class Skybox {
|
||||
mNativeObject = nativeSkybox;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct a <code>Skybox</code> object instance.
|
||||
*/
|
||||
public static class Builder {
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
private final long mNativeBuilder;
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct a <code>Skybox</code> object instance.
|
||||
*/
|
||||
public Builder() {
|
||||
mNativeBuilder = nCreateBuilder();
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the environment map (i.e. the skybox content).
|
||||
*
|
||||
* <p>The <code>Skybox</code> is rendered as though it were an infinitely large cube with the
|
||||
* camera inside it. This means that the cubemap which is mapped onto the cube's exterior
|
||||
* will appear mirrored. This follows the OpenGL conventions.</p>
|
||||
*
|
||||
* <p>The <code>cmgen</code> tool generates reflection maps by default which are therefore
|
||||
* ideal to use as skyboxes.</p>
|
||||
*
|
||||
* @param cubemap A cubemap {@link Texture}
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @see Texture
|
||||
*/
|
||||
@NonNull
|
||||
public Builder environment(@NonNull Texture texture) {
|
||||
nBuilderEnvironment(mNativeBuilder, texture.getNativeObject());
|
||||
public Builder environment(@NonNull Texture cubemap) {
|
||||
nBuilderEnvironment(mNativeBuilder, cubemap.getNativeObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the sun should be rendered. The sun can only be
|
||||
* rendered if there is at least one light of type {@link LightManager.Type#SUN} in
|
||||
* the {@link Scene}. The default value is <code>false</code>.
|
||||
*
|
||||
* @param show <code>true</code> if the sun should be rendered, <code>false</code> otherwise
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder showSun(boolean show) {
|
||||
nBuilderShowSun(mNativeBuilder, show);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>Skybox</code> intensity when no {@link IndirectLight} is set
|
||||
*
|
||||
* <p>This call is ignored when an {@link IndirectLight} is set, otherwise it is used in
|
||||
* its place.</p>
|
||||
*
|
||||
* @param envIntensity Scale factor applied to the skybox texel values such that
|
||||
* the result is in cd/m<sup>2</sup> (lux) units (default = 30000)
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @see IndirectLight.Builder#intensity
|
||||
*/
|
||||
@NonNull
|
||||
public Builder intensity(float envIntensity) {
|
||||
nBuilderIntensity(mNativeBuilder, envIntensity);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>Skybox</code> object
|
||||
*
|
||||
* @param engine the {@link Engine} to associate this <code>Skybox</code> with.
|
||||
*
|
||||
* @return A newly created <code>Skybox</code>object
|
||||
*
|
||||
* @exception IllegalStateException can be thrown if the <code>Skybox</code> couldn't be created
|
||||
*/
|
||||
@NonNull
|
||||
public Skybox build(@NonNull Engine engine) {
|
||||
long nativeSkybox = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -75,14 +160,35 @@ public class Skybox {
|
||||
}
|
||||
}
|
||||
|
||||
public void setLayerMask(@IntRange(from = 0, to = 255) int select, @IntRange(from = 0, to = 255) int value) {
|
||||
nSetLayerMask(getNativeObject(), select & 0xff, value & 0xff);
|
||||
/**
|
||||
* Sets bits in a visibility mask. By default, this is <code>0x1</code>.
|
||||
* <p>This provides a simple mechanism for hiding or showing this <code>Skybox</code> in a
|
||||
* {@link Scene}.</p>
|
||||
*
|
||||
* <p>For example, to set bit 1 and reset bits 0 and 2 while leaving all other bits unaffected,
|
||||
* call: <code>setLayerMask(7, 2)</code>.</p>
|
||||
*
|
||||
* @param select the set of bits to affect
|
||||
* @param values the replacement values for the affected bits
|
||||
*
|
||||
* @see View#setVisibleLayers
|
||||
*/
|
||||
public void setLayerMask(@IntRange(from = 0, to = 255) int select, @IntRange(from = 0, to = 255) int values) {
|
||||
nSetLayerMask(getNativeObject(), select & 0xff, values & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the visibility mask bits
|
||||
*/
|
||||
public int getLayerMask() {
|
||||
return nGetLayerMask(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Skybox</code>'s intensity in cd/m<sup>2</sup>.
|
||||
*/
|
||||
public float getIntensity() { return nGetIntensity(getNativeObject()); }
|
||||
|
||||
public long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed Skybox");
|
||||
@@ -98,7 +204,9 @@ public class Skybox {
|
||||
private static native void nDestroyBuilder(long nativeSkyboxBuilder);
|
||||
private static native void nBuilderEnvironment(long nativeSkyboxBuilder, long nativeTexture);
|
||||
private static native void nBuilderShowSun(long nativeSkyboxBuilder, boolean show);
|
||||
private static native void nBuilderIntensity(long nativeSkyboxBuilder, float intensity);
|
||||
private static native long nBuilderBuild(long nativeSkyboxBuilder, long nativeEngine);
|
||||
private static native void nSetLayerMask(long nativeSkybox, int select, int value);
|
||||
private static native int nGetLayerMask(long nativeSkybox);
|
||||
private static native float nGetIntensity(long nativeSkybox);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,12 @@ import java.nio.Buffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
|
||||
/**
|
||||
* <code>Stream</code> is used to attach a native video stream to a filament {@link Texture}.
|
||||
*
|
||||
* @see Texture#setExternalStream
|
||||
* @see Engine#destroyStream
|
||||
*/
|
||||
public class Stream {
|
||||
private long mNativeObject;
|
||||
private long mNativeEngine;
|
||||
@@ -32,20 +38,31 @@ public class Stream {
|
||||
mNativeEngine = engine.getNativeObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct an Stream object instance.
|
||||
*/
|
||||
public static class Builder {
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
private final long mNativeBuilder;
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct an Stream object instance.
|
||||
*/
|
||||
public Builder() {
|
||||
mNativeBuilder = nCreateBuilder();
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepted types for the stream source:
|
||||
* - Android: SurfaceView
|
||||
* - Other: none
|
||||
* Creates a native stream. Native streams can sample data directly from an
|
||||
* opaque platform object such as a {@link android.graphics.SurfaceTexture SurfaceTexture}
|
||||
* on Android.
|
||||
*
|
||||
* @param streamSource an opaque native stream handle, e.g.: on Android this must be a
|
||||
* {@link android.graphics.SurfaceTexture SurfaceTexture} object
|
||||
* @return This Builder, for chaining calls.
|
||||
* @see Texture#setExternalStream
|
||||
*/
|
||||
@NonNull
|
||||
public Builder stream(@NonNull Object streamSource) {
|
||||
@@ -56,24 +73,57 @@ public class Stream {
|
||||
throw new IllegalArgumentException("Invalid stream source: " + streamSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy stream. A copy stream will sample data from the supplied
|
||||
* external texture and copy it into an internal private texture.
|
||||
*
|
||||
* <p>Currently only OpenGL external texture ids are supported.</p>
|
||||
*
|
||||
* @param externalTextureId An opaque texture id (typically a GLuint created with
|
||||
* <code>glGenTextures()</code>) in a context shared with
|
||||
* filament -- in that case this texture's target must be
|
||||
* <code>GL_TEXTURE_EXTERNAL_OES.</code>
|
||||
* @return This Builder, for chaining calls.
|
||||
* @see Texture#setExternalStream
|
||||
*/
|
||||
@NonNull
|
||||
public Builder stream(long externalTextureId) {
|
||||
nBuilderStream(mNativeBuilder, externalTextureId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param width initial width of the incoming stream. Whether this value is used is
|
||||
* stream dependent. On Android, it must be set when using
|
||||
* {@link #stream(long)}
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder width(int width) {
|
||||
nBuilderWidth(mNativeBuilder, width);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param height initial height of the incoming stream. Whether this value is used is
|
||||
* stream dependent. On Android, it must be set when using
|
||||
* {@link #stream(long)}
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder height(int height) {
|
||||
nBuilderHeight(mNativeBuilder, height);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>Stream</code> object instance.
|
||||
*
|
||||
* @param engine {@link Engine} instance to associate this <code>Stream</code> with.
|
||||
*
|
||||
* @return newly created <code>Stream</code> object
|
||||
* @exception IllegalStateException if the <code>Stream</code> couldn't be created
|
||||
*/
|
||||
@NonNull
|
||||
public Stream build(@NonNull Engine engine) {
|
||||
long nativeStream = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -99,14 +149,92 @@ public class Stream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this <code>Stream</code> is a native stream or a copy stream.
|
||||
*
|
||||
* @return true if this is a native <code>Stream</code>, false otherwise.
|
||||
*/
|
||||
public boolean isNative() {
|
||||
return nIsNative(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the size of the incoming stream. Whether this value is used is
|
||||
* stream dependent. On Android, it must be set when using
|
||||
* {@link Builder#stream(long)}
|
||||
*
|
||||
* @param width new width of the incoming stream
|
||||
* @param height new height of the incoming stream
|
||||
*/
|
||||
public void setDimensions(@IntRange(from = 0) int width, @IntRange(from = 0) int height) {
|
||||
nSetDimensions(getNativeObject(), width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads back the content of the last frame of a <code>Stream</code> since the last call to
|
||||
* {@link Renderer#beginFrame}.
|
||||
*
|
||||
* <p>The Stream must be a copy stream, which can be checked with {@link #isNative()}.
|
||||
* This function is a no-op otherwise.</p>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* Stream buffer User buffer (PixelBufferDescriptor)
|
||||
* +--------------------+
|
||||
* | | .stride .alignment
|
||||
* | | ----------------------->-->
|
||||
* | | O----------------------+--+ low addresses
|
||||
* | | | | | |
|
||||
* | w | | | .top | |
|
||||
* | <---------> | | V | |
|
||||
* | +---------+ | | +---------+ | |
|
||||
* | | ^ | | ======> | | | | |
|
||||
* | x | h| | | |.left| | | |
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | ^ | | | |
|
||||
* | y | | +----------------------+--+ high addresses
|
||||
* O------------+-------+
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>Typically readPixels() will be called after {@link Renderer#beginFrame}.</p>
|
||||
*
|
||||
* <p>After calling this method, the callback associated with <code>buffer</code>
|
||||
* will be invoked on the main thread, indicating that the read-back has completed.
|
||||
* Typically, this will happen after multiple calls to {@link Renderer#beginFrame},
|
||||
* {@link Renderer#render}, {@link Renderer#endFrame}.</p>
|
||||
*
|
||||
* <p><code>readPixels</code> is intended for debugging and testing.
|
||||
* It will impact performance significantly.</p>
|
||||
*
|
||||
* @param xoffset left offset of the sub-region to read back
|
||||
* @param yoffset bottom offset of the sub-region to read back
|
||||
* @param width width of the sub-region to read back
|
||||
* @param height height of the sub-region to read back
|
||||
* @param buffer client-side buffer where the read-back will be written
|
||||
*
|
||||
* <p>
|
||||
* The following format are always supported:
|
||||
* <li>{@link Texture.Format#RGBA}</li>
|
||||
* <li>{@link Texture.Format#RGBA_INTEGER}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The following types are always supported:
|
||||
* <li>{@link Texture.Type#UBYTE}</li>
|
||||
* <li>{@link Texture.Type#UINT}</li>
|
||||
* <li>{@link Texture.Type#INT}</li>
|
||||
* <li>{@link Texture.Type#FLOAT}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>Other combination of format/type may be supported. If a combination is
|
||||
* not supported, this operation may fail silently. Use a DEBUG build
|
||||
* to get some logs about the failure.</p>
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*/
|
||||
public void readPixels(
|
||||
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
|
||||
@IntRange(from = 0) int width, @IntRange(from = 0) int height,
|
||||
@@ -128,6 +256,13 @@ public class Stream {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the presentation time of the currently displayed frame in nanosecond.
|
||||
*
|
||||
* This value can change at any time.
|
||||
*
|
||||
* @return timestamp in nanosecond.
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return nGetTimestamp(getNativeObject());
|
||||
}
|
||||
|
||||
@@ -18,12 +18,71 @@ package com.google.android.filament;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* A <code>SwapChain</code> represents an Operating System's <b>native</b> renderable surface.
|
||||
*
|
||||
* <p>Typically it's a native window or a view. Because a <code>SwapChain</code> is initialized
|
||||
* from a native object, it is given to filament as an <code>Object</code>, which must be of the
|
||||
* proper type for each platform filament is running on.</p>
|
||||
*
|
||||
* <code>
|
||||
* SwapChain swapChain = engine.createSwapChain(nativeWindow);
|
||||
* </code>
|
||||
*
|
||||
* <p>The <code>nativeWindow</code> parameter above must be of type:</p>
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr><th> Platform </th><th> nativeWindow type </th></tr>
|
||||
* <tr><td> Android </td><td>{@link android.view.Surface Surface}</td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
* <p>
|
||||
*
|
||||
* <h1>Examples</h1>
|
||||
*
|
||||
* <h2>Android</h2>
|
||||
*
|
||||
*
|
||||
* <p>A {@link android.view.Surface Surface} can be retrieved from a
|
||||
* {@link android.view.SurfaceView SurfaceView} or {@link android.view.SurfaceHolder SurfaceHolder}
|
||||
* easily using {@link android.view.SurfaceHolder#getSurface SurfaceHolder.getSurface()} and/or
|
||||
* {@link android.view.SurfaceView#getHolder SurfaceView.getHolder()}.</p>
|
||||
*
|
||||
* <p>To use a {@link android.view.TextureView Textureview} as a <code>SwapChain</code>, it is
|
||||
* necessary to first get its {@link android.graphics.SurfaceTexture SurfaceTexture},
|
||||
* for instance using {@link android.view.TextureView.SurfaceTextureListener SurfaceTextureListener}
|
||||
* and then create a {@link android.view.Surface Surface}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* // using a TextureView.SurfaceTextureListener:
|
||||
* public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
|
||||
* mSurface = new Surface(surfaceTexture);
|
||||
* // mSurface can now be used with Engine.createSwapChain()
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see Engine
|
||||
*/
|
||||
public class SwapChain {
|
||||
private final Object mSurface;
|
||||
private long mNativeObject;
|
||||
|
||||
public static final long CONFIG_DEFAULT = 0x0;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> must be allocated with an
|
||||
* alpha-channel.
|
||||
*/
|
||||
public static final long CONFIG_TRANSPARENT = 0x1;
|
||||
|
||||
/**
|
||||
* This flag indicates that the <code>SwapChain</code> may be used as a source surface
|
||||
* for reading back render results. This config must be set when creating
|
||||
* any <code>SwapChain</code> that will be used as the source for a blit operation.
|
||||
*
|
||||
* @see Renderer#copyFrame
|
||||
*/
|
||||
public static final long CONFIG_READABLE = 0x2;
|
||||
|
||||
SwapChain(long nativeSwapChain, @NonNull Object surface) {
|
||||
@@ -31,6 +90,9 @@ public class SwapChain {
|
||||
mSurface = surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native <code>Object</code> this <code>SwapChain</code> was created from.
|
||||
*/
|
||||
@NonNull
|
||||
public Object getNativeWindow() {
|
||||
return mSurface;
|
||||
|
||||
@@ -29,6 +29,47 @@ import java.nio.ByteBuffer;
|
||||
|
||||
import static com.google.android.filament.Texture.Type.COMPRESSED;
|
||||
|
||||
/**
|
||||
* Texture
|
||||
* <p>The <code>Texture</code> class supports:</p>
|
||||
* <ul>
|
||||
* <li>2D textures</li>
|
||||
* <li>3D textures</li>
|
||||
* <li>Cube maps</li>
|
||||
* <li>mip mapping</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <h1>Usage example</h1>
|
||||
*
|
||||
* A <code>Texture</code> object is created using the {@link Texture.Builder} and destroyed by
|
||||
* calling {@link Engine#destroyTexture}. They're bound using {@link MaterialInstance#setParameter}.
|
||||
*
|
||||
* <pre>
|
||||
* Engine engine = Engine.create();
|
||||
*
|
||||
* Material material = new Material.Builder()
|
||||
* .payload( ... )
|
||||
* .build(ending);
|
||||
*
|
||||
* MaterialInstance mi = material.getDefaultInstance();
|
||||
*
|
||||
* Texture texture = new Texture.Builder()
|
||||
* .width(64)
|
||||
* .height(64)
|
||||
* .build(engine);
|
||||
*
|
||||
*
|
||||
* texture.setImage(engine, 0,
|
||||
* new Texture.PixelBufferDescriptor( ... ));
|
||||
*
|
||||
* mi.setParameter("parameterName", texture, new TextureSampler());
|
||||
* </pre>
|
||||
*
|
||||
* @see #setImage
|
||||
* @see PixelBufferDescriptor
|
||||
* @see MaterialInstance#setParameter(String, Texture, TextureSampler)
|
||||
*/
|
||||
public class Texture {
|
||||
private long mNativeObject;
|
||||
|
||||
@@ -37,12 +78,95 @@ public class Texture {
|
||||
mNativeObject = nativeTexture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of sampler
|
||||
*/
|
||||
public enum Sampler {
|
||||
/** 2D sampler */
|
||||
SAMPLER_2D,
|
||||
/** Cubemap sampler */
|
||||
SAMPLER_CUBEMAP,
|
||||
/** External texture sampler */
|
||||
SAMPLER_EXTERNAL
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal texel formats
|
||||
*
|
||||
* <p>These formats are used to specify a texture's internal storage format.</p>
|
||||
*
|
||||
* <h1>Enumerants syntax format</h1>
|
||||
*
|
||||
* <code>[components][size][type]</code>
|
||||
* <br><code>components</code> : List of stored components by this format
|
||||
* <br><code>size</code> : Size in bit of each component
|
||||
* <br><code>type</code> : Type this format is stored as
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr><th> Name </th><th> Component </th></tr>
|
||||
* <tr><td> R </td><td> Linear Red </td></tr>
|
||||
* <tr><td> RG </td><td> Linear Red, Green </td></tr>
|
||||
* <tr><td> RGB </td><td> Linear Red, Green, Blue </td></tr>
|
||||
* <tr><td> RGBA </td><td> Linear Red, Green Blue, Alpha </td></tr>
|
||||
* <tr><td> SRGB </td><td> sRGB encoded Red, Green, Blue </td></tr>
|
||||
* <tr><td> DEPTH </td><td> Depth </td></tr>
|
||||
* <tr><td> STENCIL </td><td> Stencil </td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
* <br>
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr><th> Name </th><th> Type </th></tr>
|
||||
* <tr><td> (none) </td><td> Unsigned Normalized Integer [0, 1] </th></tr>
|
||||
* <tr><td> _SNORM </td><td> Signed Normalized Integer [-1, 1] </td></tr>
|
||||
* <tr><td> UI </td><td> Unsigned Integer [0, 2<sup>size</sup>] </td></tr>
|
||||
* <tr><td> I </td><td> Signed Integer [-2<sup>size-1</sup>, 2<sup>size-1</sup>-1] </td></tr>
|
||||
* <tr><td> F </td><td> Floating-point </td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
* <br>
|
||||
*
|
||||
* <h1>Special color formats</h1>
|
||||
*
|
||||
* There are a few special color formats that don't follow the convention above:
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr><th> Name </th><th> Format </th></tr>
|
||||
* <tr><td> RGB565 </td><td> 5-bits for R and B, 6-bits for G. </td></tr>
|
||||
* <tr><td> RGB5_A1 </td><td> 5-bits for R, G and B, 1-bit for A. </td></tr>
|
||||
* <tr><td> RGB10_A2 </td><td> 10-bits for R, G and B, 2-bits for A. </td></tr>
|
||||
* <tr><td> RGB9_E5 </td><td> <b>Unsigned</b> floating point. 9-bits mantissa for RGB, 5-bits shared exponent </td></tr>
|
||||
* <tr><td> R11F_G11F_B10F </td><td> <b>Unsigned</b> floating point. 6-bits mantissa, for R and G, 5-bits for B. 5-bits exponent. </td></tr>
|
||||
* <tr><td> SRGB8_A8 </td><td> sRGB 8-bits with linear 8-bits alpha. </td></tr>
|
||||
* <tr><td> DEPTH24_STENCIL8 </td><td> 24-bits unsigned normalized integer depth, 8-bits stencil. </td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
* <br>
|
||||
*
|
||||
* <h1>Compressed texture formats</h1>
|
||||
*
|
||||
* Many compressed texture formats are supported as well, which include (but are not limited to)
|
||||
* the following list:
|
||||
*
|
||||
* <center>
|
||||
* <table border="1">
|
||||
* <tr><th> Name </th><th> Format </th></tr>
|
||||
* <tr><td> EAC_R11 </td><td> Compresses R11UI </td></tr>
|
||||
* <tr><td> EAC_R11_SIGNED </td><td> Compresses R11I </td></tr>
|
||||
* <tr><td> EAC_RG11 </td><td> Compresses RG11UI </td></tr>
|
||||
* <tr><td> EAC_RG11_SIGNED </td><td> Compresses RG11I </td></tr>
|
||||
* <tr><td> ETC2_RGB8 </td><td> Compresses RGB8 </td></tr>
|
||||
* <tr><td> ETC2_SRGB8 </td><td> compresses SRGB8 </td></tr>
|
||||
* <tr><td> ETC2_EAC_RGBA8 </td><td> Compresses RGBA8 </td></tr>
|
||||
* <tr><td> ETC2_EAC_SRGBA8 </td><td> Compresses SRGB8_A8 </td></tr>
|
||||
* <tr><td> ETC2_RGB8_A1 </td><td> Compresses RGB8 with 1-bit alpha </td></tr>
|
||||
* <tr><td> ETC2_SRGB8_A1 </td><td> Compresses sRGB8 with 1-bit alpha </td></tr>
|
||||
* </table>
|
||||
* </center>
|
||||
*/
|
||||
public enum InternalFormat {
|
||||
// 8-bits per element
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8,
|
||||
@@ -92,6 +216,10 @@ public class Texture {
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA
|
||||
}
|
||||
|
||||
/**
|
||||
* Compressed data types for use with {@link PixelBufferDescriptor}
|
||||
* @see InternalFormat
|
||||
*/
|
||||
public enum CompressedFormat {
|
||||
// Mandatory in GLES 3.0 and GL 4.3
|
||||
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED,
|
||||
@@ -103,15 +231,27 @@ public class Texture {
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA
|
||||
}
|
||||
|
||||
/**
|
||||
* Cubemap faces
|
||||
*/
|
||||
public enum CubemapFace {
|
||||
/** +x face */
|
||||
POSITIVE_X,
|
||||
/** -x face */
|
||||
NEGATIVE_X,
|
||||
/** +y face */
|
||||
POSITIVE_Y,
|
||||
/** -y face */
|
||||
NEGATIVE_Y,
|
||||
/** +z face */
|
||||
POSITIVE_Z,
|
||||
/** -z face */
|
||||
NEGATIVE_Z
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixel color format
|
||||
*/
|
||||
public enum Format {
|
||||
R,
|
||||
R_INTEGER,
|
||||
@@ -128,19 +268,43 @@ public class Texture {
|
||||
ALPHA
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixel data type
|
||||
*/
|
||||
public enum Type {
|
||||
/** unsigned byte, 8-bits */
|
||||
UBYTE,
|
||||
/** signed byte, 8-bits */
|
||||
BYTE,
|
||||
/** unsigned short, 16-bits */
|
||||
USHORT,
|
||||
/** signed short, 16-bits */
|
||||
SHORT,
|
||||
/** unsigned int, 32-bits */
|
||||
UINT,
|
||||
/** signed int, 32-bits */
|
||||
INT,
|
||||
/** half-float, 16-bits float with 10 bits mantissa */
|
||||
HALF,
|
||||
/** float, 32-bits float, with 24 bits mantissa */
|
||||
FLOAT,
|
||||
/** a compessed type */
|
||||
COMPRESSED,
|
||||
/** unsigned 5.6 (5.5 for blue) float packed in 32-bits */
|
||||
UINT_10F_11F_11F_REV
|
||||
}
|
||||
|
||||
/**
|
||||
* A descriptor to an image in main memory, typically used to transfer image data from the CPU
|
||||
* to the GPU.
|
||||
* <p>A <code>PixelBufferDescriptor</code> owns the memory buffer it references,
|
||||
* therefore <code>PixelBufferDescriptor</code> cannot be copied, but can be moved.</p>
|
||||
*
|
||||
* <code>PixelBufferDescriptor</code> releases ownership of the memory-buffer when it's
|
||||
* destroyed.
|
||||
*
|
||||
* @see #setImage
|
||||
*/
|
||||
public static class PixelBufferDescriptor {
|
||||
public Buffer storage;
|
||||
|
||||
@@ -165,6 +329,20 @@ public class Texture {
|
||||
* - Android: Handler, Executor
|
||||
* - Other: Executor
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a <code>PixelBufferDescriptor</code>
|
||||
*
|
||||
* @param storage CPU-side buffer containing the image data to upload into the texture
|
||||
* @param format Pixel {@link Format format} of the CPU-side image
|
||||
* @param type Pixel data {@link Type type} of the CPU-side image
|
||||
* @param alignment Row-alignment in bytes of the CPU-side image (1 to 8 bytes)
|
||||
* @param left Left coordinate in pixels of the CPU-side image
|
||||
* @param top Top coordinate in pixels of the CPU-side image
|
||||
* @param stride Stride in pixels of the CPU-side image (i.e. distance in pixels to the next row)
|
||||
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback A callback executed by <code>handler</code> when <code>storage</code> is no longer needed.
|
||||
*/
|
||||
public PixelBufferDescriptor(@NonNull Buffer storage,
|
||||
@NonNull Format format, @NonNull Type type,
|
||||
@IntRange(from = 1, to = 8) int alignment,
|
||||
@@ -182,17 +360,48 @@ public class Texture {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>PixelBufferDescriptor</code> with some default values and no callback.
|
||||
*
|
||||
* @param storage CPU-side buffer containing the image data to upload into the texture
|
||||
* @param format Pixel {@link Format format} of the CPU-side image
|
||||
* @param type Pixel data {@link Type type} of the CPU-side image
|
||||
*
|
||||
* @see #setCallback
|
||||
*/
|
||||
public PixelBufferDescriptor(@NonNull Buffer storage,
|
||||
@NonNull Format format, @NonNull Type type) {
|
||||
this(storage, format, type, 1, 0, 0, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>PixelBufferDescriptor</code> with some default values and no callback.
|
||||
*
|
||||
* @param storage CPU-side buffer containing the image data to upload into the texture
|
||||
* @param format Pixel {@link Format format} of the CPU-side image
|
||||
* @param type Pixel data {@link Type type} of the CPU-side image
|
||||
* @param alignment Row-alignment in bytes of the CPU-side image (1 to 8 bytes)
|
||||
*
|
||||
* @see #setCallback
|
||||
*/
|
||||
public PixelBufferDescriptor(@NonNull Buffer storage,
|
||||
@NonNull Format format, @NonNull Type type,
|
||||
@IntRange(from = 1, to = 8) int alignment) {
|
||||
this(storage, format, type, alignment, 0, 0, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>PixelBufferDescriptor</code> with some default values and no callback.
|
||||
*
|
||||
* @param storage CPU-side buffer containing the image data to upload into the texture
|
||||
* @param format Pixel {@link Format format} of the CPU-side image
|
||||
* @param type Pixel data {@link Type type} of the CPU-side image
|
||||
* @param alignment Row-alignment in bytes of the CPU-side image (1 to 8 bytes)
|
||||
* @param left Left coordinate in pixels of the CPU-side image
|
||||
* @param top Top coordinate in pixels of the CPU-side image
|
||||
*
|
||||
* @see #setCallback
|
||||
*/
|
||||
public PixelBufferDescriptor(@NonNull Buffer storage,
|
||||
@NonNull Format format, @NonNull Type type,
|
||||
@IntRange(from = 1, to = 8) int alignment,
|
||||
@@ -200,6 +409,14 @@ public class Texture {
|
||||
this(storage, format, type, alignment, left, top, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param storage CPU-side buffer containing the image data to upload into the texture
|
||||
* @param format Compressed pixel {@link CompressedFormat format} of the CPU-side image
|
||||
* @param compressedSizeInBytes Size of the compressed data in bytes
|
||||
*
|
||||
* @see #setCallback
|
||||
*/
|
||||
public PixelBufferDescriptor(@NonNull ByteBuffer storage,
|
||||
@NonNull CompressedFormat format,
|
||||
@IntRange(from = 0) int compressedSizeInBytes) {
|
||||
@@ -211,9 +428,10 @@ public class Texture {
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid handler types:
|
||||
* - Android: Handler, Executor
|
||||
* - Other: Executor
|
||||
* Set or replace the callback called when the CPU-side data is no longer needed.
|
||||
*
|
||||
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback A callback executed by <code>handler</code> when <code>storage</code> is no longer needed.
|
||||
*/
|
||||
public void setCallback(@Nullable Object handler, @Nullable Runnable callback) {
|
||||
this.handler = handler;
|
||||
@@ -288,57 +506,109 @@ public class Texture {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options of {@link #generatePrefilterMipmap}
|
||||
*/
|
||||
public static class PrefilterOptions {
|
||||
/** number of samples for roughness pre-filtering */
|
||||
public int sampleCount = 8;
|
||||
/** whether to generate a reflection map (mirror) */
|
||||
public boolean mirror = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given format is supported for texturing in this {@link Engine}.
|
||||
* This depends on the selected backend.
|
||||
*
|
||||
* @param engine {@link Engine} to test the {@link InternalFormat InternalFormat} against
|
||||
* @param format format to check
|
||||
* @return <code>true</code> if this format is supported for texturing.
|
||||
*/
|
||||
public static boolean isTextureFormatSupported(@NonNull Engine engine,
|
||||
@NonNull InternalFormat format) {
|
||||
return nIsTextureFormatSupported(engine.getNativeObject(), format.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
||||
*/
|
||||
public static class Builder {
|
||||
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
|
||||
// Keep to finalize native resources
|
||||
private final BuilderFinalizer mFinalizer;
|
||||
private final long mNativeBuilder;
|
||||
|
||||
/**
|
||||
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
|
||||
*/
|
||||
public Builder() {
|
||||
mNativeBuilder = nCreateBuilder();
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the width of the texture in texels.
|
||||
* @param width texture width in texels, must be at least 1. Default is 1.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder width(@IntRange(from = 1) int width) {
|
||||
nBuilderWidth(mNativeBuilder, width);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the height of the texture in texels.
|
||||
* @param height texture height in texels, must be at least 1. Default is 1.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder height(@IntRange(from = 1) int height) {
|
||||
nBuilderHeight(mNativeBuilder, height);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the texture's number of layers. This creates a 3D texture.
|
||||
* @param depth texture number of layer, must be at least 1. Default is 1.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder depth(@IntRange(from = 1) int depth) {
|
||||
nBuilderDepth(mNativeBuilder, depth);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the number of mipmap levels
|
||||
* @param levels must be at least 1 and less or equal to <code>floor(log<sub>2</sub>(max(width, height))) + 1</code>. Default is 1.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder levels(@IntRange(from = 1) int levels) {
|
||||
nBuilderLevels(mNativeBuilder, levels);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the type of sampler to use.
|
||||
* @param target {@link Sampler Sampler} type
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder sampler(@NonNull Sampler target) {
|
||||
nBuilderSampler(mNativeBuilder, target.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the texture's internal format.
|
||||
* <p>The internal format specifies how texels are stored (which may be different from how
|
||||
* they're specified in {@link #setImage}). {@link InternalFormat InternalFormat} specifies
|
||||
* both the color components and the data type used.</p>
|
||||
* @param format texture's {@link InternalFormat internal format}.
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder format(@NonNull InternalFormat format) {
|
||||
nBuilderFormat(mNativeBuilder, format.ordinal());
|
||||
@@ -356,6 +626,13 @@ public class Texture {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>Texture</code> instance.
|
||||
* @param engine The {@link Engine} to associate this <code>Texture</code> with.
|
||||
* @return A newly created <code>Texture</code>
|
||||
* @exception IllegalStateException if a parameter to a builder function was invalid.
|
||||
* A mode detailed message about the error is output in the system log.
|
||||
*/
|
||||
@NonNull
|
||||
public Texture build(@NonNull Engine engine) {
|
||||
long nativeTexture = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -382,38 +659,71 @@ public class Texture {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitmask to specify how the texture will be used.
|
||||
*/
|
||||
public static class Usage {
|
||||
/** The texture will be used as a color attachment */
|
||||
public static final int COLOR_ATTACHMENT = 0x1;
|
||||
/** The texture will be used as a depth attachment */
|
||||
public static final int DEPTH_ATTACHMENT = 0x2;
|
||||
/** The texture will be used as a stencil attachment */
|
||||
public static final int STENCIL_ATTACHMENT = 0x4;
|
||||
/** The texture content can be set with {@link #setImage} */
|
||||
public static final int UPLOADABLE = 0x8;
|
||||
/** The texture can be read from a shader or blitted from */
|
||||
public static final int SAMPLEABLE = 0x10;
|
||||
/** by default textures are <code>UPLOADABLE</code> and <code>SAMPLEABLE</code>*/
|
||||
public static final int DEFAULT = UPLOADABLE | SAMPLEABLE;
|
||||
}
|
||||
|
||||
public static final int BASE_LEVEL = 0;
|
||||
|
||||
/**
|
||||
* Queries the width of a given level of this texture.
|
||||
* @param level to query the with of. Must be between 0 and {@link #getLevels}
|
||||
* @return The width in texel of the given level
|
||||
*/
|
||||
public int getWidth(@IntRange(from = 0) int level) {
|
||||
return nGetWidth(getNativeObject(), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the height of a given level of this texture.
|
||||
* @param level to query the height of. Must be between 0 and {@link #getLevels}
|
||||
* @return The height in texel of the given level
|
||||
*/
|
||||
public int getHeight(@IntRange(from = 0) int level) {
|
||||
return nGetHeight(getNativeObject(), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the number of layers of given level of this texture has.
|
||||
* @param level to query the number of layers of. Must be between 0 and {@link #getLevels}
|
||||
* @return The number of layers of the given level
|
||||
*/
|
||||
public int getDepth(@IntRange(from = 0) int level) {
|
||||
return nGetDepth(getNativeObject(), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of mipmap levels of this texture
|
||||
*/
|
||||
public int getLevels() {
|
||||
return nGetLevels(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This texture {@link Sampler Sampler} type.
|
||||
*/
|
||||
@NonNull
|
||||
public Sampler getTarget() {
|
||||
return Sampler.values()[nGetTarget(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This texture's {@link InternalFormat InternalFormat}.
|
||||
*/
|
||||
@NonNull
|
||||
public InternalFormat getFormat() {
|
||||
return InternalFormat.values()[nGetInternalFormat(getNativeObject())];
|
||||
@@ -421,12 +731,65 @@ public class Texture {
|
||||
|
||||
// TODO: add a setImage() version that takes an android Bitmap
|
||||
|
||||
/**
|
||||
* <code>setImage</code> is used to modify the whole content of the texure from a CPU-buffer.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use {@link Sampler#SAMPLER_2D SAMPLER_2D} or
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}. If the later is specified
|
||||
* and external textures are supported by the driver implementation,
|
||||
* this method will have no effect, otherwise it will behave as if the
|
||||
* texture was specified with {@link Sampler#SAMPLER_2D SAMPLER_2D}.</p>
|
||||
*
|
||||
* This is equivalent to calling: <br>
|
||||
*
|
||||
* <code>setImage(engine, level, 0, 0, getWidth(level), getHeight(level), buffer)</code>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param level Level to set the image for. Must be less than {@link #getLevels()}.
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
* <code>buffer</code>'s {@link Format format} must match that
|
||||
* of {@link #getFormat()}
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*
|
||||
* @see Builder#sampler
|
||||
* @see PixelBufferDescriptor
|
||||
*/
|
||||
public void setImage(@NonNull Engine engine,
|
||||
@IntRange(from = 0) int level,
|
||||
@NonNull PixelBufferDescriptor buffer) {
|
||||
setImage(engine, level, 0, 0, getWidth(level), getHeight(level), buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>setImage</code> is used to modify a sub-region of the texure from a CPU-buffer.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use {@link Sampler#SAMPLER_2D SAMPLER_2D} or
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}. If the later is specified
|
||||
* and external textures are supported by the driver implementation,
|
||||
* this method will have no effect, otherwise it will behave as if the
|
||||
* texture was specified with {@link Sampler#SAMPLER_2D SAMPLER_2D}.</p>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param level Level to set the image for. Must be less than {@link #getLevels()}.
|
||||
* @param xoffset x-offset in texel of the region to modify
|
||||
* @param yoffset y-offset in texel of the region to modify
|
||||
* @param width width in texel of the region to modify
|
||||
* @param height height in texel of the region to modify
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
* <code>buffer</code>'s {@link Format format} must match that
|
||||
* of {@link #getFormat()}
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*
|
||||
* @see Builder#sampler
|
||||
* @see PixelBufferDescriptor
|
||||
*/
|
||||
public void setImage(@NonNull Engine engine,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
|
||||
@@ -453,9 +816,33 @@ public class Texture {
|
||||
}
|
||||
}
|
||||
|
||||
// note: faceOffsetsInBytes are offsets in byte in the buffer relative to the current position()
|
||||
// note: use Texture CubemapFace to index the faceOffsetsInBytes array
|
||||
// note: we assume all 6 faces are tightly packed
|
||||
/**
|
||||
* <code>setImage</code> is used to specify all six images of a cubemap level and
|
||||
* follows exactly the OpenGL conventions
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use
|
||||
* {@link Sampler#SAMPLER_CUBEMAP SAMPLER_CUBEMAP}.</p>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param level Level to set the image for. Must be less than {@link #getLevels()}.
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
* <code>buffer</code>'s {@link Format format} must match that
|
||||
* of {@link #getFormat()}
|
||||
* @param faceOffsetsInBytes Offsets in bytes into <code>buffer</code> for all six images.
|
||||
* The offsets are specified in the following order:
|
||||
* +x, -x, +y, -y, +z, -z.
|
||||
*
|
||||
* <p><code>faceOffsetsInBytes</code> are offsets in byte in the <code>buffer</code> relative
|
||||
* to the current {@link Buffer#position()}. Use {@link CubemapFace} to index the
|
||||
* <code>faceOffsetsInBytes</code> array. All six faces must be tightly packed.</p>
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*
|
||||
* @see Builder#sampler
|
||||
* @see PixelBufferDescriptor
|
||||
*/
|
||||
public void setImage(@NonNull Engine engine, @IntRange(from = 0) int level,
|
||||
@NonNull PixelBufferDescriptor buffer,
|
||||
@NonNull @Size(min = 6) int[] faceOffsetsInBytes) {
|
||||
@@ -478,10 +865,60 @@ public class Texture {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the external image to associate with this <code>Texture</code>.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}.</p>
|
||||
* <p>Typically the external image is OS specific, and can be a video or camera frame.
|
||||
* There are many restrictions when using an external image as a texture, such as:</p>
|
||||
* <ul>
|
||||
* <li> only the level of detail (LOD) 0 can be specified</li>
|
||||
* <li> only {@link TextureSampler.MagFilter#NEAREST NEAREST} or
|
||||
* {@link TextureSampler.MagFilter#LINEAR LINEAR} filtering is supported</li>
|
||||
* <li> the size and format of the texture is defined by the external image</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param eglImage An opaque handle to a platform specific image. Supported types are
|
||||
* <code>eglImageOES</code> on Android and <code>CVPixelBufferRef</code> on iOS.
|
||||
* <p>On iOS the following pixel formats are supported: <ul>
|
||||
* <li><code>kCVPixelFormatType_32BGRA</code></li>
|
||||
* <li><code>kCVPixelFormatType_420YpCbCr8BiPlanarFullRange</code></li>
|
||||
* </ul></p>
|
||||
*
|
||||
* @see Builder#sampler
|
||||
*/
|
||||
public void setExternalImage(@NonNull Engine engine, long eglImage) {
|
||||
nSetExternalImage(getNativeObject(), engine.getNativeObject(), eglImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the external stream to associate with this <code>Texture</code>.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must use
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}.</p>
|
||||
* <p>Typically the external image is OS specific, and can be a video or camera frame.
|
||||
* There are many restrictions when using an external image as a texture, such as:</p>
|
||||
* <ul>
|
||||
* <li> only the level of detail (LOD) 0 can be specified</li>
|
||||
* <li> only {@link TextureSampler.MagFilter#NEAREST NEAREST} or
|
||||
* {@link TextureSampler.MagFilter#LINEAR LINEAR} filtering is supported</li>
|
||||
* <li> the size and format of the texture is defined by the external image</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param stream A {@link Stream} object
|
||||
*
|
||||
* @exception IllegalStateException if the sampler type is not
|
||||
* {@link Sampler#SAMPLER_EXTERNAL SAMPLER_EXTERNAL}
|
||||
*
|
||||
* @see Stream
|
||||
* @see Builder#sampler
|
||||
*
|
||||
*/
|
||||
public void setExternalStream(@NonNull Engine engine, @NonNull Stream stream) {
|
||||
long nativeObject = getNativeObject();
|
||||
long streamNativeObject = stream.getNativeObject();
|
||||
@@ -492,10 +929,68 @@ public class Texture {
|
||||
nSetExternalStream(nativeObject, engine.getNativeObject(), streamNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates all the mipmap levels automatically. This requires the texture to have a
|
||||
* color-renderable format.
|
||||
*
|
||||
* <p>This <code>Texture</code> instance must <b>not</b> use
|
||||
* {@link Sampler#SAMPLER_CUBEMAP SAMPLER_CUBEMAP}, or it has no effect.</p>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
*/
|
||||
public void generateMipmaps(@NonNull Engine engine) {
|
||||
nGenerateMipmaps(getNativeObject(), engine.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reflection map from an environment map.
|
||||
*
|
||||
* <p>This is a utility function that replaces calls to {@link #setImage}.
|
||||
* The provided environment map is processed and all mipmap levels are populated. The
|
||||
* processing is similar to the offline tool <code>cmgen</code> at a lower quality setting.</p>
|
||||
*
|
||||
* <p>This function is intended to be used when the environment cannot be processed offline,
|
||||
* for instance if it's generated at runtime.</p>
|
||||
*
|
||||
* <p>The source data must obey to some constraints:</p>
|
||||
* <ul>
|
||||
* <li>the data {@link Format format} must be {@link Format#RGB}</li>
|
||||
* <li>the data {@link Type type} must be one of
|
||||
* <ul>
|
||||
* <li>{@link Type#FLOAT}</li>
|
||||
* <li>{@link Type#HALF}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>The current texture must be a cubemap.</p>
|
||||
*
|
||||
* <p>The reflections cubemap's {@link InternalFormat internal format} cannot be a compressed format.</p>
|
||||
*
|
||||
* <p>The reflections cubemap's dimension must be a power-of-two.</p>
|
||||
*
|
||||
* <p>This operation is computationally intensive, especially with large environments and
|
||||
* is currently <b>synchronous</b>. Expect about 1ms for a 16 × 16 cubemap.</p>
|
||||
*
|
||||
* @param engine {@link Engine} this texture is associated to. Must be the
|
||||
* instance passed to {@link Builder#build Builder.build()}.
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
* <code>buffer</code>'s {@link Format format} and {@link Type type} must match
|
||||
* the constraints above.
|
||||
* @param faceOffsetsInBytes Offsets in bytes into <code>buffer</code> for all six images.
|
||||
* The offsets are specified in the following order:
|
||||
* +x, -x, +y, -y, +z, -z.
|
||||
*
|
||||
* @param options Optional parameter to control user-specified quality and options.
|
||||
*
|
||||
* <p><code>faceOffsetsInBytes</code> are offsets in byte in the <code>buffer</code> relative
|
||||
* to the current {@link Buffer#position()}. Use {@link CubemapFace} to index the
|
||||
* <code>faceOffsetsInBytes</code> array. All six faces must be tightly packed.</p>
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*/
|
||||
public void generatePrefilterMipmap(@NonNull Engine engine,
|
||||
@NonNull PixelBufferDescriptor buffer, @NonNull @Size(min = 6) int[] faceOffsetsInBytes,
|
||||
PrefilterOptions options) {
|
||||
|
||||
@@ -18,24 +18,60 @@ package com.google.android.filament;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* <code>TextureSampler</code> defines how a texture is accessed.
|
||||
*/
|
||||
public class TextureSampler {
|
||||
public enum WrapMode {
|
||||
/**
|
||||
* The edge of the texture extends to infinity.
|
||||
*/
|
||||
CLAMP_TO_EDGE,
|
||||
/**
|
||||
* The texture infinitely repeats in the wrap direction.
|
||||
*/
|
||||
REPEAT,
|
||||
/**
|
||||
* The texture infinitely repeats and mirrors in the wrap direction.
|
||||
*/
|
||||
MIRRORED_REPEAT
|
||||
}
|
||||
|
||||
public enum MinFilter {
|
||||
/**
|
||||
* No filtering. Nearest neighbor is used.
|
||||
*/
|
||||
NEAREST,
|
||||
/**
|
||||
* Box filtering. Weighted average of 4 neighbors is used.
|
||||
*/
|
||||
LINEAR,
|
||||
/**
|
||||
* Mip-mapping is activated. But no filtering occurs.
|
||||
*/
|
||||
NEAREST_MIPMAP_NEAREST,
|
||||
/**
|
||||
* Box filtering within a mip-map level.
|
||||
*/
|
||||
LINEAR_MIPMAP_NEAREST,
|
||||
/**
|
||||
* Mip-map levels are interpolated, but no other filtering occurs.
|
||||
*/
|
||||
NEAREST_MIPMAP_LINEAR,
|
||||
/**
|
||||
* Both interpolated Mip-mapping and linear filtering are used.
|
||||
*/
|
||||
LINEAR_MIPMAP_LINEAR,
|
||||
}
|
||||
|
||||
public enum MagFilter {
|
||||
/**
|
||||
* No filtering. Nearest neighbor is used.
|
||||
*/
|
||||
NEAREST,
|
||||
/**
|
||||
* Box filtering. Weighted average of 4 neighbors is used.
|
||||
*/
|
||||
LINEAR
|
||||
}
|
||||
|
||||
@@ -44,114 +80,246 @@ public class TextureSampler {
|
||||
COMPARE_TO_TEXTURE
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison functions for the depth sampler.
|
||||
*/
|
||||
public enum CompareFunction {
|
||||
/**
|
||||
* Less or equal
|
||||
*/
|
||||
LESS_EQUAL,
|
||||
/**
|
||||
* Greater or equal
|
||||
*/
|
||||
GREATER_EQUAL,
|
||||
/**
|
||||
* Strictly less than
|
||||
*/
|
||||
LESS,
|
||||
/**
|
||||
* Strictly greater than
|
||||
*/
|
||||
GREATER,
|
||||
/**
|
||||
* Equal
|
||||
*/
|
||||
EQUAL,
|
||||
/**
|
||||
* Not equal
|
||||
*/
|
||||
NOT_EQUAL,
|
||||
/**
|
||||
* Always. Depth testing is deactivated.
|
||||
*/
|
||||
ALWAYS,
|
||||
/**
|
||||
* Never. The depth test always fails.
|
||||
*/
|
||||
NEVER
|
||||
}
|
||||
|
||||
int mSampler = 0; // bit field used by native
|
||||
|
||||
/**
|
||||
* Min filter: LINEAR_MIPMAP_LINEAR
|
||||
* Mag filter: LINEAR
|
||||
* Wrap mode: REPEAT
|
||||
* Initializes the <code>TextureSampler</code> with default values.
|
||||
* <br>Minification filter: {@link MinFilter#LINEAR_MIPMAP_LINEAR}
|
||||
* <br>Magnification filter: {@link MagFilter#LINEAR}
|
||||
* <br>Wrap modes: {@link WrapMode#REPEAT}
|
||||
*/
|
||||
public TextureSampler() {
|
||||
this(MinFilter.LINEAR_MIPMAP_LINEAR, MagFilter.LINEAR, WrapMode.REPEAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with default values, but specifying the
|
||||
* minification and magnification filters.
|
||||
*
|
||||
* @param minMag {@link MagFilter magnification filter},
|
||||
* the minification filter will be set to the same value.
|
||||
*/
|
||||
public TextureSampler(@NonNull MagFilter minMag) {
|
||||
this(minMag, WrapMode.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with user specified values.
|
||||
*
|
||||
* @param minMag {@link MagFilter magnification filter},
|
||||
* the minification filter will be set to the same value.
|
||||
* @param wrap {@link WrapMode wrapping mode} for all directions
|
||||
*/
|
||||
public TextureSampler(@NonNull MagFilter minMag, @NonNull WrapMode wrap) {
|
||||
this(minFilterFromMagFilter(minMag), minMag, wrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with user specified values.
|
||||
*
|
||||
* @param min {@link MagFilter magnification filter}
|
||||
* @param mag {@link MinFilter minification filter}
|
||||
* @param wrap {@link WrapMode wrapping mode} for all directions
|
||||
*/
|
||||
public TextureSampler(@NonNull MinFilter min, @NonNull MagFilter mag, @NonNull WrapMode wrap) {
|
||||
this(min, mag, wrap, wrap, wrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with user specified values.
|
||||
*
|
||||
* @param min {@link MagFilter magnification filter}
|
||||
* @param mag {@link MinFilter minification filter}
|
||||
* @param s {@link WrapMode wrapping mode} for the s (horizontal) direction
|
||||
* @param t {@link WrapMode wrapping mode} for the t (vertical) direction
|
||||
* @param r {@link WrapMode wrapping mode} fot the r (depth) direction
|
||||
*/
|
||||
public TextureSampler(@NonNull MinFilter min, @NonNull MagFilter mag,
|
||||
@NonNull WrapMode s, @NonNull WrapMode t, @NonNull WrapMode r) {
|
||||
mSampler = nCreateSampler(min.ordinal(), mag.ordinal(),
|
||||
s.ordinal(), t.ordinal(), r.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with user specified comparison mode. The
|
||||
* comparison fonction is set to {@link CompareFunction#LESS_EQUAL}.
|
||||
*
|
||||
* @param mode {@link CompareMode comparison mode}
|
||||
*/
|
||||
public TextureSampler(@NonNull CompareMode mode) {
|
||||
this(mode, CompareFunction.LESS_EQUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>TextureSampler</code> with user specified comparison mode and function.
|
||||
*
|
||||
* @param mode {@link CompareMode comparison mode}
|
||||
* @param function {@link CompareFunction comparison function}
|
||||
*/
|
||||
public TextureSampler(@NonNull CompareMode mode, @NonNull CompareFunction function) {
|
||||
mSampler = nCreateCompareSampler(mode.ordinal(), function.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minification filter
|
||||
*/
|
||||
public MinFilter getMinFilter() {
|
||||
return MinFilter.values()[nGetMinFilter(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minification filter.
|
||||
*
|
||||
* @param filter minification filter
|
||||
*/
|
||||
public void setMinFilter(MinFilter filter) {
|
||||
mSampler = nSetMinFilter(mSampler, filter.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the magnification filter
|
||||
*/
|
||||
public MagFilter getMagFilter() {
|
||||
return MagFilter.values()[nGetMagFilter(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the magnification filter.
|
||||
*
|
||||
* @param filter magnification filter
|
||||
*/
|
||||
public void setMagFilter(MagFilter filter) {
|
||||
mSampler = nSetMagFilter(mSampler, filter.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the wrapping mode in the s (horizontal) direction
|
||||
*/
|
||||
public WrapMode getWrapModeS() {
|
||||
return WrapMode.values()[nGetWrapModeS(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wrapping mode in the s (horizontal) direction.
|
||||
* @param mode wrapping mode
|
||||
*/
|
||||
public void setWrapModeS(WrapMode mode) {
|
||||
mSampler = nSetWrapModeS(mSampler, mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the wrapping mode in the t (vertical) direction
|
||||
*/
|
||||
public WrapMode getWrapModeT() {
|
||||
return WrapMode.values()[nGetWrapModeT(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wrapping mode in the t (vertical) direction.
|
||||
* @param mode wrapping mode
|
||||
*/
|
||||
public void setWrapModeT(WrapMode mode) {
|
||||
mSampler = nSetWrapModeT(mSampler, mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the wrapping mode in the r (depth) direction
|
||||
*/
|
||||
public WrapMode getWrapModeR() {
|
||||
return WrapMode.values()[nGetWrapModeR(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wrapping mode in the t (depth) direction.
|
||||
* @param mode wrapping mode
|
||||
*/
|
||||
public void setWrapModeR(WrapMode mode) {
|
||||
mSampler = nSetWrapModeR(mSampler, mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the anisotropy value
|
||||
* @see #setAnisotropy
|
||||
*/
|
||||
public float getAnisotropy() {
|
||||
return nGetAnisotropy(mSampler);
|
||||
}
|
||||
|
||||
/**
|
||||
* This controls anisotropic filtering.
|
||||
*
|
||||
* @param anisotropy Amount of anisotropy, should be a power-of-two. The default is 0.
|
||||
* The maximum permissible value is 7.
|
||||
*/
|
||||
public void setAnisotropy(float anisotropy) {
|
||||
mSampler = nSetAnisotropy(mSampler, anisotropy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the comparison mode
|
||||
*/
|
||||
public CompareMode getCompareMode() {
|
||||
return CompareMode.values()[nGetCompareMode(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the comparison mode.
|
||||
*
|
||||
* @param mode comparison mode
|
||||
*/
|
||||
public void setCompareMode(CompareMode mode) {
|
||||
mSampler = nSetCompareMode(mSampler, mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the comparison function
|
||||
*/
|
||||
public CompareFunction getCompareFunction() {
|
||||
return CompareFunction.values()[nGetCompareFunction(mSampler)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the comparison function.
|
||||
* @param function the comparison function
|
||||
*/
|
||||
public void setCompareFunction(CompareFunction function) {
|
||||
mSampler = nSetCompareFunction(mSampler, function.ordinal());
|
||||
}
|
||||
|
||||
@@ -20,47 +20,154 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.Size;
|
||||
|
||||
public class TransformManager {
|
||||
/**
|
||||
* <code>TransformManager</code> is used to add transform components to entities.
|
||||
*
|
||||
* <p>A transform component gives an entity a position and orientation in space in the coordinate
|
||||
* space of its parent transform. The <code>TransformManager</code> takes care of computing the
|
||||
* world-space transform of each component (i.e. its transform relative to the root).</p>
|
||||
*
|
||||
* <h1>Creation and destruction</h1>
|
||||
*
|
||||
* A transform component is created using {@link TransformManager#create} and destroyed by calling
|
||||
* {@link TransformManager#destroy}.
|
||||
*
|
||||
* <pre>
|
||||
* Engine engine = Engine.create();
|
||||
* EntityManager entityManager = EntityManager().get();
|
||||
* int object = entityManager.create();
|
||||
*
|
||||
* TransformManager tcm = engine.getTransformManager();
|
||||
*
|
||||
* // create the transform component
|
||||
* tcm.create(object);
|
||||
*
|
||||
* // set its transform
|
||||
* float[] transform = ...; // transform to set
|
||||
* EntityInstance i = tcm.getInstance(object);
|
||||
* tcm.setTransform(i, transform));
|
||||
*
|
||||
* // destroy the transform component
|
||||
* tcm.destroy(object);
|
||||
* </pre>
|
||||
*
|
||||
*/public class TransformManager {
|
||||
private long mNativeObject;
|
||||
|
||||
TransformManager(long nativeTransformManager) {
|
||||
mNativeObject = nativeTransformManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a particular {@link Entity} is associated with a component of this
|
||||
* <code>TransformManager</code>
|
||||
*
|
||||
* @param entity an {@link Entity}
|
||||
* @return true if this {@link Entity} has a component associated with this manager
|
||||
*/
|
||||
public boolean hasComponent(@Entity int entity) {
|
||||
return nHasComponent(mNativeObject, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link EntityInstance} representing the transform component associated with the
|
||||
* given {@link Entity}.
|
||||
*
|
||||
* @param entity an {@link Entity}
|
||||
* @return an {@link EntityInstance}, which represents the transform component associated with
|
||||
* the {@link Entity} <code>entity</code>
|
||||
* @see #hasComponent
|
||||
*/
|
||||
@EntityInstance
|
||||
public int getInstance(@Entity int entity) {
|
||||
return nGetInstance(mNativeObject, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transform component and associates it with the given entity. The component is
|
||||
* initialized with the identity transform.
|
||||
* If this component already exists on the given entity, it is first
|
||||
* destroyed as if {@link #destroy} was called.
|
||||
*
|
||||
* @param entity an {@link Entity} to associate a transform component to.
|
||||
* @see #destroy
|
||||
*/
|
||||
@EntityInstance
|
||||
public int create(@Entity int entity) {
|
||||
return nCreate(mNativeObject, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transform component with a parent and associates it with the given entity.
|
||||
* If this component already exists on the given entity, it is first
|
||||
* destroyed as if {@link #destroy} was called.
|
||||
*
|
||||
* @param entity an {@link Entity} to associate a transform component to.
|
||||
* @param parent the {@link EntityInstance} of the parent transform
|
||||
* @param localTransform the transform, relative to the parent, to initialize the transform
|
||||
* component with.
|
||||
* @see #destroy
|
||||
*/
|
||||
@EntityInstance
|
||||
public int create(@Entity int entity, @EntityInstance int parent,
|
||||
@Nullable @Size(min = 16) float[] localTransform) {
|
||||
return nCreateArray(mNativeObject, entity, parent, localTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this component from the given entity, children are orphaned.
|
||||
*
|
||||
* @param entity an {@link Entity}.
|
||||
* If this transform had children, these are orphaned, which means their local
|
||||
* transform becomes a world transform. Usually it's nonsensical.
|
||||
* It's recommended to make sure that a destroyed transform doesn't have children.
|
||||
* @see #create
|
||||
*/
|
||||
public void destroy(@Entity int entity) {
|
||||
nDestroy(mNativeObject, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-parents an entity to a new one.
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to re-parent
|
||||
* @param newParent the {@link EntityInstance} of the new parent transform.
|
||||
* It is an error to re-parent an entity to a descendant and will cause
|
||||
* undefined behaviour.
|
||||
* @see #getInstance
|
||||
*/
|
||||
public void setParent(@EntityInstance int i, @EntityInstance int newParent) {
|
||||
nSetParent(mNativeObject, i, newParent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a local transform of a transform component.
|
||||
* <p>This operation can be slow if the hierarchy of transform is too deep, and this
|
||||
* will be particularly bad when updating a lot of transforms. In that case,
|
||||
* consider using {@link #openLocalTransformTransaction} / {@link #commitLocalTransformTransaction}.</p>
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to set the local
|
||||
* transform to.
|
||||
* @param localTransform the local transform (i.e. relative to the parent).
|
||||
* @see #getTransform
|
||||
*/
|
||||
public void setTransform(@EntityInstance int i,
|
||||
@NonNull @Size(min = 16) float[] localTransform) {
|
||||
Asserts.assertMat4fIn(localTransform);
|
||||
nSetTransform(mNativeObject, i, localTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local transform of a transform component.
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to query the
|
||||
* local transform from.
|
||||
* @param outLocalTransform a 16 <code>float</code> array to receive the result.
|
||||
* If <code>null</code> is given, a new suitable array is allocated.
|
||||
* @return the local transform of the component (i.e. relative to the parent). This always
|
||||
* returns the value set by setTransform().
|
||||
* @see #setTransform
|
||||
*/
|
||||
@NonNull
|
||||
@Size(min = 16)
|
||||
public float[] getTransform(@EntityInstance int i,
|
||||
@@ -70,6 +177,17 @@ public class TransformManager {
|
||||
return outLocalTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the world transform of a transform component.
|
||||
*
|
||||
* @param i the {@link EntityInstance} of the transform component to query the
|
||||
* world transform from.
|
||||
* @param outWorldTransform a 16 <code>float</code> array to receive the result.
|
||||
* If <code>null</code> is given, a new suitable array is allocated
|
||||
* @return The world transform of the component (i.e. relative to the root). This is the
|
||||
* composition of this component's local transform with its parent's world transform.
|
||||
* @see #setTransform
|
||||
*/
|
||||
@NonNull
|
||||
@Size(min = 16)
|
||||
public float[] getWorldTransform(@EntityInstance int i,
|
||||
@@ -79,10 +197,36 @@ public class TransformManager {
|
||||
return outWorldTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a local transform transaction. During a transaction, {@link #getWorldTransform} can
|
||||
* return an invalid transform until {@link #commitLocalTransformTransaction} is called.
|
||||
* However, {@link #setTransform} will perform significantly better and in constant time.
|
||||
*
|
||||
* <p>This is useful when updating many transforms and the transform hierarchy is deep (say more
|
||||
* than 4 or 5 levels).</p>
|
||||
*
|
||||
* <p>If the local transform transaction is already open, this is a no-op.</p>
|
||||
*
|
||||
* @see #commitLocalTransformTransaction
|
||||
* @see #setTransform
|
||||
*/
|
||||
public void openLocalTransformTransaction() {
|
||||
nOpenLocalTransformTransaction(mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the currently open local transform transaction. When this returns, calls
|
||||
* to {@link #getWorldTransform} will return the proper value.
|
||||
*
|
||||
* <p>Failing to call this method when done updating the local transform will cause
|
||||
* a lot of rendering problems. The system never closes the transaction
|
||||
* automatically.</p>
|
||||
*
|
||||
* <p>If the local transform transaction is not open, this is a no-op.</p>
|
||||
*
|
||||
* @see #openLocalTransformTransaction
|
||||
* @see #setTransform
|
||||
*/
|
||||
public void commitLocalTransformTransaction() {
|
||||
nCommitLocalTransformTransaction(mNativeObject);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,33 @@ import android.support.annotation.Nullable;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
|
||||
/**
|
||||
* Holds a set of buffers that define the geometry of a <code>Renderable</code>.
|
||||
*
|
||||
* <p>
|
||||
* The geometry of the <code>Renderable</code> itself is defined by a set of vertex attributes such as
|
||||
* position, color, normals, tangents, etc...
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* There is no need to have a 1-to-1 mapping between attributes and buffer. A buffer can hold the
|
||||
* data of several attributes -- attributes are then referred as being "interleaved".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The buffers themselves are GPU resources, therefore mutating their data can be relatively slow.
|
||||
* For this reason, it is best to separate the constant data from the dynamic data into multiple
|
||||
* buffers.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It is possible, and even encouraged, to use a single vertex buffer for several
|
||||
* <code>Renderable</code>s.
|
||||
* </p>
|
||||
*
|
||||
* @see IndexBuffer
|
||||
* @see RenderableManager
|
||||
*/
|
||||
public class VertexBuffer {
|
||||
private long mNativeObject;
|
||||
|
||||
@@ -77,22 +104,47 @@ public class VertexBuffer {
|
||||
HALF3,
|
||||
HALF4,
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the quaternion type for the {@link #populateTangentQuaternions} utility.
|
||||
*/
|
||||
public enum QuatType {
|
||||
HALF4, // 2 bytes per component as half-floats (8 bytes per quat)
|
||||
SHORT4, // 2 bytes per component as normalized integers (8 bytes per quat)
|
||||
FLOAT4, // 4 bytes per component as floats (16 bytes per quat)
|
||||
/** 2 bytes per component as half-floats (8 bytes per quat) */
|
||||
HALF4,
|
||||
|
||||
/** 2 bytes per component as normalized integers (8 bytes per quat) */
|
||||
SHORT4,
|
||||
|
||||
/** 4 bytes per component as floats (16 bytes per quat) */
|
||||
FLOAT4,
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the parameters for the {@link #populateTangentQuaternions} utility.
|
||||
*/
|
||||
public static class QuatTangentContext {
|
||||
public QuatType quatType; // desired quaternion type (required)
|
||||
public int quatCount; // number of quaternions (required)
|
||||
public Buffer outBuffer; // pre-allocated output buffer (required)
|
||||
public int outStride; // desired stride in bytes (optional)
|
||||
public Buffer normals; // source normals (required)
|
||||
public int normalsStride; // normals stride in bytes (optional)
|
||||
public Buffer tangents; // source tangents (optional)
|
||||
public int tangentsStride; // tangents stride in bytes (optional)
|
||||
/** desired quaternion type (required) */
|
||||
public QuatType quatType;
|
||||
|
||||
/** number of quaternions (required) */
|
||||
public int quatCount;
|
||||
|
||||
/** pre-allocated output buffer (required) */
|
||||
public Buffer outBuffer;
|
||||
|
||||
/** desired stride in bytes (optional) */
|
||||
public int outStride;
|
||||
|
||||
/** source normals (required) */
|
||||
public Buffer normals;
|
||||
|
||||
/** normals stride in bytes (optional) */
|
||||
public int normalsStride;
|
||||
|
||||
/** source tangents (optional) */
|
||||
public Buffer tangents;
|
||||
|
||||
/** tangents stride in bytes (optional) */
|
||||
public int tangentsStride;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
@@ -105,18 +157,64 @@ public class VertexBuffer {
|
||||
mFinalizer = new BuilderFinalizer(mNativeBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of each buffer in this set, expressed in in number of vertices.
|
||||
*
|
||||
* @param vertexCount number of vertices in each buffer in this set
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder vertexCount(@IntRange(from = 1) int vertexCount) {
|
||||
nBuilderVertexCount(mNativeBuilder, vertexCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines how many buffers will be created in this vertex buffer set. These buffers are
|
||||
* later referenced by index from 0 to <code>bufferCount</code> - 1.
|
||||
*
|
||||
* This call is mandatory. The default is 0.
|
||||
*
|
||||
* @param bufferCount number of buffers in this vertex buffer set. The maximum value is 8.
|
||||
*
|
||||
* @return this <code>Builder</code> for chaining calls
|
||||
*/
|
||||
@NonNull
|
||||
public Builder bufferCount(@IntRange(from = 1) int bufferCount) {
|
||||
nBuilderBufferCount(mNativeBuilder, bufferCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an attribute for this vertex buffer set.
|
||||
*
|
||||
* Using <code>byteOffset</code> and <code>byteStride</code>, attributes can be interleaved
|
||||
* in the same buffer.
|
||||
*
|
||||
* <p>
|
||||
* This is a no-op if the <code>attribute</code> is an invalid enum.
|
||||
* This is a no-op if the <code>bufferIndex</code> is out of bounds.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Warning: <code>VertexAttribute.TANGENTS</code> must be specified as a quaternion and is
|
||||
* how normals are specified.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute the attribute to set up
|
||||
* @param bufferIndex the index of the buffer containing the data for this attribute. Must
|
||||
* be between 0 and bufferCount() - 1.
|
||||
* @param attributeType the type of the attribute data (e.g. byte, float3, etc...)
|
||||
* @param byteOffset offset in <i>bytes</i> into the buffer <code>bufferIndex</code>
|
||||
* @param byteStride stride in <i>bytes</i> to the next element of this attribute. When
|
||||
* set to zero the attribute size, as defined by
|
||||
* <code>attributeType</code> is used.
|
||||
*
|
||||
* @return A reference to this <code>Builder</code> for chaining calls.
|
||||
*
|
||||
* @see VertexAttribute
|
||||
*/
|
||||
@NonNull
|
||||
public Builder attribute(@NonNull VertexAttribute attribute,
|
||||
@IntRange(from = 0) int bufferIndex, @NonNull AttributeType attributeType,
|
||||
@@ -126,24 +224,82 @@ public class VertexBuffer {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an attribute for this vertex buffer set.
|
||||
*
|
||||
* Using <code>byteOffset</code> and <code>byteStride</code>, attributes can be interleaved
|
||||
* in the same buffer.
|
||||
*
|
||||
* <p>
|
||||
* This is a no-op if the <code>attribute</code> is an invalid enum.
|
||||
* This is a no-op if the <code>bufferIndex</code> is out of bounds.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Warning: <code>VertexAttribute.TANGENTS</code> must be specified as a quaternion and is
|
||||
* how normals are specified.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute the attribute to set up
|
||||
* @param bufferIndex the index of the buffer containing the data for this attribute. Must
|
||||
* be between 0 and bufferCount() - 1.
|
||||
* @param attributeType the type of the attribute data (e.g. byte, float3, etc...)
|
||||
*
|
||||
* @return A reference to this <code>Builder</code> for chaining calls.
|
||||
*
|
||||
* @see VertexAttribute
|
||||
*/
|
||||
@NonNull
|
||||
public Builder attribute(@NonNull VertexAttribute attribute,
|
||||
@IntRange(from = 0) int bufferIndex, @NonNull AttributeType attributeType) {
|
||||
return attribute(attribute, bufferIndex, attributeType, 0, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a given attribute should be normalized. By default attributes are not
|
||||
* normalized. A normalized attribute is mapped between 0 and 1 in the shader. This applies
|
||||
* only to integer types.
|
||||
*
|
||||
* @param attribute enum of the attribute to set the normalization flag to
|
||||
*
|
||||
* @return this <code>Builder</code> object for chaining calls.
|
||||
*
|
||||
* This is a no-op if the <code>attribute</code> is an invalid enum.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder normalized(@NonNull VertexAttribute attribute) {
|
||||
nBuilderNormalized(mNativeBuilder, attribute.ordinal(), true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a given attribute should be normalized. By default attributes are not
|
||||
* normalized. A normalized attribute is mapped between 0 and 1 in the shader. This applies
|
||||
* only to integer types.
|
||||
*
|
||||
* @param attribute enum of the attribute to set the normalization flag to
|
||||
* @param enabled true to automatically normalize the given attribute
|
||||
*
|
||||
* @return this <code>Builder</code> object for chaining calls.
|
||||
*
|
||||
* This is a no-op if the <code>attribute</code> is an invalid enum.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder normalized(@NonNull VertexAttribute attribute, boolean enabled) {
|
||||
nBuilderNormalized(mNativeBuilder, attribute.ordinal(), enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the <code>VertexBuffer</code> object and returns a pointer to it.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this <code>VertexBuffer</code>
|
||||
* with
|
||||
*
|
||||
* @return the newly created <code>VertexBuffer</code> object
|
||||
*
|
||||
* @exception IllegalStateException if the VertexBuffer could not be created
|
||||
*/
|
||||
@NonNull
|
||||
public VertexBuffer build(@NonNull Engine engine) {
|
||||
long nativeVertexBuffer = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
|
||||
@@ -168,24 +324,68 @@ public class VertexBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex count.
|
||||
*
|
||||
* @return number of vertices in this vertex buffer set
|
||||
*/
|
||||
@IntRange(from = 0)
|
||||
public int getVertexCount() {
|
||||
return nGetVertexCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously copy-initializes the specified buffer from the given buffer data.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>VertexBuffer</code> with
|
||||
* @param bufferIndex index of the buffer to initialize. Must be between 0 and
|
||||
* bufferCount() - 1.
|
||||
* @param buffer a CPU-side {@link Buffer} representing the data used to initialize
|
||||
* the <code>VertexBuffer</code> at index <code>bufferIndex</code>.
|
||||
* <code>buffer</code> should contain raw, untyped data that will
|
||||
* be copied as-is into the buffer.
|
||||
*/
|
||||
public void setBufferAt(@NonNull Engine engine, int bufferIndex, @NonNull Buffer buffer) {
|
||||
setBufferAt(engine, bufferIndex, buffer, 0, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously copy-initializes a region of the specified buffer from the given buffer data.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>VertexBuffer</code> with
|
||||
* @param bufferIndex index of the buffer to initialize. Must be between 0 and
|
||||
* bufferCount() - 1.
|
||||
* @param buffer a CPU-side {@link Buffer} representing the data used to initialize
|
||||
* the <code>VertexBuffer</code> at index <code>bufferIndex</code>.
|
||||
* <code>buffer</code> should contain raw, untyped data that will
|
||||
* be copied as-is into the buffer.
|
||||
* @param destOffsetInBytes offset in <i>bytes</i> into the buffer at index
|
||||
* <code>bufferIndex</code> of this vertex buffer set.
|
||||
*/
|
||||
public void setBufferAt(@NonNull Engine engine, int bufferIndex, @NonNull Buffer buffer,
|
||||
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count) {
|
||||
setBufferAt(engine, bufferIndex, buffer, destOffsetInBytes, count, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid handler types:
|
||||
* - Android: Handler, Executor
|
||||
* - Other: Executor
|
||||
* Asynchronously copy-initializes a region of the specified buffer from the given buffer data.
|
||||
*
|
||||
* @param engine reference to the {@link Engine} to associate this
|
||||
* <code>VertexBuffer</code> with
|
||||
* @param bufferIndex index of the buffer to initialize. Must be between 0 and
|
||||
* bufferCount() - 1.
|
||||
* @param buffer a CPU-side {@link Buffer} representing the data used to initialize
|
||||
* the <code>VertexBuffer</code> at index <code>bufferIndex</code>.
|
||||
* <code>buffer</code> should contain raw, untyped data that will
|
||||
* be copied as-is into the buffer.
|
||||
* @param destOffsetInBytes offset in <i>bytes</i> into the buffer at index
|
||||
* <code>bufferIndex</code> of this vertex buffer set.
|
||||
* @param handler an {@link java.util.concurrent.Executor Executor}. On Android this
|
||||
* can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback a callback executed by <code>handler</code> when <code>buffer</code>
|
||||
* is no longer needed.
|
||||
*/
|
||||
public void setBufferAt(@NonNull Engine engine, int bufferIndex, @NonNull Buffer buffer,
|
||||
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count,
|
||||
@@ -197,7 +397,27 @@ public class VertexBuffer {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function that consumes normal vectors (and, optionally, tangent vectors) and
|
||||
* produces quaternions that can be passed into a TANGENTS buffer.
|
||||
*
|
||||
* <p>
|
||||
* The given output buffer must be preallocated with at least quatCount * outStride bytes.
|
||||
* <p>
|
||||
*
|
||||
* <p>
|
||||
* Normals are required but tangents are optional, in which case this function tries to generate
|
||||
* reasonable tangents. The given normals should be unit length.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If supplied, the tangent vectors should be unit length and should be orthogonal to the
|
||||
* normals. The w component of the tangent is a sign (-1 or +1) indicating handedness of the
|
||||
* basis.
|
||||
* </p>
|
||||
*
|
||||
* @param context an initialized QuatTangentContext object
|
||||
*/
|
||||
public static void populateTangentQuaternions(@NonNull QuatTangentContext context) {
|
||||
nPopulateTangentQuaternions(context.quatType.ordinal(), context.quatCount,
|
||||
context.outBuffer, context.outBuffer.remaining(), context.outStride,
|
||||
|
||||
@@ -23,6 +23,37 @@ import android.support.annotation.Size;
|
||||
|
||||
import static com.google.android.filament.Colors.LinearColor;
|
||||
|
||||
/**
|
||||
* Encompasses all the state needed for rendering a {@link Scene}.
|
||||
*
|
||||
* <p>
|
||||
* {@link Renderer#render} operates on <code>View</code> objects. These <code>View</code> objects
|
||||
* specify important parameters such as:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>The Scene</li>
|
||||
* <li>The Camera</li>
|
||||
* <li>The Viewport</li>
|
||||
* <li>Some rendering parameters</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <code>View</code> instances are heavy objects that internally cache a lot of data needed for
|
||||
* rendering. It is not advised for an application to use many View objects.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* For example, in a game, a <code>View</code> could be used for the main scene and another one for
|
||||
* the game's user interface. More <code>View</code> instances could be used for creating special
|
||||
* effects (e.g. a <code>View</code> is akin to a rendering pass).
|
||||
* </p>
|
||||
*
|
||||
* @see Renderer
|
||||
* @see Scene
|
||||
* @see Camera
|
||||
* @see RenderTarget
|
||||
*/
|
||||
public class View {
|
||||
private long mNativeObject;
|
||||
private String mName;
|
||||
@@ -35,24 +66,102 @@ public class View {
|
||||
private AmbientOcclusionOptions mAmbientOcclusionOptions;
|
||||
private RenderTarget mRenderTarget;
|
||||
|
||||
/**
|
||||
* Dynamic resolution can be used to either reach a desired target frame rate by lowering the
|
||||
* resolution of a <code>View</code>, or to increase the quality when the rendering is faster
|
||||
* than the target frame rate.
|
||||
*
|
||||
* <p>
|
||||
* This structure can be used to specify the minimum scale factor used when lowering the
|
||||
* resolution of a <code>View</code>, and the maximum scale factor used when increasing the
|
||||
* resolution for higher quality rendering. The scale factors can be controlled on each X and Y
|
||||
* axis independently. By default, all scale factors are set to 1.0.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Dynamic resolution is only supported on platforms where the time to render a frame can be
|
||||
* measured accurately. Dynamic resolution is currently only supported on Android.
|
||||
* </p>
|
||||
*/
|
||||
public static class DynamicResolutionOptions {
|
||||
/**
|
||||
* Enables or disables dynamic resolution on a View.
|
||||
*/
|
||||
public boolean enabled = false;
|
||||
|
||||
/**
|
||||
* If false, the system scales the major axis first.
|
||||
*/
|
||||
public boolean homogeneousScaling = false;
|
||||
|
||||
/**
|
||||
* Desired frame time in milliseconds.
|
||||
*/
|
||||
public float targetFrameTimeMilli = 1000.0f / 60.0f;
|
||||
|
||||
/**
|
||||
* Additional headroom for the GPU as a ratio of the targetFrameTime.
|
||||
*/
|
||||
public float headRoomRatio = 0.0f;
|
||||
|
||||
/**
|
||||
* Rate at which the scale will change to reach the target frame rate.
|
||||
*/
|
||||
public float scaleRate = 0.125f;
|
||||
|
||||
/**
|
||||
* The minimum scale in X and Y this View should use.
|
||||
*/
|
||||
public float minScale = 0.5f;
|
||||
|
||||
/**
|
||||
* The maximum scale in X and Y this View should use.
|
||||
*/
|
||||
public float maxScale = 1.0f;
|
||||
|
||||
/**
|
||||
* History size. higher values, tend to filter more (clamped to 30).
|
||||
*/
|
||||
public int history = 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for Ambient Occlusion
|
||||
* @see #setAmbientOcclusion
|
||||
*/
|
||||
public static class AmbientOcclusionOptions {
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
public float radius = 0.3f;
|
||||
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
*/
|
||||
public float bias = 0.005f;
|
||||
|
||||
/**
|
||||
* Controls ambient occlusion's contrast. Between 0 (linear) and 1 (squared)
|
||||
*/
|
||||
public float power = 0.0f;
|
||||
|
||||
/**
|
||||
* How each dimension of the AO buffer is scaled. Must be positive and <= 1.
|
||||
*/
|
||||
public float resolution = 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of the HDR color buffer.
|
||||
*
|
||||
* <p>
|
||||
* A quality of <code>HIGH</code> or <code>ULTRA</code> means using an RGB16F or RGBA16F color
|
||||
* buffer. This means colors in the LDR range (0..1) have 10 bit precision. A quality of
|
||||
* <code>LOW</code> or <code>MEDIUM</code> means using an R11G11B10F opaque color buffer or an
|
||||
* RGBA16F transparent color buffer. With R11G11B10F colors in the LDR range have a precision of
|
||||
* either 6 bits (red and green channels) or 5 bits (blue channel).
|
||||
* </p>
|
||||
*/
|
||||
public enum QualityLevel {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
@@ -60,30 +169,73 @@ public class View {
|
||||
ULTRA
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure used to set the color precision for the rendering of a <code>View</code>.
|
||||
*
|
||||
* <p>
|
||||
* This structure offers separate quality settings for different parts of the rendering
|
||||
* pipeline.
|
||||
* </p>
|
||||
*
|
||||
* @see #setRenderQuality
|
||||
* @see #getRenderQuality
|
||||
*/
|
||||
public static class RenderQuality {
|
||||
public QualityLevel hdrColorBuffer = QualityLevel.HIGH;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available ambient occlusion techniques.
|
||||
*
|
||||
* @see #setAmbientOcclusion
|
||||
*/
|
||||
public enum AmbientOcclusion {
|
||||
NONE,
|
||||
SSAO
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available post-processing anti-aliasing techniques.
|
||||
*
|
||||
* @see #setAntiAliasing
|
||||
* @see #getAntiAliasing
|
||||
*/
|
||||
public enum AntiAliasing {
|
||||
/**
|
||||
* No anti aliasing performed as part of post-processing.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* FXAA is a low-quality but very efficient type of anti-aliasing. (default).
|
||||
*/
|
||||
FXAA
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available tone-mapping operators
|
||||
*/
|
||||
public enum ToneMapping {
|
||||
/**
|
||||
* Equivalent to disabling tone-mapping.
|
||||
*/
|
||||
LINEAR,
|
||||
|
||||
/**
|
||||
* The Academy Color Encoding System (ACES).
|
||||
*/
|
||||
ACES
|
||||
}
|
||||
|
||||
/**
|
||||
* List of available post-processing dithering techniques.
|
||||
*/
|
||||
public enum Dithering {
|
||||
NONE,
|
||||
TEMPORAL
|
||||
}
|
||||
|
||||
/** @see #setDepthPrepass */
|
||||
public enum DepthPrepass {
|
||||
DEFAULT(-1),
|
||||
DISABLED(0),
|
||||
@@ -100,52 +252,135 @@ public class View {
|
||||
mNativeObject = nativeView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the View's name. Only useful for debugging.
|
||||
*/
|
||||
public void setName(@NonNull String name) {
|
||||
mName = name;
|
||||
nSetName(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the View's name.
|
||||
*/
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this View instance's Scene.
|
||||
*
|
||||
* <p>
|
||||
* This method associates the specified Scene with this View. Note that a particular scene can
|
||||
* be associated with several View instances. To remove an existing association, simply pass
|
||||
* null.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The View does not take ownership of the Scene pointer. Before destroying a Scene, be sure
|
||||
* to remove it from all assoicated Views.
|
||||
* </p>
|
||||
*
|
||||
* @see #getScene
|
||||
*/
|
||||
public void setScene(@Nullable Scene scene) {
|
||||
mScene = scene;
|
||||
nSetScene(getNativeObject(), scene == null ? 0 : scene.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this View's associated Scene, or null if none has been assigned.
|
||||
*
|
||||
* @see #setScene
|
||||
*/
|
||||
@Nullable
|
||||
public Scene getScene() {
|
||||
return mScene;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this View's Camera.
|
||||
*
|
||||
* <p>
|
||||
* This method associates the specified Camera with this View. A Camera can be associated with
|
||||
* several View instances. To remove an existing association, simply pass
|
||||
* null.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The View does not take ownership of the Scene pointer. Before destroying a Camera, be sure
|
||||
* to remove it from all assoicated Views.
|
||||
* </p>
|
||||
*
|
||||
* @see #getCamera
|
||||
*/
|
||||
public void setCamera(@Nullable Camera camera) {
|
||||
mCamera = camera;
|
||||
nSetCamera(getNativeObject(), camera == null ? 0 : camera.getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this View's associated Camera, or null if none has been assigned.
|
||||
*
|
||||
* @see #setCamera
|
||||
*/
|
||||
@Nullable
|
||||
public Camera getCamera() {
|
||||
return mCamera;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the rectangular rendering area.
|
||||
*
|
||||
* <p>
|
||||
* The viewport specifies where the content of the View (i.e. the Scene) is rendered in
|
||||
* the render target. The render target is automatically clipped to the Viewport.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If you wish subsequent changes to take effect please call this method again in order to
|
||||
* propagate the changes down to the native layer.
|
||||
* </p>
|
||||
*
|
||||
* @param viewport The Viewport to render the Scene into.
|
||||
*/
|
||||
public void setViewport(@NonNull Viewport viewport) {
|
||||
mViewport = viewport;
|
||||
nSetViewport(getNativeObject(),
|
||||
mViewport.left, mViewport.bottom, mViewport.width, mViewport.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rectangular rendering area.
|
||||
*
|
||||
* @see #setViewport
|
||||
*/
|
||||
@NonNull
|
||||
public Viewport getViewport() {
|
||||
return mViewport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color used to clear the Viewport when rendering this View.
|
||||
*
|
||||
* <p>This is ignored if a {@link Skybox} is present or if clearing has been disabled
|
||||
* via {@link #setClearTargets}. Defaults to black.</p>
|
||||
*
|
||||
* @see #getClearColor
|
||||
*/
|
||||
public void setClearColor(
|
||||
@LinearColor float r, @LinearColor float g, @LinearColor float b, float a) {
|
||||
nSetClearColor(getNativeObject(), r, g, b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the View clear color in a provided 4-tuple.
|
||||
*
|
||||
* @return A reference to the passed-in array.
|
||||
*
|
||||
* @see #setClearColor
|
||||
*/
|
||||
@NonNull @Size(min = 4)
|
||||
public float[] getClearColor(@NonNull @Size(min = 4) float[] out) {
|
||||
out = Asserts.assertFloat4(out);
|
||||
@@ -153,65 +388,178 @@ public class View {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which targets to clear (default: true, true, false)
|
||||
*
|
||||
* @see #setClearColor
|
||||
*/
|
||||
public void setClearTargets(boolean color, boolean depth, boolean stencil) {
|
||||
nSetClearTargets(getNativeObject(), color, depth, stencil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which layers are visible.
|
||||
*
|
||||
* <p>
|
||||
* Renderable objects can have one or several layers associated to them. Layers are
|
||||
* represented with an 8-bits bitmask, where each bit corresponds to a layer.
|
||||
* By default all layers are visible.
|
||||
* </p>
|
||||
*
|
||||
* @see RenderableManager#setLayerMask
|
||||
*
|
||||
* @param select a bitmask specifying which layer to set or clear using <code>values</code>.
|
||||
* @param values a bitmask where each bit sets the visibility of the corresponding layer
|
||||
* (1: visible, 0: invisible), only layers in <code>select</code> are affected.
|
||||
*/
|
||||
public void setVisibleLayers(
|
||||
@IntRange(from = 0, to = 255) int select,
|
||||
@IntRange(from = 0, to = 255) int values) {
|
||||
nSetVisibleLayers(getNativeObject(), select & 0xFF, values & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables shadow mapping. Enabled by default.
|
||||
*
|
||||
* @see LightManager.Builder#castShadows
|
||||
* @see RenderableManager.Builder#receiveShadows
|
||||
* @see RenderableManager.Builder#castShadows
|
||||
*/
|
||||
public void setShadowsEnabled(boolean enabled) {
|
||||
nSetShadowsEnabled(getNativeObject(), enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies an offscreen render target to render into.
|
||||
*
|
||||
* <p>
|
||||
* By default, the view's associated render target is null, which corresponds to the
|
||||
* SwapChain associated with the engine.
|
||||
* </p>
|
||||
*
|
||||
* @param target render target associated with view, or null for the swap chain
|
||||
*/
|
||||
public void setRenderTarget(@Nullable RenderTarget target) {
|
||||
mRenderTarget = target;
|
||||
nSetRenderTarget(getNativeObject(), target != null ? target.getNativeObject() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offscreen render target associated with this view.
|
||||
*
|
||||
* Returns null if the render target is the swap chain (which is default).
|
||||
*
|
||||
* @see #setRenderTarget
|
||||
*/
|
||||
@Nullable
|
||||
public RenderTarget getRenderTarget() {
|
||||
return mRenderTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many samples are to be used for MSAA in the post-process stage.
|
||||
* Default is 1 and disables MSAA.
|
||||
*
|
||||
* <p>
|
||||
* Note that anti-aliasing can also be performed in the post-processing stage, generally at
|
||||
* lower cost. See the FXAA option in {@link #setAntiAliasing}.
|
||||
* </p>
|
||||
*
|
||||
* @param count number of samples to use for multi-sampled anti-aliasing.
|
||||
*/
|
||||
public void setSampleCount(int count) {
|
||||
nSetSampleCount(getNativeObject(), count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the effective MSAA sample count.
|
||||
*
|
||||
* <p>
|
||||
* A value of 0 or 1 means MSAA is disabled.
|
||||
* </p>
|
||||
*
|
||||
* @return value set by {@link #setSampleCount}
|
||||
*/
|
||||
public int getSampleCount() {
|
||||
return nGetSampleCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables anti-aliasing in the post-processing stage. Enabled by default.
|
||||
*
|
||||
* <p>
|
||||
* For MSAA anti-aliasing, see {@link #setSampleCount}.
|
||||
* </p>
|
||||
*
|
||||
* @param type FXAA for enabling, NONE for disabling anti-aliasing.
|
||||
*/
|
||||
public void setAntiAliasing(@NonNull AntiAliasing type) {
|
||||
nSetAntiAliasing(getNativeObject(), type.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether anti-aliasing is enabled during the post-processing stage. To query
|
||||
* whether MSAA is enabled, see {@link #getSampleCount}.
|
||||
*
|
||||
* @return The post-processing anti-aliasing method.
|
||||
*/
|
||||
@NonNull
|
||||
public AntiAliasing getAntiAliasing() {
|
||||
return AntiAliasing.values()[nGetAntiAliasing(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables tone-mapping in the post-processing stage. Enabled by default.
|
||||
*
|
||||
* @param type Tone-mapping function.
|
||||
*/
|
||||
public void setToneMapping(@NonNull ToneMapping type) {
|
||||
nSetToneMapping(getNativeObject(), type.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tone-mapping function.
|
||||
* @return tone-mapping function.
|
||||
*/
|
||||
@NonNull
|
||||
public ToneMapping getToneMapping() {
|
||||
return ToneMapping.values()[nGetToneMapping(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables dithering in the post-processing stage. Enabled by default.
|
||||
*
|
||||
* @param dithering dithering type
|
||||
*/
|
||||
public void setDithering(@NonNull Dithering dithering) {
|
||||
nSetDithering(getNativeObject(), dithering.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries whether dithering is enabled during the post-processing stage.
|
||||
*
|
||||
* @return the current dithering type for this view.
|
||||
*/
|
||||
@NonNull
|
||||
public Dithering getDithering() {
|
||||
return Dithering.values()[nGetDithering(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dynamic resolution options for this view.
|
||||
*
|
||||
* <p>
|
||||
* Dynamic resolution options controls whether dynamic resolution is enabled, and if it is,
|
||||
* how it behaves.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If you wish subsequent changes to take effect please call this method again in order to
|
||||
* propagate the changes down to the native layer.
|
||||
* </p>
|
||||
*
|
||||
* @param options The dynamic resolution options to use on this view
|
||||
*/
|
||||
public void setDynamicResolutionOptions(@NonNull DynamicResolutionOptions options) {
|
||||
mDynamicResolution = options;
|
||||
nSetDynamicResolutionOptions(getNativeObject(),
|
||||
@@ -225,6 +573,10 @@ public class View {
|
||||
options.history);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dynamic resolution options associated with this view.
|
||||
* @return value set by {@link #setDynamicResolutionOptions}.
|
||||
*/
|
||||
@NonNull
|
||||
public DynamicResolutionOptions getDynamicResolutionOptions() {
|
||||
if (mDynamicResolution == null) {
|
||||
@@ -233,11 +585,20 @@ public class View {
|
||||
return mDynamicResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rendering quality for this view (e.g. color precision).
|
||||
*
|
||||
* @param renderQuality The render quality to use on this view
|
||||
*/
|
||||
public void setRenderQuality(@NonNull RenderQuality renderQuality) {
|
||||
mRenderQuality = renderQuality;
|
||||
nSetRenderQuality(getNativeObject(), renderQuality.hdrColorBuffer.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the render quality used by this view.
|
||||
* @return value set by {@link #setRenderQuality}.
|
||||
*/
|
||||
@NonNull
|
||||
public RenderQuality getRenderQuality() {
|
||||
if (mRenderQuality == null) {
|
||||
@@ -246,50 +607,168 @@ public class View {
|
||||
return mRenderQuality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this view is rendered with a depth-only prepass.
|
||||
*
|
||||
* @return the value set by {@link #setDepthPrepass}.
|
||||
*/
|
||||
@NonNull
|
||||
public DepthPrepass getDepthPrepass() {
|
||||
return mDepthPrepass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this view is rendered with or without a depth pre-pass.
|
||||
*
|
||||
* <p>
|
||||
* By default, the system picks the most appropriate strategy for your platform; this method
|
||||
* lets you override that strategy.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* When the depth pre-pass is enabled, the renderer will first draw all objects in the
|
||||
* depth buffer from front to back, and then draw the objects again but sorted to minimize
|
||||
* state changes. With the depth pre-pass disabled, objects are drawn only once, but it may
|
||||
* result in more state changes or more overdraw.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The best strategy may depend on the scene and/or GPU.
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>DepthPrepass::DEFAULT uses the most appropriate strategy</li>
|
||||
* <li>DepthPrepass::DISABLED disables the depth pre-pass</li>
|
||||
* <li>DepthPrepass::ENABLE enables the depth pre-pass</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void setDepthPrepass(@NonNull DepthPrepass depthPrepass) {
|
||||
mDepthPrepass = depthPrepass;
|
||||
nSetDepthPrepass(getNativeObject(), depthPrepass.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if post-processing is enabled.
|
||||
*
|
||||
* @see #setPostProcessingEnabled
|
||||
*/
|
||||
public boolean isPostProcessingEnabled() {
|
||||
return nIsPostProcessingEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables post processing. Enabled by default.
|
||||
*
|
||||
* <p>Post-processing includes:</p>
|
||||
* <ul>
|
||||
* <li>Tone-mapping & gamma encoding</li>
|
||||
* <li>Dithering</li>
|
||||
* <li>MSAA</li>
|
||||
* <li>FXAA</li>
|
||||
* <li>Dynamic scaling</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Disabling post-processing forgoes color correctness as well as anti-aliasing and
|
||||
* should only be used experimentally (e.g., for UI overlays).
|
||||
* </p>
|
||||
*
|
||||
* @param enabled true enables post processing, false disables it
|
||||
*
|
||||
* @see #setToneMapping
|
||||
* @see #setAntiAliasing
|
||||
* @see #setDithering
|
||||
* @see #setSampleCount
|
||||
*/
|
||||
public void setPostProcessingEnabled(boolean enabled) {
|
||||
nSetPostProcessingEnabled(getNativeObject(), enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if post-processing is enabled.
|
||||
*
|
||||
* @see #setPostProcessingEnabled
|
||||
*/
|
||||
public boolean isFrontFaceWindingInverted() {
|
||||
return nIsFrontFaceWindingInverted(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts the winding order of front faces. By default front faces use a counter-clockwise
|
||||
* winding order. When the winding order is inverted, front faces are faces with a clockwise
|
||||
* winding order.
|
||||
*
|
||||
* Changing the winding order will directly affect the culling mode in materials
|
||||
* (see Material#getCullingMode).
|
||||
*
|
||||
* Inverting the winding order of front faces is useful when rendering mirrored reflections
|
||||
* (water, mirror surfaces, front camera in AR, etc.).
|
||||
*
|
||||
* @param inverted True to invert front faces, false otherwise.
|
||||
*/
|
||||
public void setFrontFaceWindingInverted(boolean inverted) {
|
||||
nSetFrontFaceWindingInverted(getNativeObject(), inverted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets options relative to dynamic lighting for this view.
|
||||
*
|
||||
* <p>
|
||||
* Together <code>zLightNear</code> and <code>zLightFar</code> must be chosen so that the
|
||||
* visible influence of lights is spread between these two values.
|
||||
* </p>
|
||||
*
|
||||
* @param zLightNear Distance from the camera where the lights are expected to shine.
|
||||
* This parameter can affect performance and is useful because depending
|
||||
* on the scene, lights that shine close to the camera may not be
|
||||
* visible -- in this case, using a larger value can improve performance.
|
||||
* e.g. when standing and looking straight, several meters of the ground
|
||||
* isn't visible and if lights are expected to shine there, there is no
|
||||
* point using a short zLightNear. (Default 5m).
|
||||
*
|
||||
* @param zLightFar Distance from the camera after which lights are not expected to be visible.
|
||||
* Similarly to zLightNear, setting this value properly can improve
|
||||
* performance. (Default 100m).
|
||||
*
|
||||
*/
|
||||
public void setDynamicLightingOptions(float zLightNear, float zLightFar) {
|
||||
nSetDynamicLightingOptions(getNativeObject(), zLightNear, zLightFar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates ambient occlusion.
|
||||
*
|
||||
* @param ao Type of ambient occlusion to use.
|
||||
*/
|
||||
public void setAmbientOcclusion(@NonNull AmbientOcclusion ao) {
|
||||
nSetAmbientOcclusion(getNativeObject(), ao.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the type of ambient occlusion active for this View.
|
||||
*
|
||||
* @return ambient occlusion type.
|
||||
*/
|
||||
@NonNull
|
||||
public AmbientOcclusion getAmbientOcclusion() {
|
||||
return AmbientOcclusion.values()[nGetAmbientOcclusion(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ambient occlusion options.
|
||||
*
|
||||
* @param options Options for ambient occlusion.
|
||||
*/
|
||||
public void setAmbientOcclusionOptions(@NonNull AmbientOcclusionOptions options) {
|
||||
mAmbientOcclusionOptions = options;
|
||||
nSetAmbientOcclusionOptions(getNativeObject(), options.radius, options.bias, options.power, options.resolution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ambient occlusion options.
|
||||
*
|
||||
* @return ambient occlusion options currently set.
|
||||
*/
|
||||
@NonNull
|
||||
public AmbientOcclusionOptions getAmbientOcclusionOptions() {
|
||||
if (mAmbientOcclusionOptions == null) {
|
||||
|
||||
@@ -18,6 +18,16 @@ package com.google.android.filament;
|
||||
|
||||
import android.support.annotation.IntRange;
|
||||
|
||||
/**
|
||||
* Specifies a rectangular region within a render target in terms of pixel coordinates.
|
||||
*
|
||||
* <p>
|
||||
* The rectangle spans from <code>(left,bottom)</code> to <code>(left+width-1, top+height-1)</code>,
|
||||
* inclusive. Width and height must be non-negative.
|
||||
* </p>
|
||||
*
|
||||
* @see View#setViewport
|
||||
*/
|
||||
public class Viewport {
|
||||
public Viewport(int left, int bottom, @IntRange(from = 0) int width, @IntRange(from = 0) int height) {
|
||||
this.left = left;
|
||||
|
||||
@@ -34,21 +34,6 @@ public final class TextureHelper {
|
||||
private static final int BITMAP_CONFIG_RGBA_F16 = 4;
|
||||
private static final int BITMAP_CONFIG_HARDWARE = 5;
|
||||
|
||||
private static Method sEngineGetNativeObject;
|
||||
private static Method sTextureGetNativeObject;
|
||||
|
||||
static {
|
||||
try {
|
||||
sEngineGetNativeObject = Engine.class.getDeclaredMethod("getNativeObject");
|
||||
sTextureGetNativeObject = Texture.class.getDeclaredMethod("getNativeObject");
|
||||
|
||||
sEngineGetNativeObject.setAccessible(true);
|
||||
sTextureGetNativeObject.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
|
||||
private TextureHelper() {
|
||||
}
|
||||
|
||||
@@ -69,14 +54,10 @@ public final class TextureHelper {
|
||||
throw new IllegalArgumentException("Unsupported config: ARGB_4444 or HARDWARE");
|
||||
}
|
||||
|
||||
try {
|
||||
long nativeTexture = (Long) sTextureGetNativeObject.invoke(texture);
|
||||
long nativeEngine = (Long) sEngineGetNativeObject.invoke(engine);
|
||||
nSetBitmap(nativeTexture, nativeEngine, level, xoffset, yoffset, width, height,
|
||||
bitmap, format);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
long nativeTexture = texture.getNativeObject();
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
nSetBitmap(nativeTexture, nativeEngine, level, xoffset, yoffset, width, height,
|
||||
bitmap, format);
|
||||
}
|
||||
|
||||
private static int toNativeFormat(Bitmap.Config config) {
|
||||
|
||||
@@ -99,10 +99,6 @@ import com.google.android.filament.SwapChain;
|
||||
* // Always detach the surface before destroying the engine
|
||||
* mUiHelper.detach();
|
||||
*
|
||||
* // This ensures that all the commands we've sent to Filament have
|
||||
* // been processed before we attempt to destroy anything
|
||||
* Fence.waitAndDestroy(mEngine.createFence(Fence.Type.SOFT), Fence.Mode.FLUSH);
|
||||
*
|
||||
* mEngine.destroy();
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -26,16 +26,14 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* Note that adding this annotation to a method is not enough to guarantee that
|
||||
* it is kept - either its class must be referenced elsewhere in the program, or
|
||||
* the class must be annotated with this as well.
|
||||
* the class must be annotated with this as well. Usage example:
|
||||
* <pre>
|
||||
*
|
||||
* Usage example:<br />
|
||||
* {@code
|
||||
* @UsedByNative("NativeCrashHandler.cpp")
|
||||
public static void reportCrash(int signal, int code, int address) {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
* @UsedByNative("NativeCrashHandler.cpp")
|
||||
* public static void reportCrash(int signal, int code, int address) {
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Target({
|
||||
ElementType.METHOD,
|
||||
|
||||
@@ -26,16 +26,14 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* Note that adding this annotation to a method is not enough to guarantee that
|
||||
* it is kept - either its class must be referenced elsewhere in the program, or
|
||||
* the class must be annotated with this as well.
|
||||
* the class must be annotated with this as well. Usage example:
|
||||
* <pre>
|
||||
*
|
||||
* Usage example:<br />
|
||||
* {@code
|
||||
* @UsedByReflection("PeopleListItemView.java")
|
||||
public PeopleListItemViewV11(Context context) {
|
||||
super(context);
|
||||
}
|
||||
}
|
||||
|
||||
* @UsedByReflection("PeopleListItemView.java")
|
||||
* public PeopleListItemViewV11(Context context) {
|
||||
* super(context);
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Target({
|
||||
ElementType.METHOD,
|
||||
|
||||
@@ -2,19 +2,22 @@ cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
||||
|
||||
add_library(filament SHARED IMPORTED)
|
||||
set(DISABLE_FILAMENT_JNI TRUE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../filament-android ${CMAKE_CURRENT_BINARY_DIR}/filament-android)
|
||||
|
||||
add_library(filament STATIC IMPORTED)
|
||||
set_target_properties(filament PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament.a)
|
||||
|
||||
add_library(backend SHARED IMPORTED)
|
||||
add_library(backend STATIC IMPORTED)
|
||||
set_target_properties(backend PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbackend.a)
|
||||
|
||||
add_library(utils SHARED IMPORTED)
|
||||
add_library(utils STATIC IMPORTED)
|
||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||
|
||||
add_library(filaflat SHARED IMPORTED)
|
||||
add_library(filaflat STATIC IMPORTED)
|
||||
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
|
||||
|
||||
@@ -26,27 +29,27 @@ add_library(ibl STATIC IMPORTED)
|
||||
set_target_properties(ibl PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libibl.a)
|
||||
|
||||
add_library(geometry SHARED IMPORTED)
|
||||
add_library(geometry STATIC IMPORTED)
|
||||
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
|
||||
|
||||
add_library(filabridge SHARED IMPORTED)
|
||||
add_library(filabridge STATIC IMPORTED)
|
||||
set_target_properties(filabridge PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilabridge.a)
|
||||
|
||||
add_library(gltfio SHARED IMPORTED)
|
||||
add_library(gltfio STATIC IMPORTED)
|
||||
set_target_properties(gltfio PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_core.a)
|
||||
|
||||
add_library(gltfio_resources SHARED IMPORTED)
|
||||
add_library(gltfio_resources STATIC IMPORTED)
|
||||
set_target_properties(gltfio_resources PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_resources.a)
|
||||
|
||||
add_library(bluevk SHARED IMPORTED)
|
||||
add_library(bluevk STATIC IMPORTED)
|
||||
set_target_properties(bluevk PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbluevk.a)
|
||||
|
||||
add_library(smol-v SHARED IMPORTED)
|
||||
add_library(smol-v STATIC IMPORTED)
|
||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||
|
||||
@@ -54,25 +57,20 @@ include_directories(${FILAMENT_DIR}/include
|
||||
..
|
||||
../../libs/utils/include)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-stack-protector")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -ffp-contract=fast")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-inlines-hidden")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility=hidden")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ffunction-sections -fdata-sections")
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS " ${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS " ${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic-functions")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libgltfio-jni.map")
|
||||
|
||||
add_library(gltfio-jni SHARED
|
||||
src/main/cpp/Animator.cpp
|
||||
src/main/cpp/AssetLoader.cpp
|
||||
src/main/cpp/FilamentAsset.cpp
|
||||
src/main/cpp/KtxLoader.cpp
|
||||
src/main/cpp/MaterialProvider.cpp
|
||||
src/main/cpp/ResourceLoader.cpp
|
||||
|
||||
../common/CallbackUtils.cpp
|
||||
../common/NioUtils.cpp
|
||||
|
||||
$<TARGET_OBJECTS:filament-jni-obj>
|
||||
)
|
||||
|
||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
|
||||
@@ -80,21 +78,22 @@ set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
|
||||
|
||||
# The ordering in the following list is important because CMake does not have dependency information.
|
||||
target_link_libraries(gltfio-jni
|
||||
android
|
||||
gltfio
|
||||
gltfio_resources
|
||||
filament
|
||||
filabridge
|
||||
backend
|
||||
filaflat
|
||||
filabridge
|
||||
geometry
|
||||
image
|
||||
ibl
|
||||
utils
|
||||
log
|
||||
GLESv3
|
||||
EGL
|
||||
android
|
||||
jnigraphics
|
||||
gltfio_resources
|
||||
m
|
||||
log
|
||||
)
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
|
||||
59
android/gltfio-android/src/main/cpp/Animator.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nApplyAnimation(JNIEnv*, jclass, jlong nativeAnimator,
|
||||
jint index, jfloat time) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
animator->applyAnimation(index, time);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
animator->updateBoneMatrices();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nGetAnimationCount(JNIEnv*, jclass, jlong nativeAnimator) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
return animator->getAnimationCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT float JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nGetAnimationDuration(JNIEnv*, jclass,
|
||||
jlong nativeAnimator, jint index) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
return animator->getAnimationDuration(index);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nGetAnimationName(JNIEnv* env, jclass,
|
||||
jlong nativeAnimator, jint index) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
const char* val = animator->getAnimationName(index);
|
||||
return val ? env->NewStringUTF(val) : nullptr;
|
||||
|
||||
}
|
||||
@@ -71,3 +71,10 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetName(JNIEnv* env, jcla
|
||||
const char* val = asset->getName(*entity);
|
||||
return val ? env->NewStringUTF(val) : nullptr;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_gltfio_FilamentAsset_nGetAnimator(JNIEnv* env, jclass,
|
||||
jlong nativeAsset) {
|
||||
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
|
||||
return (jlong) asset->getAnimator();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.gltfio;
|
||||
|
||||
import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Updates matrices according to glTF <code>animation</code> and <code>skin</code> definitions.
|
||||
*
|
||||
* <p>Animator can be used for two things:
|
||||
* <ul>
|
||||
* <li>Updating matrices in <code>TransformManager</code> components according to glTF <code>animation</code> definitions.</li>
|
||||
* <li>Updating bone matrices in <code>RenderableManager</code> components according to glTF <code>skin</code> definitions.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @see AssetLoader
|
||||
* @see FilamentAsset
|
||||
* @see ResourceLoader
|
||||
*/
|
||||
public class Animator {
|
||||
private long mNativeObject;
|
||||
|
||||
Animator(long nativeObject) {
|
||||
mNativeObject = nativeObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies rotation, translation, and scale to entities that have been targeted by the given
|
||||
* animation definition. Uses <code>TransformManager</code>.
|
||||
*
|
||||
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
|
||||
* @param time Elapsed time of interest in seconds.
|
||||
*
|
||||
* @see #getAnimationCount
|
||||
*/
|
||||
public void applyAnimation(@IntRange(from = 0) int animationIndex, float time) {
|
||||
nApplyAnimation(mNativeObject, animationIndex, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes root-to-node transforms for all bone nodes, then passes
|
||||
* the results into {@see RenderableManager#setBones}.
|
||||
* Uses <code>TransformManager</code> and <code>RenderableManager</code>.
|
||||
*
|
||||
* <p>NOTE: this operation is independent of <code>animation</code>.</p>
|
||||
*/
|
||||
public void updateBoneMatrices() {
|
||||
nUpdateBoneMatrices(mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of <code>animation</code> definitions in the glTF asset.
|
||||
*/
|
||||
public int getAnimationCount() {
|
||||
return nGetAnimationCount(mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the specified glTF <code>animation</code> in seconds.
|
||||
*
|
||||
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
|
||||
*
|
||||
* @see #getAnimationCount
|
||||
* */
|
||||
public float getAnimationDuration(@IntRange(from = 0) int animationIndex) {
|
||||
return nGetAnimationDuration(mNativeObject, animationIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a weak reference to the string name of the specified <code>animation</code>, or an
|
||||
* empty string if none was specified.
|
||||
*
|
||||
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
|
||||
*
|
||||
* @see #getAnimationCount
|
||||
*/
|
||||
public String getAnimationName(@IntRange(from = 0) int animationIndex) {
|
||||
return nGetAnimationName(mNativeObject, animationIndex);
|
||||
}
|
||||
|
||||
private static native void nApplyAnimation(long nativeAnimator, int index, float time);
|
||||
private static native void nUpdateBoneMatrices(long nativeAnimator);
|
||||
private static native int nGetAnimationCount(long nativeAnimator);
|
||||
private static native float nGetAnimationDuration(long nativeAnimator, int index);
|
||||
private static native String nGetAnimationName(long nativeAnimator, int index);
|
||||
}
|
||||
@@ -21,12 +21,7 @@ import android.support.annotation.Nullable;
|
||||
|
||||
import com.google.android.filament.Engine;
|
||||
import com.google.android.filament.EntityManager;
|
||||
import com.google.android.filament.IndirectLight;
|
||||
import com.google.android.filament.Skybox;
|
||||
import com.google.android.filament.Texture;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.Buffer;
|
||||
|
||||
/**
|
||||
@@ -60,45 +55,24 @@ import java.nio.Buffer;
|
||||
* }
|
||||
*
|
||||
* ResourceLoader(engine).loadResources(filamentAsset).destroy()
|
||||
* animator = asset.getAnimator()
|
||||
*
|
||||
* scene.addEntities(filamentAsset.entities)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see Animator
|
||||
* @see FilamentAsset
|
||||
* @see ResourceLoader
|
||||
*/
|
||||
public class AssetLoader {
|
||||
private long mNativeObject;
|
||||
|
||||
static Method sEngineGetNativeObject;
|
||||
static Method sEntityManagerGetNativeObject;
|
||||
static Constructor<Texture> sTextureConstructor;
|
||||
static Constructor<IndirectLight> sIndirectLightConstructor;
|
||||
static Constructor<Skybox> sSkyboxConstructor;
|
||||
|
||||
/**
|
||||
* Initializes the gltfio JNI layer. Must be called before using any gltfio functionality.
|
||||
*/
|
||||
public static void init() {
|
||||
System.loadLibrary("gltfio-jni");
|
||||
try {
|
||||
sEngineGetNativeObject = Engine.class.getDeclaredMethod("getNativeObject");
|
||||
sEngineGetNativeObject.setAccessible(true);
|
||||
|
||||
sEntityManagerGetNativeObject = EntityManager.class.getDeclaredMethod("getNativeObject");
|
||||
sEntityManagerGetNativeObject.setAccessible(true);
|
||||
|
||||
sTextureConstructor = Texture.class.getDeclaredConstructor(long.class);
|
||||
sTextureConstructor.setAccessible(true);
|
||||
|
||||
sIndirectLightConstructor = IndirectLight.class.getDeclaredConstructor(long.class);
|
||||
sIndirectLightConstructor.setAccessible(true);
|
||||
|
||||
sSkyboxConstructor = Skybox.class.getDeclaredConstructor(long.class);
|
||||
sSkyboxConstructor.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,14 +85,12 @@ public class AssetLoader {
|
||||
*/
|
||||
public AssetLoader(@NonNull Engine engine, @NonNull MaterialProvider generator,
|
||||
@NonNull EntityManager entities) {
|
||||
try {
|
||||
long nativeEngine = (long) sEngineGetNativeObject.invoke(engine);
|
||||
long nativeMaterials = generator.getNativeObject();
|
||||
long nativeEntities = (long) sEntityManagerGetNativeObject.invoke(entities);
|
||||
mNativeObject = nCreateAssetLoader(nativeEngine, nativeMaterials, nativeEntities);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
long nativeMaterials = generator.getNativeObject();
|
||||
long nativeEntities = entities.getNativeObject();
|
||||
mNativeObject = nCreateAssetLoader(nativeEngine, nativeMaterials, nativeEntities);
|
||||
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Unable to parse glTF asset.");
|
||||
}
|
||||
|
||||
@@ -37,16 +37,17 @@ import com.google.android.filament.Entity;
|
||||
* <p>Clients can use {@link ResourceLoader} to create textures, compute tangent quaternions, and
|
||||
* upload data into vertex buffers and index buffers.</p>
|
||||
*
|
||||
* <p>TODO: <code>Animator</code> is not yet exposed to Java / Kotlin clients.</p>
|
||||
*
|
||||
* @see ResourceLoader
|
||||
* @see Animator
|
||||
* @see AssetLoader
|
||||
*/
|
||||
public class FilamentAsset {
|
||||
private long mNativeObject;
|
||||
private Animator mAnimator;
|
||||
|
||||
FilamentAsset(long nativeObject) {
|
||||
mNativeObject = nativeObject;
|
||||
mAnimator = null;
|
||||
}
|
||||
|
||||
long getNativeObject() {
|
||||
@@ -82,12 +83,26 @@ public class FilamentAsset {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>NameComponentManager<?code> label for the given entity, if it exists.
|
||||
* Gets the <code>NameComponentManager</code> label for the given entity, if it exists.
|
||||
*/
|
||||
public String getName(@Entity int entity) {
|
||||
return nGetName(getNativeObject(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or retrieves the <code>Animator</code> for this asset.
|
||||
*
|
||||
* <p>When calling this for the first time, this must be called after
|
||||
* {@see ResourceLoader#loadResources}.</p>
|
||||
*/
|
||||
public Animator getAnimator() {
|
||||
if (mAnimator != null) {
|
||||
return mAnimator;
|
||||
}
|
||||
mAnimator = new Animator(nGetAnimator(getNativeObject()));
|
||||
return mAnimator;
|
||||
}
|
||||
|
||||
void clearNativeObject() {
|
||||
mNativeObject = 0;
|
||||
}
|
||||
@@ -97,4 +112,5 @@ public class FilamentAsset {
|
||||
private static native void nGetEntities(long nativeAsset, int[] result);
|
||||
private static native void nGetBoundingBox(long nativeAsset, float[] box);
|
||||
private static native String nGetName(long nativeAsset, int entity);
|
||||
private static native long nGetAnimator(long nativeAsset);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.google.android.filament.IndirectLight;
|
||||
import com.google.android.filament.Skybox;
|
||||
import com.google.android.filament.Texture;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.Buffer;
|
||||
|
||||
/**
|
||||
@@ -33,6 +35,24 @@ import java.nio.Buffer;
|
||||
* into a single file.</p>
|
||||
*/
|
||||
public class KtxLoader {
|
||||
private static Constructor<Texture> sTextureConstructor;
|
||||
private static Constructor<IndirectLight> sIndirectLightConstructor;
|
||||
private static Constructor<Skybox> sSkyboxConstructor;
|
||||
|
||||
static {
|
||||
try {
|
||||
sTextureConstructor = Texture.class.getDeclaredConstructor(long.class);
|
||||
sTextureConstructor.setAccessible(true);
|
||||
|
||||
sIndirectLightConstructor = IndirectLight.class.getDeclaredConstructor(long.class);
|
||||
sIndirectLightConstructor.setAccessible(true);
|
||||
|
||||
sSkyboxConstructor = Skybox.class.getDeclaredConstructor(long.class);
|
||||
sSkyboxConstructor.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
|
||||
public static class Options {
|
||||
public boolean srgb;
|
||||
@@ -49,9 +69,9 @@ public class KtxLoader {
|
||||
@Nullable
|
||||
public static Texture createTexture(@NonNull Engine engine, @NonNull Buffer buffer, @NonNull Options options) {
|
||||
try {
|
||||
long nativeEngine = (long) AssetLoader.sEngineGetNativeObject.invoke(engine);
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
long nativeTexture = nCreateTexture(nativeEngine, buffer, buffer.remaining(), options.srgb);
|
||||
return AssetLoader.sTextureConstructor.newInstance(nativeTexture);
|
||||
return sTextureConstructor.newInstance(nativeTexture);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
@@ -68,9 +88,9 @@ public class KtxLoader {
|
||||
@Nullable
|
||||
public static IndirectLight createIndirectLight(@NonNull Engine engine, @NonNull Buffer buffer, @NonNull Options options) {
|
||||
try {
|
||||
long nativeEngine = (long) AssetLoader.sEngineGetNativeObject.invoke(engine);
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
long nativeIndirectLight = nCreateIndirectLight(nativeEngine, buffer, buffer.remaining(), options.srgb);
|
||||
return AssetLoader.sIndirectLightConstructor.newInstance(nativeIndirectLight);
|
||||
return sIndirectLightConstructor.newInstance(nativeIndirectLight);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
@@ -87,9 +107,9 @@ public class KtxLoader {
|
||||
@Nullable
|
||||
public static Skybox createSkybox(@NonNull Engine engine, @NonNull Buffer buffer, @NonNull Options options) {
|
||||
try {
|
||||
long nativeEngine = (long) AssetLoader.sEngineGetNativeObject.invoke(engine);
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
long nativeSkybox = nCreateSkybox(nativeEngine, buffer, buffer.remaining(), options.srgb);
|
||||
return AssetLoader.sSkyboxConstructor.newInstance(nativeSkybox);
|
||||
return sSkyboxConstructor.newInstance(nativeSkybox);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -29,29 +29,14 @@ import java.lang.reflect.Method;
|
||||
public class MaterialProvider {
|
||||
private long mNativeObject;
|
||||
|
||||
private static Method sEngineGetNativeObject;
|
||||
|
||||
static {
|
||||
try {
|
||||
sEngineGetNativeObject = Engine.class.getDeclaredMethod("getNativeObject");
|
||||
sEngineGetNativeObject.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an ubershader loader using the supplied {@link Engine}.
|
||||
*
|
||||
* @param engine the engine used to create materials
|
||||
*/
|
||||
public MaterialProvider(Engine engine) {
|
||||
try {
|
||||
long nativeEngine = (long) sEngineGetNativeObject.invoke(engine);
|
||||
mNativeObject = nCreateMaterialProvider(nativeEngine);
|
||||
} catch (Exception e) {
|
||||
// Ignored
|
||||
}
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
mNativeObject = nCreateMaterialProvider(nativeEngine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,17 +36,6 @@ import java.nio.Buffer;
|
||||
public class ResourceLoader {
|
||||
private final long mNativeObject;
|
||||
|
||||
private static Method sEngineGetNativeObject;
|
||||
|
||||
static {
|
||||
try {
|
||||
sEngineGetNativeObject = Engine.class.getDeclaredMethod("getNativeObject");
|
||||
sEngineGetNativeObject.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Cannot happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a resource loader tied to the given Filament engine.
|
||||
*
|
||||
@@ -54,8 +43,8 @@ public class ResourceLoader {
|
||||
* @throws IllegalAccessException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
public ResourceLoader(@NonNull Engine engine) throws IllegalAccessException, InvocationTargetException {
|
||||
long nativeEngine = (long) sEngineGetNativeObject.invoke(engine);
|
||||
public ResourceLoader(@NonNull Engine engine) {
|
||||
long nativeEngine = engine.getNativeObject();
|
||||
mNativeObject = nCreateResourceLoader(nativeEngine);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,12 @@ Demonstrates how to load glTF models and render to an offscreen buffer:
|
||||
|
||||

|
||||
|
||||
### `hello-camera`
|
||||
|
||||
Demonstrates how to use `Stream` with Android's Camera2 API:
|
||||
|
||||

|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start, make sure to read [Filament's README](../../README.md). You need to be able to
|
||||
|
||||
@@ -43,10 +43,9 @@ data class Framebuffer(
|
||||
|
||||
class MainActivity : Activity() {
|
||||
|
||||
// Be sure to initialize not only Filament, but also gltfio (via AssetLoader)
|
||||
// We are using the gltfio library, so init the AssetLoader rather than Filament.
|
||||
companion object {
|
||||
init {
|
||||
Filament.init()
|
||||
AssetLoader.init()
|
||||
}
|
||||
}
|
||||
@@ -155,7 +154,7 @@ class MainActivity : Activity() {
|
||||
// IndirectLight and SkyBox
|
||||
// ------------------------
|
||||
|
||||
val ibl = "venetian_crossroads_2k";
|
||||
val ibl = "venetian_crossroads_2k"
|
||||
|
||||
readUncompressedAsset("envs/$ibl/${ibl}_ibl.ktx").let {
|
||||
primary.scene.indirectLight = KtxLoader.createIndirectLight(engine, it, KtxLoader.Options())
|
||||
@@ -209,7 +208,7 @@ class MainActivity : Activity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Punctual Light Sources
|
||||
// Light Sources
|
||||
// ----------------------
|
||||
|
||||
light = EntityManager.get().create()
|
||||
@@ -236,12 +235,19 @@ class MainActivity : Activity() {
|
||||
|
||||
tm.setTransform(tm.getInstance(filamentAsset.root),
|
||||
floatArrayOf(
|
||||
cos(v), 0.0f, -sin(v), 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
sin(v), 0.0f, cos(v), 0.0f,
|
||||
0.0f, -1.7f, 0.0f, 1.0f
|
||||
cos(v), 0.0f, -sin(v), 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
sin(v), 0.0f, cos(v), 0.0f,
|
||||
0.0f, -1.7f, 0.0f, 1.0f
|
||||
))
|
||||
|
||||
|
||||
// The lucy asset does not have animation but we invoke the asset animator for demonstration purposes.
|
||||
if (filamentAsset.animator.animationCount > 0) {
|
||||
val elapsedTimeInSeconds = a.currentPlayTime.toFloat() / 1000.0f
|
||||
filamentAsset.animator.applyAnimation(0, elapsedTimeInSeconds)
|
||||
filamentAsset.animator.updateBoneMatrices()
|
||||
}
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
@@ -429,15 +435,11 @@ class MainActivity : Activity() {
|
||||
|
||||
// Stop the animation and any pending frame
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel();
|
||||
animator.cancel()
|
||||
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
assetLoader.destroyAsset(filamentAsset)
|
||||
assetLoader.destroy()
|
||||
|
||||
|
||||
12
android/samples/hello-camera/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
/.idea/caches
|
||||
/.idea/gradle.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
/app/src/main/assets/materials/*.filamat
|
||||
.externalNativeBuild
|
||||
1
android/samples/hello-camera/app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
101
android/samples/hello-camera/app/build.gradle
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
apply from: '../../../build/filament-tasks.gradle'
|
||||
|
||||
compileMaterials {
|
||||
group 'Filament'
|
||||
description 'Compile materials'
|
||||
|
||||
inputDir = file("src/main/materials")
|
||||
outputDir = file("src/main/assets/materials")
|
||||
}
|
||||
|
||||
preBuild.dependsOn compileMaterials
|
||||
|
||||
clean.doFirst {
|
||||
delete "src/main/assets"
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.hellocam"
|
||||
minSdkVersion 23 // 21 is required for CameraDevice.StateCallback, 23 is required for shouldShowRequestPermissionRationale
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
// Filament comes with native code, the following declarations
|
||||
// can be used to generate architecture specific APKs
|
||||
flavorDimensions 'cpuArch'
|
||||
productFlavors {
|
||||
arm8 {
|
||||
dimension 'cpuArch'
|
||||
ndk {
|
||||
abiFilters 'arm64-v8a'
|
||||
}
|
||||
}
|
||||
arm7 {
|
||||
dimension 'cpuArch'
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a'
|
||||
}
|
||||
}
|
||||
x86_64 {
|
||||
dimension 'cpuArch'
|
||||
ndk {
|
||||
abiFilters 'x86_64'
|
||||
}
|
||||
}
|
||||
x86 {
|
||||
dimension 'cpuArch'
|
||||
ndk {
|
||||
abiFilters 'x86'
|
||||
}
|
||||
}
|
||||
universal {
|
||||
dimension 'cpuArch'
|
||||
}
|
||||
}
|
||||
|
||||
// We use the .filamat extension for materials compiled with matc
|
||||
// Telling aapt to not compress them allows to load them efficiently
|
||||
aaptOptions {
|
||||
noCompress 'filamat'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
// Depend on Filament
|
||||
implementation 'com.google.android.filament:filament-android'
|
||||
implementation 'com.android.support:support-compat:28.0.0'
|
||||
}
|
||||
21
android/samples/hello-camera/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.hellocam">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.hellocam
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.hardware.camera2.*
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.Log
|
||||
import android.util.Size
|
||||
import android.view.Surface
|
||||
|
||||
import android.Manifest
|
||||
import android.opengl.Matrix
|
||||
import android.view.Display
|
||||
|
||||
import com.google.android.filament.*
|
||||
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Toy class that handles all interaction with the Android camera2 API.
|
||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
||||
*/
|
||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance, private val display: Display) {
|
||||
private lateinit var cameraId: String
|
||||
private lateinit var captureRequest: CaptureRequest
|
||||
|
||||
private val cameraOpenCloseLock = Semaphore(1)
|
||||
private var backgroundHandler: Handler? = null
|
||||
private var backgroundThread: HandlerThread? = null
|
||||
private var cameraDevice: CameraDevice? = null
|
||||
private var captureSession: CameraCaptureSession? = null
|
||||
private var resolution = Size(640, 480)
|
||||
private var filamentTexture: Texture? = null
|
||||
private var filamentStream: Stream? = null
|
||||
private var surfaceTexture: SurfaceTexture? = null
|
||||
|
||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
this@CameraHelper.cameraDevice = cameraDevice
|
||||
createCaptureSession()
|
||||
}
|
||||
override fun onDisconnected(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
cameraDevice.close()
|
||||
this@CameraHelper.cameraDevice = null
|
||||
}
|
||||
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
||||
onDisconnected(cameraDevice)
|
||||
this@CameraHelper.activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the front-facing Android camera, requests permission, and sets up a listener that will
|
||||
* start a capture session as soon as the camera is ready.
|
||||
*/
|
||||
fun openCamera() {
|
||||
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
try {
|
||||
for (cameraId in manager.cameraIdList) {
|
||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
||||
val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
|
||||
continue
|
||||
}
|
||||
|
||||
this.cameraId = cameraId
|
||||
Log.i(kLogTag, "Selected camera $cameraId.")
|
||||
|
||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
|
||||
resolution = map.getOutputSizes(SurfaceTexture::class.java)[0]
|
||||
Log.i(kLogTag, "Highest resolution is $resolution.")
|
||||
}
|
||||
} catch (e: CameraAccessException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
} catch (e: NullPointerException) {
|
||||
Log.e(kLogTag, "Camera2 API is not supported on this device.")
|
||||
}
|
||||
|
||||
val permission = ContextCompat.checkSelfPermission(this.activity, Manifest.permission.CAMERA)
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), kRequestCameraPermission)
|
||||
return
|
||||
}
|
||||
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
||||
throw RuntimeException("Time out waiting to lock camera opening.")
|
||||
}
|
||||
manager.openCamera(cameraId, cameraCallback, backgroundHandler)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
|
||||
backgroundHandler = Handler(backgroundThread?.looper!!)
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
backgroundThread?.quitSafely()
|
||||
try {
|
||||
backgroundThread?.join()
|
||||
backgroundThread = null
|
||||
backgroundHandler = null
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
||||
if (requestCode == kRequestCameraPermission) {
|
||||
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.e(kLogTag, "Unable to obtain camera position.")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun createCaptureSession() {
|
||||
if (surfaceTexture != null) {
|
||||
surfaceTexture!!.release()
|
||||
filamentEngine.destroyStream(filamentStream!!)
|
||||
}
|
||||
|
||||
// Create the Android surface that will hold the camera image.
|
||||
surfaceTexture = SurfaceTexture(0)
|
||||
surfaceTexture!!.setDefaultBufferSize(resolution.width, resolution.height)
|
||||
surfaceTexture!!.detachFromGLContext()
|
||||
val surface = Surface(surfaceTexture)
|
||||
|
||||
// [Re]create the Filament Stream object that gets bound to the Texture.
|
||||
filamentStream = Stream.Builder()
|
||||
.stream(surfaceTexture!!)
|
||||
.build(filamentEngine)
|
||||
|
||||
// Create the Filament Texture object if we haven't done so already.
|
||||
if (filamentTexture == null) {
|
||||
filamentTexture = Texture.Builder()
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.format(Texture.InternalFormat.RGB8)
|
||||
.build(filamentEngine)
|
||||
}
|
||||
|
||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
||||
val aspectRatio = resolution.width.toFloat() / resolution.height.toFloat()
|
||||
val textureTransform = FloatArray(16)
|
||||
Matrix.setIdentityM(textureTransform, 0)
|
||||
when (display.rotation) {
|
||||
Surface.ROTATION_0 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 90.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f, 1.0f / aspectRatio, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_90 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 1.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 180.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_270 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
||||
filamentTexture!!.setExternalStream(filamentEngine, filamentStream!!)
|
||||
filamentMaterial.setParameter("videoTexture", filamentTexture!!, sampler)
|
||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
|
||||
// Start the capture session. You could also use TEMPLATE_PREVIEW here.
|
||||
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
|
||||
captureRequestBuilder.addTarget(surface)
|
||||
|
||||
cameraDevice?.createCaptureSession(listOf(surface),
|
||||
object : CameraCaptureSession.StateCallback() {
|
||||
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
|
||||
if (cameraDevice == null) return
|
||||
captureSession = cameraCaptureSession
|
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
||||
captureRequest = captureRequestBuilder.build()
|
||||
captureSession!!.setRepeatingRequest(captureRequest, null, backgroundHandler)
|
||||
Log.i(kLogTag, "Created CaptureRequest.")
|
||||
}
|
||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||
Log.e(kLogTag, "onConfigureFailed")
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val kLogTag = "CameraHelper"
|
||||
private const val kRequestCameraPermission = 1
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.hellocam
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.opengl.Matrix
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.util.Log
|
||||
import android.view.Choreographer
|
||||
import android.view.Display
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceView
|
||||
import android.view.animation.LinearInterpolator
|
||||
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.RenderableManager.*
|
||||
import com.google.android.filament.VertexBuffer.*
|
||||
import com.google.android.filament.android.UiHelper
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.channels.Channels
|
||||
|
||||
import kotlin.math.*
|
||||
|
||||
class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
companion object {
|
||||
init {
|
||||
Filament.init()
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var surfaceView: SurfaceView
|
||||
private lateinit var uiHelper: UiHelper
|
||||
private lateinit var choreographer: Choreographer
|
||||
|
||||
private lateinit var engine: Engine
|
||||
private lateinit var renderer: Renderer
|
||||
private lateinit var scene: Scene
|
||||
private lateinit var view: View
|
||||
|
||||
// This helper wraps the Android camera2 API and connects it to a Filament material.
|
||||
private lateinit var cameraHelper: CameraHelper
|
||||
|
||||
// This is the Filament camera, not the phone camera. :)
|
||||
private lateinit var camera: Camera
|
||||
|
||||
// Other Filament objects:
|
||||
private lateinit var material: Material
|
||||
private lateinit var materialInstance: MaterialInstance
|
||||
private lateinit var vertexBuffer: VertexBuffer
|
||||
private lateinit var indexBuffer: IndexBuffer
|
||||
|
||||
// Filament entity representing a renderable object
|
||||
@Entity private var renderable = 0
|
||||
@Entity private var light = 0
|
||||
|
||||
// A swap chain is Filament's representation of a surface
|
||||
private var swapChain: SwapChain? = null
|
||||
|
||||
// Performs the rendering and schedules new frames
|
||||
private val frameScheduler = FrameCallback()
|
||||
|
||||
private val animator = ValueAnimator.ofFloat(0.0f, 50.0f)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
surfaceView = SurfaceView(this)
|
||||
setContentView(surfaceView)
|
||||
|
||||
choreographer = Choreographer.getInstance()
|
||||
|
||||
setupSurfaceView()
|
||||
setupFilament()
|
||||
setupView()
|
||||
setupScene()
|
||||
|
||||
cameraHelper = CameraHelper(this, engine, materialInstance, windowManager.defaultDisplay)
|
||||
cameraHelper.openCamera()
|
||||
}
|
||||
|
||||
private fun setupSurfaceView() {
|
||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
uiHelper.attachTo(surfaceView)
|
||||
}
|
||||
|
||||
private fun setupFilament() {
|
||||
engine = Engine.create()
|
||||
renderer = engine.createRenderer()
|
||||
scene = engine.createScene()
|
||||
view = engine.createView()
|
||||
camera = engine.createCamera()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
|
||||
view.camera = camera
|
||||
view.scene = scene
|
||||
}
|
||||
|
||||
private fun setupScene() {
|
||||
loadMaterial()
|
||||
setupMaterial()
|
||||
createMesh()
|
||||
|
||||
// To create a renderable we first create a generic entity
|
||||
renderable = EntityManager.get().create()
|
||||
|
||||
// We then create a renderable component on that entity
|
||||
// A renderable is made of several primitives; in this case we declare only 1
|
||||
// If we wanted each face of the cube to have a different material, we could
|
||||
// declare 6 primitives (1 per face) and give each of them a different material
|
||||
// instance, setup with different parameters
|
||||
RenderableManager.Builder(1)
|
||||
// Overall bounding box of the renderable
|
||||
.boundingBox(Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f))
|
||||
// Sets the mesh data of the first primitive, 6 faces of 6 indices each
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vertexBuffer, indexBuffer, 0, 6 * 6)
|
||||
// Sets the material of the first primitive
|
||||
.material(0, materialInstance)
|
||||
.build(engine, renderable)
|
||||
|
||||
// Add the entity to the scene to render it
|
||||
scene.addEntity(renderable)
|
||||
|
||||
// We now need a light, let's create a directional light
|
||||
light = EntityManager.get().create()
|
||||
|
||||
// Create a color from a temperature (5,500K)
|
||||
val (r, g, b) = Colors.cct(5_500.0f)
|
||||
LightManager.Builder(LightManager.Type.DIRECTIONAL)
|
||||
.color(r, g, b)
|
||||
// Intensity of the sun in lux on a clear day
|
||||
.intensity(110_000.0f)
|
||||
// The direction is normalized on our behalf
|
||||
.direction(0.0f, -0.5f, -1.0f)
|
||||
.castShadows(true)
|
||||
.build(engine, light)
|
||||
|
||||
// Add the entity to the scene to light it
|
||||
scene.addEntity(light)
|
||||
|
||||
// Set the exposure on the camera, this exposure follows the sunny f/16 rule
|
||||
// Since we've defined a light that has the same intensity as the sun, it
|
||||
// guarantees a proper exposure
|
||||
camera.setExposure(16.0f, 1.0f / 125.0f, 100.0f)
|
||||
|
||||
// Move the camera back to see the object
|
||||
camera.lookAt(0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
||||
|
||||
startAnimation()
|
||||
}
|
||||
|
||||
private fun loadMaterial() {
|
||||
readUncompressedAsset("materials/lit.filamat").let {
|
||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMaterial() {
|
||||
materialInstance = material.createInstance()
|
||||
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
|
||||
materialInstance.setParameter("roughness", 0.3f)
|
||||
}
|
||||
|
||||
private fun createMesh() {
|
||||
val floatSize = 4
|
||||
val shortSize = 2
|
||||
// A vertex is a position + a tangent frame:
|
||||
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
|
||||
val vertexSize = 3 * floatSize + 4 * floatSize
|
||||
|
||||
// Define a vertex and a function to put a vertex in a ByteBuffer
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
|
||||
fun ByteBuffer.put(v: Vertex): ByteBuffer {
|
||||
putFloat(v.x)
|
||||
putFloat(v.y)
|
||||
putFloat(v.z)
|
||||
v.tangents.forEach { putFloat(it) }
|
||||
return this
|
||||
}
|
||||
|
||||
// 6 faces, 4 vertices per face
|
||||
val vertexCount = 6 * 4
|
||||
|
||||
// Create tangent frames, one per face
|
||||
val tfPX = FloatArray(4)
|
||||
val tfNX = FloatArray(4)
|
||||
val tfPY = FloatArray(4)
|
||||
val tfNY = FloatArray(4)
|
||||
val tfPZ = FloatArray(4)
|
||||
val tfNZ = FloatArray(4)
|
||||
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, tfPX)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, tfNX)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, tfPY)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, tfNY)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, tfPZ)
|
||||
MathUtils.packTangentFrame( 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, tfNZ)
|
||||
|
||||
val vertexData = ByteBuffer.allocate(vertexCount * vertexSize)
|
||||
// It is important to respect the native byte order
|
||||
.order(ByteOrder.nativeOrder())
|
||||
// Face -Z
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNZ))
|
||||
// Face +X
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPX))
|
||||
// Face +Z
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPZ))
|
||||
// Face -X
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNX))
|
||||
// Face -Y
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNY))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfNY))
|
||||
// Face +Y
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfPY))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPY))
|
||||
// Make sure the cursor is pointing in the right place in the byte buffer
|
||||
.flip()
|
||||
|
||||
// Declare the layout of our mesh
|
||||
vertexBuffer = VertexBuffer.Builder()
|
||||
.bufferCount(1)
|
||||
.vertexCount(vertexCount)
|
||||
// Because we interleave position and color data we must specify offset and stride
|
||||
// We could use de-interleaved data by declaring two buffers and giving each
|
||||
// attribute a different buffer index
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
|
||||
.attribute(VertexAttribute.TANGENTS, 0, AttributeType.FLOAT4, 3 * floatSize, vertexSize)
|
||||
.build(engine)
|
||||
|
||||
// Feed the vertex data to the mesh
|
||||
// We only set 1 buffer because the data is interleaved
|
||||
vertexBuffer.setBufferAt(engine, 0, vertexData)
|
||||
|
||||
// Create the indices
|
||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
repeat(6) {
|
||||
val i = (it * 4).toShort()
|
||||
indexData
|
||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
||||
.putShort(i).putShort((i + 2).toShort()).putShort((i + 3).toShort())
|
||||
}
|
||||
indexData.flip()
|
||||
|
||||
// 6 faces, 2 triangles per face,
|
||||
indexBuffer = IndexBuffer.Builder()
|
||||
.indexCount(vertexCount * 2)
|
||||
.bufferType(IndexBuffer.Builder.IndexType.USHORT)
|
||||
.build(engine)
|
||||
indexBuffer.setBuffer(engine, indexData)
|
||||
}
|
||||
|
||||
private fun startAnimation() {
|
||||
// Animate the triangle
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.duration = 6000
|
||||
animator.repeatMode = ValueAnimator.RESTART
|
||||
animator.repeatCount = ValueAnimator.INFINITE
|
||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
||||
val transformMatrix = FloatArray(16)
|
||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
||||
val t = animator.animatedValue as Float
|
||||
val radians = sin(t) * 3.0f * PI.toFloat()
|
||||
Matrix.setRotateM(transformMatrix, 0, radians, 0.0f, 1.0f, 0.0f)
|
||||
val tcm = engine.transformManager
|
||||
tcm.setTransform(tcm.getInstance(renderable), transformMatrix)
|
||||
}
|
||||
})
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
choreographer.postFrameCallback(frameScheduler)
|
||||
animator.start()
|
||||
cameraHelper.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
cameraHelper.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
// Stop the animation and any pending frame
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(light)
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
engine.destroyVertexBuffer(vertexBuffer)
|
||||
engine.destroyIndexBuffer(indexBuffer)
|
||||
engine.destroyMaterialInstance(materialInstance)
|
||||
engine.destroyMaterial(material)
|
||||
engine.destroyView(view)
|
||||
engine.destroyScene(scene)
|
||||
engine.destroyCamera(camera)
|
||||
|
||||
// Engine.destroyEntity() destroys Filament related resources only
|
||||
// (components), not the entity itself
|
||||
val entityManager = EntityManager.get()
|
||||
entityManager.destroy(light)
|
||||
entityManager.destroy(renderable)
|
||||
|
||||
// Destroying the engine will free up any resource you may have forgotten
|
||||
// to destroy, but it's recommended to do the cleanup properly
|
||||
engine.destroy()
|
||||
}
|
||||
|
||||
inner class FrameCallback : Choreographer.FrameCallback {
|
||||
override fun doFrame(frameTimeNanos: Long) {
|
||||
// Schedule the next frame
|
||||
choreographer.postFrameCallback(this)
|
||||
|
||||
// This check guarantees that we have a swap chain
|
||||
if (uiHelper.isReadyToRender) {
|
||||
// If beginFrame() returns false you should skip the frame
|
||||
// This means you are sending frames too quickly to the GPU
|
||||
if (renderer.beginFrame(swapChain!!)) {
|
||||
renderer.render(view)
|
||||
renderer.endFrame()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class SurfaceCallback : UiHelper.RendererCallback {
|
||||
override fun onNativeWindowChanged(surface: Surface) {
|
||||
swapChain?.let { engine.destroySwapChain(it) }
|
||||
swapChain = engine.createSwapChain(surface)
|
||||
}
|
||||
|
||||
override fun onDetachedFromSurface() {
|
||||
swapChain?.let {
|
||||
engine.destroySwapChain(it)
|
||||
// Required to ensure we don't return before Filament is done executing the
|
||||
// destroySwapChain command, otherwise Android might destroy the Surface
|
||||
// too early
|
||||
engine.flushAndWait()
|
||||
swapChain = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResized(width: Int, height: Int) {
|
||||
val aspect = width.toDouble() / height.toDouble()
|
||||
camera.setProjection(45.0, aspect, 0.1, 20.0, Camera.Fov.VERTICAL)
|
||||
|
||||
view.viewport = Viewport(0, 0, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readUncompressedAsset(@Suppress("SameParameterValue") assetName: String): ByteBuffer {
|
||||
assets.openFd(assetName).use { fd ->
|
||||
val input = fd.createInputStream()
|
||||
val dst = ByteBuffer.allocate(fd.length.toInt())
|
||||
|
||||
val src = Channels.newChannel(input)
|
||||
src.read(dst)
|
||||
src.close()
|
||||
|
||||
return dst.apply { rewind() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
if (!cameraHelper.onRequestPermissionsResult(requestCode, grantResults)) {
|
||||
this.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
73
android/samples/hello-camera/app/src/main/materials/lit.mat
Normal file
@@ -0,0 +1,73 @@
|
||||
// Simple lit material that defines 3 parameters:
|
||||
// - baseColor
|
||||
// - roughness
|
||||
// - metallic
|
||||
//
|
||||
// These parameters can be used by the application to change the appearance of the material.
|
||||
//
|
||||
// This source material must be compiled to a binary material using the matc tool.
|
||||
// The command used to compile this material is:
|
||||
// matc -p mobile -a opengl -o app/src/main/assets/lit.filamat app/src/materials/lit.mat
|
||||
//
|
||||
// See build.gradle for an example of how to compile materials automatically
|
||||
// Please refer to the documentation for more information about matc and the materials system.
|
||||
|
||||
material {
|
||||
name : lit,
|
||||
|
||||
// Dynamic lighting is enabled on this material
|
||||
shadingModel : lit,
|
||||
|
||||
// We don't need to declare a "requires" array, lit materials
|
||||
// always requires the "tangents" vertex attribute (the normal
|
||||
// is required for lighting, tangent/bitangent for normal mapping
|
||||
// and anisotropy)
|
||||
|
||||
// Custom vertex shader outputs
|
||||
variables : [
|
||||
uv
|
||||
],
|
||||
|
||||
// List of parameters exposed by this material
|
||||
parameters : [
|
||||
// The color must be passed in linear space, not sRGB
|
||||
{
|
||||
type : float3,
|
||||
name : baseColor
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : roughness
|
||||
},
|
||||
{
|
||||
type : samplerExternal,
|
||||
name : videoTexture
|
||||
},
|
||||
{
|
||||
type : mat4,
|
||||
name : textureTransform
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
material.uv = 0.5 * (getPosition() + vec4(1));
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.roughness = materialParams.roughness;
|
||||
material.metallic = 0.0;
|
||||
|
||||
// Apply the video stream to the +Z face on the cube.
|
||||
if (variable_uv.z >= 1.0) {
|
||||
vec2 uv = (materialParams.textureTransform * vec4(variable_uv.xy, 0, 1)).xy;
|
||||
material.baseColor.rgb = inverseTonemapSRGB(texture(materialParams_videoTexture, uv).rgb);
|
||||
} else {
|
||||
material.baseColor.rgb = materialParams.baseColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0"/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Hello Camera</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
41
android/samples/hello-camera/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
13
android/samples/hello-camera/gradle.properties
Normal file
@@ -0,0 +1,13 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
BIN
android/samples/hello-camera/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
android/samples/hello-camera/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Mon Jan 14 11:08:15 PST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
172
android/samples/hello-camera/gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
android/samples/hello-camera/gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
3
android/samples/hello-camera/settings.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
includeBuild '../../filament-android'
|
||||
|
||||
include ':app'
|
||||
@@ -261,10 +261,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
|
||||
@@ -238,10 +238,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
destroyMesh(engine, mesh)
|
||||
destroyIbl(engine, ibl)
|
||||
|
||||
@@ -346,10 +346,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(light)
|
||||
engine.destroyEntity(renderable)
|
||||
|
||||
@@ -73,6 +73,13 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
// The filamat library has two variants: full and lite. Here we default to the "full" variant.
|
||||
// Replace "full" with "lite" to use the filamat-lite variant, which has a smaller binary size
|
||||
// but comes with certain restrictions. See "Filamat Lite" in libs/filamat/README.md.
|
||||
defaultConfig {
|
||||
missingDimensionStrategy 'functionality', 'full'
|
||||
}
|
||||
|
||||
// We use the .filamat extension for materials compiled with matc
|
||||
// Telling aapt to not compress them allows to load them efficiently
|
||||
aaptOptions {
|
||||
|
||||
@@ -212,6 +212,10 @@ class MainActivity : Activity() {
|
||||
" material.clearCoat = 1.0;\n" +
|
||||
"}\n")
|
||||
|
||||
// Turn off shader code optimization so this sample is compatible with the "lite"
|
||||
// variant of the filamat library.
|
||||
.optimization(MaterialBuilder.Optimization.NONE)
|
||||
|
||||
.build()
|
||||
|
||||
if (matPackage.isValid) {
|
||||
@@ -274,10 +278,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
destroyMesh(engine, mesh)
|
||||
destroyIbl(engine, ibl)
|
||||
|
||||
@@ -261,10 +261,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
|
||||
@@ -257,10 +257,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
destroyMesh(engine, mesh)
|
||||
destroyIbl(engine, ibl)
|
||||
|
||||
@@ -279,10 +279,6 @@ class MainActivity : Activity() {
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// This ensures that all the commands we've sent to Filament have
|
||||
// been processed before we attempt to destroy anything
|
||||
engine.flushAndWait()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
|
||||
@@ -29,7 +29,9 @@ cd ..
|
||||
# Steps for GitHub Workflows
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
|
||||
20
build/windows/build-github.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
|
||||
if "%GITHUB_WORKFLOW%" == "" (set RUNNING_LOCALLY=1)
|
||||
|
||||
set VISUAL_STUDIO_VERSION="Enterprise"
|
||||
if "%RUNNING_LOCALLY%" == "1" (set VISUAL_STUDIO_VERSION="Professional")
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\%VISUAL_STUDIO_VERSION%\VC\Auxiliary\Build\vcvars64.bat"
|
||||
if errorlevel 1 exit /b %errorlevel%
|
||||
|
||||
msbuild /version
|
||||
cmake --version
|
||||
|
||||
mkdir out\cmake-release
|
||||
cd out\cmake-release
|
||||
if errorlevel 1 exit /b %errorlevel%
|
||||
|
||||
cmake ..\.. -G "Visual Studio 16 2019" -A x64 || exit /b
|
||||
|
||||
msbuild TNT.sln /m /p:configuration=Release
|
||||
@@ -1,3 +0,0 @@
|
||||
# Format: //devtools/kokoro/config/proto/build.proto
|
||||
|
||||
build_file: "filament/build/windows/build.bat"
|
||||
BIN
docs/images/samples/sample_hello_camera.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
@@ -37,6 +37,10 @@ To use Filament from Java you must use the following two libraries instead:
|
||||
- `filament-java.jar`, Contains Filament's Java classes
|
||||
- `filament-jni`, Filament's JNI bindings
|
||||
|
||||
To link against debug builds of Filament, you must also link against:
|
||||
|
||||
- `matdbg`, Support library that adds an interactive web-based debugger to Filament
|
||||
|
||||
To use the Vulkan backend on macOS you must also make the following libraries available at runtime:
|
||||
- `MoltenVK_icd.json`
|
||||
- `libMoltenVK.dylib`
|
||||
|
||||
@@ -19,6 +19,7 @@ set(PUBLIC_HDRS
|
||||
|
||||
set(SRCS
|
||||
src/BackendUtils.cpp
|
||||
src/Callable.cpp
|
||||
src/CircularBuffer.cpp
|
||||
src/CommandBufferQueue.cpp
|
||||
src/CommandStream.cpp
|
||||
@@ -276,7 +277,9 @@ install(DIRECTORY ${PUBLIC_HDR_DIR}/backend DESTINATION include)
|
||||
# ==================================================================================================
|
||||
# Test
|
||||
# ==================================================================================================
|
||||
if (APPLE AND NOT IOS)
|
||||
option(INSTALL_BACKEND_TEST "Install the backend test library so it can be consumed on iOS" OFF)
|
||||
|
||||
if (APPLE)
|
||||
add_library(backend_test STATIC
|
||||
test/BackendTest.cpp
|
||||
test/ShaderGenerator.cpp
|
||||
@@ -292,6 +295,34 @@ if (APPLE AND NOT IOS)
|
||||
SPIRV
|
||||
spirv-cross-glsl)
|
||||
|
||||
set(BACKEND_TEST_DEPS
|
||||
OGLCompiler
|
||||
OSDependent
|
||||
SPIRV
|
||||
SPIRV-Tools
|
||||
SPIRV-Tools-opt
|
||||
backend_test
|
||||
filabridge
|
||||
getopt
|
||||
gtest
|
||||
glslang
|
||||
spirv-cross-core
|
||||
spirv-cross-glsl
|
||||
spirv-cross-msl
|
||||
)
|
||||
|
||||
set(BACKEND_TEST_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libbackendtest_combined.a")
|
||||
combine_static_libs(backend_test "${BACKEND_TEST_COMBINED_OUTPUT}" "${BACKEND_TEST_DEPS}")
|
||||
|
||||
set(BACKEND_TEST_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}backend_test${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
|
||||
if (INSTALL_BACKEND_TEST)
|
||||
install(FILES "${BACKEND_TEST_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${BACKEND_TEST_LIB_NAME})
|
||||
install(FILES test/PlatformRunner.h DESTINATION include/backend_test)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE AND NOT IOS)
|
||||
add_executable(backend_test_mac test/mac_runner.mm)
|
||||
target_link_libraries(backend_test_mac PRIVATE "-framework Metal -framework AppKit -framework QuartzCore")
|
||||
# Because each test case is a separate file, the -force_load flag is necessary to prevent the
|
||||
|
||||
111
filament/backend/include/backend/PresentCallable.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRESENT_CALLABLE
|
||||
#define TNT_FILAMENT_BACKEND_PRESENT_CALLABLE
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
/**
|
||||
* A PresentCallable is a callable object that, when called, schedules a frame for presentation on
|
||||
* a SwapChain.
|
||||
*
|
||||
* Typically, Filament's backend is responsible scheduling a frame's presentation. However, there
|
||||
* are certain cases where the application might want to control when a frame is scheduled for
|
||||
* presentation.
|
||||
*
|
||||
* For example, on iOS, UIKit elements can be synchronized to 3D content by scheduling a present
|
||||
* within a CATransation:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* void myFrameFinishedCallback(PresentCallable presentCallable, void* user) {
|
||||
* [CATransaction begin];
|
||||
* // Update other UI elements...
|
||||
* presentCallable();
|
||||
* [CATransaction commit];
|
||||
* }
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* To obtain a PresentCallable, pass a backend::FrameFinishedCallback to the beginFrame() function.
|
||||
* The callback is called with a PresentCallable object and optional user data:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* if (renderer->beginFrame(swapChain, myFrameFinishedCallback, nullptr)) {
|
||||
* renderer->render(view);
|
||||
* renderer->endFrame();
|
||||
* }
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
|
||||
* backends ignore the callback (which will never be called) and proceed normally.
|
||||
*
|
||||
* @remark The backend::FrameFinishedCallback is called on an arbitrary thread.
|
||||
*
|
||||
* Applications *must* call each PresentCallable they receive. Each PresentCallable represents a
|
||||
* frame that is waiting to be presented. If an application fails to call a PresentCallable, a
|
||||
* memory leak could occur. To "cancel" the presentation of a frame, pass false to the
|
||||
* PresentCallable, which will cancel the presentation of the frame and release associated memory.
|
||||
*
|
||||
* @see Renderer, SwapChain, Renderer.beginFrame
|
||||
*/
|
||||
class UTILS_PUBLIC PresentCallable {
|
||||
public:
|
||||
|
||||
using PresentFn = void(*)(bool presentFrame, void* user);
|
||||
|
||||
PresentCallable(PresentFn fn, void* user) noexcept;
|
||||
~PresentCallable() noexcept = default;
|
||||
PresentCallable(const PresentCallable& rhs) = default;
|
||||
PresentCallable& operator=(const PresentCallable& rhs) = default;
|
||||
|
||||
/**
|
||||
* Call this PresentCallable, scheduling the associated frame for presentation. Pass false for
|
||||
* presentFrame to effectively "cancel" the presentation of the frame.
|
||||
*
|
||||
* @param presentFrame if false, will not present the frame but releases associated memory
|
||||
*/
|
||||
void operator()(bool presentFrame = true) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
PresentFn mPresentFn;
|
||||
void* mUser = nullptr;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* FrameFinishedCallback is a callback function that notifies an application when Filament has
|
||||
* finished processing a frame and that frame is ready to be scheduled for presentation.
|
||||
*
|
||||
* beginFrame() takes an optional FrameFinishedCallback. If the callback is provided, then that
|
||||
* frame will *not* automatically be scheduled for presentation. Instead, the application must call
|
||||
* the given PresentCallable.
|
||||
*
|
||||
* @remark The backend::FrameFinishedCallback is called on an arbitrary thread.
|
||||
*
|
||||
* @see PresentCallable, beginFrame()
|
||||
*/
|
||||
using FrameFinishedCallback = void(*)(PresentCallable callable, void* user);
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRESENT_FRAME_CALLABLE
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <backend/Handle.h>
|
||||
#include <backend/PipelineState.h>
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
#include <backend/PresentCallable.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <backend/Handle.h>
|
||||
#include <backend/PipelineState.h>
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
#include <backend/PresentCallable.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
|
||||
#include "private/backend/DriverApiForward.h"
|
||||
|
||||
@@ -110,7 +110,9 @@
|
||||
|
||||
DECL_DRIVER_API_N(beginFrame,
|
||||
int64_t, monotonic_clock_ns,
|
||||
uint32_t, frameId)
|
||||
uint32_t, frameId,
|
||||
backend::FrameFinishedCallback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(setPresentationTime,
|
||||
int64_t, monotonic_clock_ns)
|
||||
|
||||
38
filament/backend/src/Callable.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <backend/PresentCallable.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
PresentCallable::PresentCallable(PresentFn fn, void* user) noexcept
|
||||
: mPresentFn(fn), mUser(user) {
|
||||
assert(fn != nullptr);
|
||||
}
|
||||
|
||||
void PresentCallable::operator()(bool presentFrame) noexcept {
|
||||
ASSERT_PRECONDITION(mPresentFn, "This PresentCallable was already called. " \
|
||||
"PresentCallables should be called exactly once.");
|
||||
mPresentFn(presentFrame, mUser);
|
||||
// Set mPresentFn to nullptr to denote that the callable has been called.
|
||||
mPresentFn = nullptr;
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
@@ -90,22 +90,27 @@ void* CircularBuffer::alloc(size_t size) noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mUsesAshmem < 0)) {
|
||||
// ashmem failed
|
||||
if (vaddr_guard != MAP_FAILED)
|
||||
if (vaddr_guard != MAP_FAILED) {
|
||||
munmap(vaddr_guard, size);
|
||||
}
|
||||
|
||||
if (vaddr_shadow != MAP_FAILED)
|
||||
if (vaddr_shadow != MAP_FAILED) {
|
||||
munmap(vaddr_shadow, size);
|
||||
}
|
||||
|
||||
if (vaddr != MAP_FAILED)
|
||||
if (vaddr != MAP_FAILED) {
|
||||
munmap(vaddr, size);
|
||||
}
|
||||
|
||||
if (fd >= 0)
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
data = mmap(nullptr, size * 2 + BLOCK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
data = mmap(nullptr, size * 2 + BLOCK_SIZE,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
ASSERT_POSTCONDITION(data,
|
||||
"couldn't allocate %u KiB of memory for the command buffer",
|
||||
"couldn't allocate %u KiB of virtual address space for the command buffer",
|
||||
(size * 2 / 1024));
|
||||
|
||||
slog.d << "WARNING: Using soft CircularBuffer (" << (size * 2 / 1024) << " KiB)"
|
||||
|
||||
@@ -53,6 +53,15 @@ struct MetalContext {
|
||||
id<MTLCommandBuffer> currentCommandBuffer = nullptr;
|
||||
id<MTLRenderCommandEncoder> currentCommandEncoder = nullptr;
|
||||
|
||||
// These two fields store a callback and user data to notify the client that a frame is ready
|
||||
// for presentation.
|
||||
// If frameFinishedCallback is nullptr, then the Metal backend automatically calls
|
||||
// presentDrawable when the frame is commited.
|
||||
// Otherwise, the Metal backend will not automatically present the frame. Instead, clients bear
|
||||
// the responsibility of presenting the frame by calling the PresentCallable object.
|
||||
backend::FrameFinishedCallback frameFinishedCallback = nullptr;
|
||||
void* frameFinishedUserData = nullptr;
|
||||
|
||||
// Tracks resources used by command buffers.
|
||||
MetalResourceTracker resourceTracker;
|
||||
|
||||
|
||||
@@ -24,9 +24,32 @@ namespace filament {
|
||||
namespace backend {
|
||||
namespace metal {
|
||||
|
||||
void presentDrawable(bool presentFrame, void* user) {
|
||||
id<CAMetalDrawable> drawable = (id<CAMetalDrawable>) user;
|
||||
if (presentFrame) {
|
||||
[drawable present];
|
||||
}
|
||||
[drawable release];
|
||||
}
|
||||
|
||||
id<CAMetalDrawable> acquireDrawable(MetalContext* context) {
|
||||
if (!context->currentDrawable) {
|
||||
context->currentDrawable = [context->currentSurface->layer nextDrawable];
|
||||
// The drawable is retained here and will be released either:
|
||||
// 1. in MetalDriver::commit
|
||||
// 2. in the presentDrawable function, when the client calls the PresentCallable
|
||||
context->currentDrawable = [[context->currentSurface->layer nextDrawable] retain];
|
||||
|
||||
if (context->frameFinishedCallback) {
|
||||
id<CAMetalDrawable> drawable = context->currentDrawable;
|
||||
backend::FrameFinishedCallback callback = context->frameFinishedCallback;
|
||||
void* userData = context->frameFinishedUserData;
|
||||
[context->currentCommandBuffer addScheduledHandler:^(id<MTLCommandBuffer> cb) {
|
||||
PresentCallable callable(presentDrawable, (void*) drawable);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
callback(callable, userData);
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
ASSERT_POSTCONDITION(context->currentDrawable != nil, "Could not obtain drawable.");
|
||||
return context->currentDrawable;
|
||||
|
||||
@@ -89,13 +89,18 @@ void MetalDriver::debugCommand(const char *methodName) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
|
||||
void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId,
|
||||
backend::FrameFinishedCallback callback, void* user) {
|
||||
mContext->framePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = acquireCommandBuffer(mContext);
|
||||
[commandBuffer addCompletedHandler:^(id <MTLCommandBuffer> buffer) {
|
||||
mContext->resourceTracker.clearResources(buffer);
|
||||
}];
|
||||
|
||||
// If a callback was specified, then the client is responsible for presenting the frame.
|
||||
mContext->frameFinishedCallback = callback;
|
||||
mContext->frameFinishedUserData = user;
|
||||
}
|
||||
|
||||
void MetalDriver::setPresentationTime(int64_t monotonic_clock_ns) {
|
||||
@@ -115,6 +120,12 @@ void MetalDriver::endFrame(uint32_t frameId) {
|
||||
[mContext->framePool drain];
|
||||
mContext->bufferPool->gc();
|
||||
|
||||
if (!mContext->frameFinishedCallback) {
|
||||
// If we're responsible for presenting the frame, then by this point we've already done so
|
||||
// and it's safe to release the drawable.
|
||||
[mContext->currentDrawable release];
|
||||
}
|
||||
|
||||
CVMetalTextureCacheFlush(mContext->textureCache, 0);
|
||||
}
|
||||
|
||||
@@ -540,11 +551,11 @@ bool MetalDriver::canGenerateMipmaps() {
|
||||
|
||||
void MetalDriver::loadUniformBuffer(Handle<HwUniformBuffer> ubh,
|
||||
BufferDescriptor&& data) {
|
||||
if (data.size <= 0) {
|
||||
if (data.size <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto buffer = handle_cast<MetalUniformBuffer>(mHandleMap, ubh);
|
||||
auto buffer = handle_cast<MetalUniformBuffer>(mHandleMap, ubh);
|
||||
|
||||
buffer->copyIntoBuffer(data.buffer, data.size);
|
||||
scheduleDestroy(std::move(data));
|
||||
@@ -664,8 +675,9 @@ void MetalDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain> s
|
||||
}
|
||||
|
||||
void MetalDriver::commit(Handle<HwSwapChain> sch) {
|
||||
if (mContext->currentDrawable != nil) {
|
||||
if (mContext->currentDrawable != nil && !mContext->frameFinishedCallback) {
|
||||
[mContext->currentCommandBuffer presentDrawable:mContext->currentDrawable];
|
||||
[mContext->currentDrawable release];
|
||||
}
|
||||
[mContext->currentCommandBuffer commit];
|
||||
mContext->currentCommandBuffer = nil;
|
||||
|
||||