Compare commits
104 Commits
sceneform-
...
v1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a052d6cf49 | ||
|
|
591c9f2454 | ||
|
|
e580bfed56 | ||
|
|
e2896f4632 | ||
|
|
a33c64c736 | ||
|
|
7ea04957d2 | ||
|
|
8c6cfdba67 | ||
|
|
e5cfbeff4d | ||
|
|
68c6afa72e | ||
|
|
bb3e9a47e5 | ||
|
|
8d410af4b3 | ||
|
|
61112c02c1 | ||
|
|
816fb99b2f | ||
|
|
9de7ffaf84 | ||
|
|
e3e16fe28b | ||
|
|
bb0c21b8ea | ||
|
|
c46ecc6e05 | ||
|
|
fffb2c8c97 | ||
|
|
a42dcd2291 | ||
|
|
4e3a88bbab | ||
|
|
02d45d464c | ||
|
|
c758b53f00 | ||
|
|
4e3c2582e0 | ||
|
|
cc1ba4fac7 | ||
|
|
f52087ec1e | ||
|
|
2ac04c27d8 | ||
|
|
211eddfbe0 | ||
|
|
522a8bedb8 | ||
|
|
8ad655766b | ||
|
|
5da454f652 | ||
|
|
0deafea0da | ||
|
|
69e379cf90 | ||
|
|
e8fddba494 | ||
|
|
31b9801f17 | ||
|
|
4860ff816f | ||
|
|
82e61ddc88 | ||
|
|
3a9f3a1984 | ||
|
|
3b793a7994 | ||
|
|
e2777b9100 | ||
|
|
96cb5d5951 | ||
|
|
e6bb8a6235 | ||
|
|
934b75e68b | ||
|
|
58f36d1a7f | ||
|
|
83e4402e90 | ||
|
|
c6a1900beb | ||
|
|
17021a1167 | ||
|
|
f0fbdaec28 | ||
|
|
b73f58e6ef | ||
|
|
254e3db215 | ||
|
|
d9df864de4 | ||
|
|
995b8361b8 | ||
|
|
a61af02038 | ||
|
|
84bfbac5fa | ||
|
|
912b301790 | ||
|
|
b707027401 | ||
|
|
68dfb5ae80 | ||
|
|
ab3770d281 | ||
|
|
28c56eb354 | ||
|
|
30eccc78b6 | ||
|
|
ab24665396 | ||
|
|
9e7b589d0a | ||
|
|
979b6f00fd | ||
|
|
0754edbf9b | ||
|
|
9916af3ab1 | ||
|
|
dcfbe694b1 | ||
|
|
835cc93b71 | ||
|
|
2f14ac64a7 | ||
|
|
e96f982c9f | ||
|
|
605a836565 | ||
|
|
1cde20d822 | ||
|
|
a547f11a8c | ||
|
|
83de0fc3e8 | ||
|
|
3ed2dd08fb | ||
|
|
db729b157a | ||
|
|
29119c7248 | ||
|
|
356c3a2c24 | ||
|
|
b0853b5eb6 | ||
|
|
d324dc724a | ||
|
|
e6435a7431 | ||
|
|
d3e7f40398 | ||
|
|
f5319f2492 | ||
|
|
e00ba80561 | ||
|
|
d15e275de0 | ||
|
|
920cc7a84a | ||
|
|
3b504f2941 | ||
|
|
f697b41a2b | ||
|
|
8452c4f8f2 | ||
|
|
c238027e49 | ||
|
|
b374340ebb | ||
|
|
c581b755fd | ||
|
|
9e5f44bd34 | ||
|
|
d9204052c8 | ||
|
|
5a8d4d818c | ||
|
|
cd84980c84 | ||
|
|
9b8d5fdf12 | ||
|
|
7cb01929a3 | ||
|
|
e7777ef330 | ||
|
|
0326d60d0a | ||
|
|
0d709b6074 | ||
|
|
6992c8a584 | ||
|
|
7c54faa8bd | ||
|
|
3a0f9791cc | ||
|
|
473824b15e | ||
|
|
b4c77166b7 |
@@ -270,6 +270,7 @@ add_subdirectory(${EXTERNAL}/libgtest/tnt)
|
||||
add_subdirectory(${LIBRARIES}/filabridge)
|
||||
add_subdirectory(${LIBRARIES}/filaflat)
|
||||
add_subdirectory(${LIBRARIES}/filamat)
|
||||
add_subdirectory(${LIBRARIES}/filameshio)
|
||||
add_subdirectory(${LIBRARIES}/image)
|
||||
add_subdirectory(${LIBRARIES}/math)
|
||||
add_subdirectory(${LIBRARIES}/utils)
|
||||
@@ -289,7 +290,8 @@ endif()
|
||||
set (FILAMENT_SAMPLES_BINARY_DIR ${PROJECT_BINARY_DIR}/samples)
|
||||
|
||||
if (WEBGL)
|
||||
add_subdirectory(${FILAMENT}/samples/web)
|
||||
add_subdirectory(web/filament-js)
|
||||
add_subdirectory(web/samples)
|
||||
|
||||
add_subdirectory(${LIBRARIES}/filagui)
|
||||
|
||||
@@ -297,7 +299,7 @@ if (WEBGL)
|
||||
add_subdirectory(${EXTERNAL}/stb/tnt)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID AND NOT WEBGL)
|
||||
if (NOT ANDROID AND NOT WEBGL AND NOT IOS)
|
||||
add_subdirectory(${FILAMENT}/samples)
|
||||
|
||||
add_subdirectory(${LIBRARIES}/bluegl)
|
||||
@@ -334,7 +336,7 @@ if (NOT ANDROID AND NOT WEBGL)
|
||||
add_subdirectory(${TOOLS}/specular-color)
|
||||
endif()
|
||||
|
||||
# Generate exported executables for cross-compiled builds (Android and WebGL)
|
||||
# Generate exported executables for cross-compiled builds (Android, WebGL, and iOS)
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
export(TARGETS matc cmgen filamesh mipgen FILE ${IMPORT_EXECUTABLES})
|
||||
endif()
|
||||
|
||||
53
README.md
@@ -1,13 +1,14 @@
|
||||
# Filament
|
||||
|
||||
<img alt="Android" src="build/img/android.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_android.html)
|
||||
<img alt="iOS" src="build/img/macos.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_ios.html)
|
||||
<img alt="Linux" src="build/img/linux.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_linux.html)
|
||||
<img alt="macOS" src="build/img/macos.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_mac.html)
|
||||
<img alt="Windows" src="build/img/windows.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_windows.html)
|
||||
<img alt="Web" src="build/img/web.png" width="20px" height="20px" hspace="2px"/>[](https://filament-build.storage.googleapis.com/badges/build_link_web.html)
|
||||
|
||||
Filament is a real-time physically based rendering engine for Android, Linux, macOS, Windows, and
|
||||
WebGL. It is designed to be as small as possible and as efficient as possible on Android.
|
||||
Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows,
|
||||
and WebGL. It is designed to be as small as possible and as efficient as possible on Android.
|
||||
|
||||
Filament is currently used in the
|
||||
[Sceneform](https://developers.google.com/ar/develop/java/sceneform/) library both at runtime on
|
||||
@@ -53,13 +54,14 @@ Here are a few sample materials rendered with Filament:
|
||||
|
||||
- Native C++ API for Android, Linux, macOS and Windows
|
||||
- Java/JNI API for Android, Linux, macOS and Windows
|
||||
- [Python bindings](https://github.com/artometa/pyfilament)
|
||||
- JavaScript API
|
||||
|
||||
### Backends
|
||||
|
||||
- OpenGL 4.1+ for Linux, macOS and Windows
|
||||
- OpenGL ES 3.0+ for Android
|
||||
- Vulkan 1.0 for Android, Linux, macOS (with MoltenVk) and Windows
|
||||
- OpenGL ES 3.0+ for Android and iOS
|
||||
- Vulkan 1.0 for Android, Linux, macOS and iOS (with MoltenVk), and Windows
|
||||
- WebGL 2.0 for all platforms
|
||||
|
||||
### Rendering
|
||||
|
||||
@@ -108,6 +110,7 @@ Many other features have been either prototyped or planned:
|
||||
- `math`: Mathematica notebooks used to explore BRDFs, equations, etc.
|
||||
- `filament`: Filament engine
|
||||
- `ide`: Configuration files for IDEs (CLion, etc.)
|
||||
- `ios`: Sample projects for iOS
|
||||
- `java`: Java bindings for Filament libraries
|
||||
- `libs`: Libraries
|
||||
- `bluegl`: OpenGL bindings for macOS, Linux and Windows
|
||||
@@ -116,6 +119,7 @@ Many other features have been either prototyped or planned:
|
||||
- `filaflat`: Serialization/deserialization library used for materials
|
||||
- `filagui`: Helper library for [Dear ImGui](https://github.com/ocornut/imgui)
|
||||
- `filamat`: Material generation library
|
||||
- `filameshio`: Tiny mesh parsing library (see also `tools/filamesh`)
|
||||
- `image`: Image filtering and simple transforms
|
||||
- `imageio`: Image file reading / writing, only intended for internal use
|
||||
- `math`: Math library
|
||||
@@ -132,7 +136,7 @@ Many other features have been either prototyped or planned:
|
||||
- `matinfo` Displays information about materials compiled with `matc`
|
||||
- `mipgen` Generates a series of miplevels from a source image.
|
||||
- `normal-blending`: Tool to blend normal maps
|
||||
- `roughness-prefilter`: Pre-filters a roughness map from a normal map to reduce aliasing
|
||||
- `roughness-prefilter`: Pre-filters a roughness map from a normal map to reduce aliasing
|
||||
- `skygen`: Physically-based sky environment texture generator
|
||||
- `specular-color`: Computes the specular color of conductors based on spectral data
|
||||
|
||||
@@ -299,6 +303,17 @@ $ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/fi
|
||||
$ ninja
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
The easiest way to build Filament for iOS is to use `build.sh` and the
|
||||
`-p ios` flag. For instance to build the debug target:
|
||||
|
||||
```
|
||||
$ ./build.sh -p ios debug
|
||||
```
|
||||
|
||||
See [ios/samples/README.md](./ios/samples/README.md) for more information.
|
||||
|
||||
### Windows
|
||||
|
||||
The following instructions have been tested on a machine running Windows 10. They should take you
|
||||
@@ -700,18 +715,24 @@ export EMSDK=<your chosen home for the emscripten SDK>
|
||||
```
|
||||
|
||||
The EMSDK variable is required so that the build script can find the Emscripten SDK. The build
|
||||
creates a `public` folder that can be used as the root of a simple static web server. Note that you
|
||||
creates a `samples` folder that can be used as the root of a simple static web server. Note that you
|
||||
cannot open the HTML directly from the filesystem due to CORS. One way to deal with this is to
|
||||
use Python to create a quick localhost server:
|
||||
|
||||
```
|
||||
cd out/cmake-webgl-release/samples/web/public
|
||||
cd out/cmake-webgl-release/web/samples
|
||||
python3 -m http.server # Python 3
|
||||
python -m SimpleHTTPServer # Python 2.7
|
||||
```
|
||||
|
||||
Each sample app has its own handwritten html file, wasm file, and js loader. Additionally the public
|
||||
folder contains meshes, textures, and the tiny `filaweb.js` library.
|
||||
You can then open http://localhost:8000/suzanne.html in your web browser.
|
||||
|
||||
Alternatively, if you have node installed you can use the
|
||||
[live-server](https://www.npmjs.com/package/live-server) package, which automatically refreshes the
|
||||
web page when it detects a change.
|
||||
|
||||
Each sample app has its own handwritten html file. Additionally the server folder contains assets
|
||||
such as meshes, textures, and materials.
|
||||
|
||||
## Running the native samples
|
||||
|
||||
@@ -730,7 +751,7 @@ in your build directory). These sample apps expect a path to a directory contain
|
||||
for the IBL. To generate an IBL simply use this command:
|
||||
|
||||
```
|
||||
cmgen -x ./ibls/ my_ibl.exr
|
||||
cmgen -x ./ibls/ my_ibl.exr
|
||||
```
|
||||
|
||||
The source environment map can be a PNG (8 or 16 bit), a PSD (16 or 32 bit), an HDR or an OpenEXR
|
||||
@@ -840,6 +861,14 @@ package `com.google.android.filament.android`. All you need to do is set a rende
|
||||
helper and attach your `SurfaceView` or `TextureView` to it. You are still responsible for
|
||||
creating the swap chain in the `onNativeWindowChanged()` callback.
|
||||
|
||||
### iOS
|
||||
|
||||
See `ios/samples` for examples of using Filament on iOS.
|
||||
|
||||
Filament on iOS is largely the same as native rendering with C++. A `CAEAGLLayer` or `CAMetalLayer`
|
||||
is passed to the `createSwapChain` method. Filament for iOS supports both OpenGL ES and Vulkan via
|
||||
MoltenVK.
|
||||
|
||||
## Generating C++ documentation
|
||||
|
||||
To generate the documentation you must first install `doxygen`, then run the following commands:
|
||||
@@ -870,7 +899,7 @@ Host tools (such as `matc` or `cmgen`) can use external dependencies freely.
|
||||
## How to make contributions
|
||||
|
||||
Please read and follow the steps in [CONTRIBUTING.md](/CONTRIBUTING.md). Make sure you are
|
||||
familiar with the [code style](/CODE_STYLE.md).
|
||||
familiar with the [code style](/CODE_STYLE.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ target_link_libraries(filament-jni
|
||||
GLESv3
|
||||
EGL
|
||||
android
|
||||
jnigraphics
|
||||
)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
|
||||
@@ -13,7 +13,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ JniCallback::~JniCallback() {
|
||||
|
||||
void JniCallback::invoke(void*, size_t, void* user) {
|
||||
JniCallback* data = reinterpret_cast<JniCallback*>(user);
|
||||
delete data;
|
||||
// don't call delete here, because we don't own the storage
|
||||
data->~JniCallback();
|
||||
}
|
||||
|
||||
JniBufferCallback* JniBufferCallback::make(filament::Engine* engine,
|
||||
|
||||
@@ -154,3 +154,9 @@ Java_com_google_android_filament_Stream_nReadPixels(JNIEnv *env, jclass,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Stream_nGetTimestamp(JNIEnv*, jclass, jlong nativeStream) {
|
||||
Stream *stream = (Stream *) nativeStream;
|
||||
return stream->getTimestamp();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/bitmap.h>
|
||||
#endif
|
||||
|
||||
#include <filament/driver/BufferDescriptor.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Stream.h>
|
||||
@@ -37,7 +41,7 @@ static size_t getTextureDataSize(const Texture *texture, size_t level,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Texture_nIsTextureFormatSupported(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nIsTextureFormatSupported(JNIEnv*, jclass,
|
||||
jlong nativeEngine, jint internalFormat) {
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
return (jboolean) Texture::isTextureFormatSupported(*engine,
|
||||
@@ -47,68 +51,68 @@ Java_com_google_android_filament_Texture_nIsTextureFormatSupported(JNIEnv *env,
|
||||
// Texture::Builder...
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Texture_nCreateBuilder(JNIEnv *env, jclass type) {
|
||||
Java_com_google_android_filament_Texture_nCreateBuilder(JNIEnv*, jclass) {
|
||||
return (jlong) new Texture::Builder();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nDestroyBuilder(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nDestroyBuilder(JNIEnv*, jclass,
|
||||
jlong nativeBuilder) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
delete builder;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderWidth(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderWidth(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint width) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->width((uint32_t) width);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderHeight(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderHeight(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint height) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->height((uint32_t) height);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderDepth(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderDepth(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint depth) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->depth((uint32_t) depth);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderLevels(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderLevels(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint levels) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->levels((uint8_t) levels);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderSampler(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderSampler(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint sampler) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->sampler((Texture::Sampler) sampler);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderFormat(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderFormat(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jint format) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->format((Texture::InternalFormat) format);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderRgbm(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderRgbm(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jboolean enable) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
builder->rgbm(enable);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jlong nativeEngine) {
|
||||
Texture::Builder *builder = (Texture::Builder *) nativeBuilder;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
@@ -118,60 +122,60 @@ Java_com_google_android_filament_Texture_nBuilderBuild(JNIEnv *env, jclass type,
|
||||
// Texture...
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetWidth(JNIEnv *env, jclass type, jlong nativeTexture,
|
||||
Java_com_google_android_filament_Texture_nGetWidth(JNIEnv*, jclass, jlong nativeTexture,
|
||||
jint level) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getWidth((size_t) level);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetHeight(JNIEnv *env, jclass type, jlong nativeTexture,
|
||||
Java_com_google_android_filament_Texture_nGetHeight(JNIEnv*, jclass, jlong nativeTexture,
|
||||
jint level) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getHeight((size_t) level);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetDepth(JNIEnv *env, jclass type, jlong nativeTexture,
|
||||
Java_com_google_android_filament_Texture_nGetDepth(JNIEnv*, jclass, jlong nativeTexture,
|
||||
jint level) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getDepth((size_t) level);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetLevels(JNIEnv *env, jclass type, jlong nativeTexture) {
|
||||
Java_com_google_android_filament_Texture_nGetLevels(JNIEnv*, jclass, jlong nativeTexture) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getLevels();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetTarget(JNIEnv *env, jclass type, jlong nativeTexture) {
|
||||
Java_com_google_android_filament_Texture_nGetTarget(JNIEnv*, jclass, jlong nativeTexture) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getTarget();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetInternalFormat(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nGetInternalFormat(JNIEnv*, jclass,
|
||||
jlong nativeTexture) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return (jint) texture->getFormat();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Texture_nGetRgbm(JNIEnv *env, jclass type, jlong nativeTexture) {
|
||||
Java_com_google_android_filament_Texture_nGetRgbm(JNIEnv*, jclass, jlong nativeTexture) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
return texture->isRgbm();
|
||||
return static_cast<jboolean>(texture->isRgbm());
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetImage(JNIEnv *env, jclass type_, jlong nativeTexture,
|
||||
Java_com_google_android_filament_Texture_nSetImage(JNIEnv* env, jclass, jlong nativeTexture,
|
||||
jlong nativeEngine, jint level, jint xoffset, jint yoffset, jint width, jint height,
|
||||
jobject storage, jint remaining,
|
||||
jint left, jint bottom, jint type, jint alignment,
|
||||
jint stride, jint format,
|
||||
jobject handler, jobject runnable) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
|
||||
size_t sizeInBytes = getTextureDataSize(texture, (size_t) level, (Texture::Format) format,
|
||||
(Texture::Type) type, (size_t) stride, (size_t) alignment);
|
||||
@@ -196,9 +200,9 @@ Java_com_google_android_filament_Texture_nSetImage(JNIEnv *env, jclass type_, jl
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetImageCompressed(JNIEnv *env, jclass type_, jlong nativeTexture,
|
||||
jlong nativeEngine, jint level, jint xoffset, jint yoffset, jint width, jint height,
|
||||
jobject storage, jint remaining,
|
||||
Java_com_google_android_filament_Texture_nSetImageCompressed(JNIEnv *env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jint level, jint xoffset, jint yoffset,
|
||||
jint width, jint height, jobject storage, jint remaining,
|
||||
jint left, jint bottom, jint type, jint alignment,
|
||||
jint compressedSizeInBytes, jint compressedFormat,
|
||||
jobject handler, jobject runnable) {
|
||||
@@ -227,7 +231,7 @@ Java_com_google_android_filament_Texture_nSetImageCompressed(JNIEnv *env, jclass
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetImageCubemap(JNIEnv *env, jclass type_,
|
||||
Java_com_google_android_filament_Texture_nSetImageCubemap(JNIEnv *env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jint level, jobject storage, jint remaining,
|
||||
jint left, jint bottom, jint type, jint alignment, jint stride, jint format,
|
||||
jintArray faceOffsetsInBytes_,
|
||||
@@ -262,7 +266,7 @@ Java_com_google_android_filament_Texture_nSetImageCubemap(JNIEnv *env, jclass ty
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetImageCubemapCompressed(JNIEnv *env, jclass type_,
|
||||
Java_com_google_android_filament_Texture_nSetImageCubemapCompressed(JNIEnv *env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jint level, jobject storage, jint remaining,
|
||||
jint left, jint bottom, jint type, jint alignment,
|
||||
jint compressedSizeInBytes, jint compressedFormat, jintArray faceOffsetsInBytes_,
|
||||
@@ -297,14 +301,15 @@ Java_com_google_android_filament_Texture_nSetImageCubemapCompressed(JNIEnv *env,
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetExternalImage(JNIEnv*, jclass, jlong nativeTexture, jlong nativeEngine, jlong eglImage) {
|
||||
Java_com_google_android_filament_Texture_nSetExternalImage(JNIEnv*, jclass, jlong nativeTexture,
|
||||
jlong nativeEngine, jlong eglImage) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
texture->setExternalImage(*engine, (void*)eglImage);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nSetExternalStream(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nSetExternalStream(JNIEnv*, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jlong nativeStream) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
@@ -313,7 +318,7 @@ Java_com_google_android_filament_Texture_nSetExternalStream(JNIEnv *env, jclass
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Texture_nGenerateMipmaps(JNIEnv *env, jclass type,
|
||||
Java_com_google_android_filament_Texture_nGenerateMipmaps(JNIEnv*, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine) {
|
||||
Texture *texture = (Texture *) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
@@ -323,9 +328,113 @@ Java_com_google_android_filament_Texture_nGenerateMipmaps(JNIEnv *env, jclass ty
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Texture_nIsStreamValidForTexture(JNIEnv*, jclass,
|
||||
jlong nativeTexture, jlong nativeStream) {
|
||||
jlong nativeTexture, jlong) {
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
Stream* stream = (Stream*) nativeStream;
|
||||
return (jboolean) (texture->getTarget() == SamplerType::SAMPLER_EXTERNAL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ANDROID SPECIFIC BITS
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
#define BITMAP_CONFIG_ALPHA_8 0
|
||||
#define BITMAP_CONFIG_RGB_565 1
|
||||
#define BITMAP_CONFIG_RGBA_4444 2
|
||||
#define BITMAP_CONFIG_RGBA_8888 3
|
||||
#define BITMAP_CONFIG_RGBA_F16 4
|
||||
#define BITMAP_CONFIG_HARDWARE 5
|
||||
|
||||
class AutoBitmap {
|
||||
public:
|
||||
AutoBitmap(JNIEnv* env, jobject bitmap) noexcept
|
||||
: mEnv(env)
|
||||
, mBitmap(env->NewGlobalRef(bitmap))
|
||||
{
|
||||
if (mBitmap) {
|
||||
AndroidBitmap_getInfo(mEnv, mBitmap, &mInfo);
|
||||
AndroidBitmap_lockPixels(mEnv, mBitmap, &mData);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoBitmap() noexcept {
|
||||
if (mBitmap) {
|
||||
AndroidBitmap_unlockPixels(mEnv, mBitmap);
|
||||
mEnv->DeleteGlobalRef(mBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
AutoBitmap(AutoBitmap &&rhs) noexcept {
|
||||
mEnv = rhs.mEnv;
|
||||
std::swap(mData, rhs.mData);
|
||||
std::swap(mBitmap, rhs.mBitmap);
|
||||
std::swap(mInfo, rhs.mInfo);
|
||||
}
|
||||
|
||||
void* getData() const noexcept {
|
||||
return mData;
|
||||
}
|
||||
|
||||
size_t getSizeInBytes() const noexcept {
|
||||
return mInfo.height * mInfo.stride;
|
||||
}
|
||||
|
||||
PixelDataFormat getFormat(int format) const noexcept {
|
||||
// AndroidBitmapInfo does not capture the HARDWARE and RGBA_F16 formats
|
||||
// so we switch on the Bitmap.Config values directly
|
||||
switch (format) {
|
||||
case BITMAP_CONFIG_ALPHA_8: return PixelDataFormat::ALPHA;
|
||||
case BITMAP_CONFIG_RGB_565: return PixelDataFormat::RGB;
|
||||
default: return PixelDataFormat::RGBA;
|
||||
}
|
||||
}
|
||||
|
||||
PixelDataType getType(int format) const noexcept {
|
||||
switch (format) {
|
||||
case BITMAP_CONFIG_RGBA_F16: return PixelDataType::HALF;
|
||||
default: return PixelDataType::UBYTE;
|
||||
}
|
||||
}
|
||||
|
||||
static void invoke(void* buffer, size_t n, void* user) {
|
||||
AutoBitmap* data = reinterpret_cast<AutoBitmap*>(user);
|
||||
data->~AutoBitmap();
|
||||
}
|
||||
|
||||
static AutoBitmap* make(Engine* engine, JNIEnv* env, jobject bitmap) {
|
||||
void* that = engine->streamAlloc(sizeof(AutoBitmap), alignof(AutoBitmap));
|
||||
return new (that) AutoBitmap(env, bitmap);
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* mEnv;
|
||||
void* mData = nullptr;
|
||||
jobject mBitmap = nullptr;
|
||||
AndroidBitmapInfo mInfo;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_android_TextureHelper_nSetBitmap(JNIEnv* env, jclass,
|
||||
jlong nativeTexture, jlong nativeEngine, jint level, jint xoffset, jint yoffset,
|
||||
jint width, jint height, jobject bitmap, jint format) {
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
auto* autoBitmap = AutoBitmap::make(engine, env, bitmap);
|
||||
|
||||
Texture::PixelBufferDescriptor desc(
|
||||
autoBitmap->getData(),
|
||||
autoBitmap->getSizeInBytes(),
|
||||
autoBitmap->getFormat(format),
|
||||
autoBitmap->getType(format),
|
||||
&AutoBitmap::invoke, autoBitmap);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
(uint32_t) width, (uint32_t) height,
|
||||
std::move(desc));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "NotReleasedValue"
|
||||
extern "C" {
|
||||
void *getNativeWindow(JNIEnv *env, jclass klass, jobject surface) {
|
||||
void *win = nullptr;
|
||||
@@ -40,7 +42,7 @@ void *getNativeWindow(JNIEnv *env, jclass klass, jobject surface) {
|
||||
view.wantsLayer = true;
|
||||
[jawldsip setLayer:view.layer];
|
||||
|
||||
win = (void*)view;
|
||||
win = (void*) view;
|
||||
releaseDrawingSurface(ds, dsi);
|
||||
return win;
|
||||
}
|
||||
@@ -48,7 +50,7 @@ void *getNativeWindow(JNIEnv *env, jclass klass, jobject surface) {
|
||||
jlong createNativeSurface(jint width, jint height) {
|
||||
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, width, height)];
|
||||
view.wantsLayer = true;
|
||||
return (jlong)view;
|
||||
return (jlong) view;
|
||||
}
|
||||
|
||||
void destroyNativeSurface(jlong surface) {
|
||||
@@ -57,3 +59,4 @@ void destroyNativeSurface(jlong surface) {
|
||||
}
|
||||
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@@ -25,65 +25,83 @@ static std::vector<int> jawtVersions = {
|
||||
0x00010009,
|
||||
};
|
||||
|
||||
bool acquireDrawingSurface(JNIEnv *env, jobject surface, JAWT_DrawingSurface** ods,
|
||||
JAWT_DrawingSurfaceInfo** odsi) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wuninitialized"
|
||||
bool acquireDrawingSurface(JNIEnv* env, jobject surface,
|
||||
JAWT_DrawingSurface** ods, JAWT_DrawingSurfaceInfo** odsi) {
|
||||
|
||||
JAWT awt;
|
||||
JAWT_DrawingSurface *ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo *dsi = nullptr;
|
||||
JAWT_DrawingSurface* ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo* dsi = nullptr;
|
||||
|
||||
// Search for a valid AWT
|
||||
jboolean foundJawt = false;
|
||||
for(int jawtVersion : jawtVersions) {
|
||||
jboolean foundJawt = JNI_FALSE;
|
||||
for (int jawtVersion : jawtVersions) {
|
||||
awt.version = jawtVersion;
|
||||
foundJawt = JAWT_GetAWT(env, &awt);
|
||||
if (foundJawt == JNI_TRUE) {
|
||||
#ifndef NDEBUG
|
||||
printf("Found valid AWT v%08x.\n", jawtVersion);
|
||||
#endif
|
||||
break;
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
printf("AWT v%08x not present.\n", jawtVersion);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
if (foundJawt == JNI_FALSE) {
|
||||
printf("AWT Not found\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the drawing surface
|
||||
ds = awt.GetDrawingSurface(env, surface);
|
||||
if (ds == NULL) {
|
||||
if (ds == nullptr) {
|
||||
#ifndef NDEBUG
|
||||
printf("NULL drawing surface\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock the drawing
|
||||
jint lock = ds->Lock(ds);
|
||||
if ((lock & JAWT_LOCK_ERROR) != 0) {
|
||||
#ifndef NDEBUG
|
||||
printf("Error locking surface\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
awt.FreeDrawingSurface(ds);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the drawing surface info
|
||||
dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
if (dsi == NULL) {
|
||||
if (dsi == nullptr) {
|
||||
#ifndef NDEBUG
|
||||
printf("Error getting surface info\n");
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
ds->Unlock(ds);
|
||||
awt.FreeDrawingSurface(ds);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
*odsi = dsi;
|
||||
*ods = ds;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void releaseDrawingSurface(JAWT_DrawingSurface *ds, JAWT_DrawingSurfaceInfo *dsi) {
|
||||
return true;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void releaseDrawingSurface(JAWT_DrawingSurface* ds, JAWT_DrawingSurfaceInfo* dsi) {
|
||||
// Free the drawing surface info
|
||||
ds->FreeDrawingSurfaceInfo(dsi);
|
||||
// Unlock the drawing surface
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <jawt.h>
|
||||
|
||||
extern "C" {
|
||||
bool acquireDrawingSurface(JNIEnv *env, jobject obj, JAWT_DrawingSurface** ds,
|
||||
JAWT_DrawingSurfaceInfo** dsi);
|
||||
bool acquireDrawingSurface(JNIEnv* env, jobject surface, JAWT_DrawingSurface** ods,
|
||||
JAWT_DrawingSurfaceInfo** odsi);
|
||||
void releaseDrawingSurface(JAWT_DrawingSurface* ds, JAWT_DrawingSurfaceInfo* dsi);
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
#include<GL/glx.h>
|
||||
|
||||
extern "C" {
|
||||
void *getNativeWindow(JNIEnv *env, jclass, jobject surface) {
|
||||
void *win = nullptr;
|
||||
JAWT_DrawingSurface *ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo *dsi = nullptr;
|
||||
void *getNativeWindow(JNIEnv* env, jclass, jobject surface) {
|
||||
void* win = nullptr;
|
||||
JAWT_DrawingSurface* ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo* dsi = nullptr;
|
||||
|
||||
if (!acquireDrawingSurface(env, surface, &ds, &dsi)) {
|
||||
return win;
|
||||
}
|
||||
JAWT_X11DrawingSurfaceInfo *dsi_x11 = (JAWT_X11DrawingSurfaceInfo *) dsi->platformInfo;
|
||||
JAWT_X11DrawingSurfaceInfo* dsi_x11 = (JAWT_X11DrawingSurfaceInfo*) dsi->platformInfo;
|
||||
|
||||
win = (void *) dsi_x11->drawable;
|
||||
win = (void*) dsi_x11->drawable;
|
||||
releaseDrawingSurface(ds, dsi);
|
||||
return win;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ jlong createNativeSurface(jint width, jint height) {
|
||||
XFlush(display);
|
||||
|
||||
// Camouflage the pbuffer as a window which are both XID anyway.
|
||||
return (jlong)window;
|
||||
return (jlong) window;
|
||||
}
|
||||
|
||||
void destroyNativeSurface(jlong surface) {
|
||||
@@ -88,4 +88,3 @@ void destroyNativeSurface(jlong surface) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,18 +50,22 @@ void chooseAndSetPixelFormat(HDC dc) {
|
||||
SetPixelFormat(dc, pixelFormat, &pfd);
|
||||
}
|
||||
|
||||
void *getNativeWindow(JNIEnv *env, jclass, jobject surface) {
|
||||
void *win = nullptr;
|
||||
JAWT_DrawingSurface *ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo *dsi = nullptr;
|
||||
void* getNativeWindow(JNIEnv* env, jclass, jobject surface) {
|
||||
void* win = nullptr;
|
||||
JAWT_DrawingSurface* ds = nullptr;
|
||||
JAWT_DrawingSurfaceInfo* dsi = nullptr;
|
||||
|
||||
if (!acquireDrawingSurface(env, surface, &ds, &dsi)) {
|
||||
return win;
|
||||
}
|
||||
JAWT_Win32DrawingSurfaceInfo *dsi_win32 = (JAWT_Win32DrawingSurfaceInfo *) dsi->platformInfo;
|
||||
|
||||
JAWT_Win32DrawingSurfaceInfo* dsi_win32 = (JAWT_Win32DrawingSurfaceInfo*) dsi->platformInfo;
|
||||
HDC dc = dsi_win32->hdc;
|
||||
chooseAndSetPixelFormat(dsi_win32->hdc);
|
||||
win = (void *) dsi_win32->hdc;
|
||||
|
||||
win = (void*) dsi_win32->hdc;
|
||||
releaseDrawingSurface(ds, dsi);
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
@@ -77,13 +81,15 @@ jlong createNativeSurface(jint width, jint height) {
|
||||
|
||||
HWND window = CreateWindowA("STATIC", "dummy", 0, 0, 0, width, height, NULL, NULL, NULL, NULL);
|
||||
SetWindowLong(window, GWL_STYLE, 0); //remove all window styles
|
||||
|
||||
HDC dc = GetDC(window);
|
||||
chooseAndSetPixelFormat(dc);
|
||||
return (jlong)dc;
|
||||
|
||||
return (jlong) dc;
|
||||
}
|
||||
|
||||
void destroyNativeSurface(jlong surface) {
|
||||
HDC dc = (HDC)surface;
|
||||
HDC dc = (HDC) surface;
|
||||
HWND window = WindowFromDC(dc);
|
||||
ReleaseDC(window, dc);
|
||||
DestroyWindow(window);
|
||||
|
||||
@@ -128,6 +128,10 @@ public class Stream {
|
||||
}
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return nGetTimestamp(getNativeObject());
|
||||
}
|
||||
|
||||
long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed Stream");
|
||||
@@ -153,6 +157,7 @@ public class Stream {
|
||||
Buffer storage, int remaining,
|
||||
int left, int top, int type, int alignment, int stride, int format,
|
||||
Object handler, Runnable callback);
|
||||
private static native long nGetTimestamp(long nativeStream);
|
||||
|
||||
private static native boolean nIsNative(long nativeStream);
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ public class Texture {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Builder rgbm(@NonNull boolean enabled) {
|
||||
public Builder rgbm(boolean enabled) {
|
||||
nBuilderRgbm(mNativeBuilder, enabled);
|
||||
return this;
|
||||
}
|
||||
@@ -524,7 +524,8 @@ public class Texture {
|
||||
int alignment, int compressedSizeInBytes, int compressedFormat,
|
||||
int[] faceOffsetsInBytes, Object handler, Runnable callback);
|
||||
|
||||
private static native void nSetExternalImage(long nativeObject, long nativeObject1, long eglImage);
|
||||
private static native void nSetExternalImage(
|
||||
long nativeObject, long nativeEngine, long eglImage);
|
||||
|
||||
private static native void nSetExternalStream(long nativeTexture,
|
||||
long nativeEngine, long nativeStream);
|
||||
|
||||
@@ -57,7 +57,13 @@ public class TextureSampler {
|
||||
|
||||
int mSampler = 0; // bit field used by native
|
||||
|
||||
/**
|
||||
* Min filter: LINEAR_MIPMAP_LINEAR
|
||||
* Mag filter: LINEAR
|
||||
* Wrap mode: REPEAT
|
||||
*/
|
||||
public TextureSampler() {
|
||||
this(MinFilter.LINEAR_MIPMAP_LINEAR, MagFilter.LINEAR, WrapMode.REPEAT);
|
||||
}
|
||||
|
||||
public TextureSampler(@NonNull MagFilter minMag) {
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.android;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.google.android.filament.Engine;
|
||||
import com.google.android.filament.Texture;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public final class TextureHelper {
|
||||
// Keep in sync with Texture.cpp
|
||||
private static final int BITMAP_CONFIG_ALPHA_8 = 0;
|
||||
private static final int BITMAP_CONFIG_RGB_565 = 1;
|
||||
private static final int BITMAP_CONFIG_RGBA_4444 = 2;
|
||||
private static final int BITMAP_CONFIG_RGBA_8888 = 3;
|
||||
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() {
|
||||
}
|
||||
|
||||
public static void setBitmap(@NonNull Engine engine,
|
||||
@NonNull Texture texture, @IntRange(from = 0) int level, @NonNull Bitmap bitmap) {
|
||||
setBitmap(engine, texture,
|
||||
level, 0, 0, texture.getWidth(level), texture.getHeight(level), bitmap);
|
||||
}
|
||||
|
||||
public static void setBitmap(@NonNull Engine engine,
|
||||
@NonNull Texture texture, @IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
|
||||
@IntRange(from = 0) int width, @IntRange(from = 0) int height,
|
||||
@NonNull Bitmap bitmap) {
|
||||
|
||||
int format = toNativeFormat(bitmap.getConfig());
|
||||
if (format == BITMAP_CONFIG_RGBA_4444 || format == BITMAP_CONFIG_HARDWARE) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
private static int toNativeFormat(Bitmap.Config config) {
|
||||
switch (config) {
|
||||
case ALPHA_8: return BITMAP_CONFIG_ALPHA_8;
|
||||
case RGB_565: return BITMAP_CONFIG_RGB_565;
|
||||
case ARGB_4444: return BITMAP_CONFIG_RGBA_4444;
|
||||
case ARGB_8888: return BITMAP_CONFIG_RGBA_8888;
|
||||
case RGBA_F16: return BITMAP_CONFIG_RGBA_F16;
|
||||
case HARDWARE: return BITMAP_CONFIG_HARDWARE;
|
||||
}
|
||||
return BITMAP_CONFIG_RGBA_8888;
|
||||
}
|
||||
|
||||
private static native void nSetBitmap(long nativeTexture, long nativeEngine,
|
||||
int level, int xoffset, int yoffset, int width, int height, Bitmap bitmap, int format);
|
||||
}
|
||||
@@ -126,11 +126,6 @@ public class UiHelper {
|
||||
// TODO: do something with policy
|
||||
}
|
||||
|
||||
public UiHelper(int sampleCount, RendererCallback renderCallback) {
|
||||
this();
|
||||
setRenderCallback(renderCallback);
|
||||
}
|
||||
|
||||
public void setRenderCallback(RendererCallback renderCallback) {
|
||||
mRenderCallback = renderCallback;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ Filament APIs:
|
||||
|
||||
- `hello-triangle`: Minimal example showing how to setup a rendering surface for Filament
|
||||
- `lit-cube`: Shows how to create a light and a mesh with the attributes required for lighting
|
||||
- `image-based-lighting`: Demonstrates how to create image-based lights and load complex meshes
|
||||
- `image-based-lighting`: Demonstrates how to create image-based lights and load complex meshes
|
||||
- `textured-object`: Demonstrates how to load and use textures for complex materials
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.2.70'
|
||||
ext.kotlin_version = '1.3.0'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -49,11 +49,11 @@ fun destroyIbl(engine: Engine, ibl: Ibl) {
|
||||
}
|
||||
|
||||
private fun peekSize(assets: AssetManager, name: String): Pair<Int, Int> {
|
||||
val input = assets.open(name)
|
||||
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeStream(input, null, opts)
|
||||
input.close()
|
||||
return opts.outWidth to opts.outHeight
|
||||
assets.open(name).use { input ->
|
||||
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeStream(input, null, opts)
|
||||
return opts.outWidth to opts.outHeight
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadIndirectLight(
|
||||
@@ -70,7 +70,7 @@ private fun loadIndirectLight(
|
||||
.sampler(Texture.Sampler.SAMPLER_CUBEMAP)
|
||||
.build(engine)
|
||||
|
||||
(0 until texture.levels).forEach {
|
||||
repeat(texture.levels) {
|
||||
loadCubemap(texture, assets, name, engine, "m${it}_", it)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ private fun loadSphericalHarmonics(assets: AssetManager, name: String): FloatArr
|
||||
// 3 bands = 9 RGB coefficients, so 9 * 3 floats
|
||||
val sphericalHarmonics = FloatArray(9 * 3)
|
||||
BufferedReader(InputStreamReader(assets.open("$name/sh.txt"))).use { input ->
|
||||
(0 until 9).forEach { i ->
|
||||
repeat(9) { i ->
|
||||
val line = input.readLine()
|
||||
re.find(line)?.let {
|
||||
sphericalHarmonics[i * 3] = it.groups[1]?.value?.toFloat() ?: 0.0f
|
||||
@@ -133,7 +133,7 @@ private fun loadCubemap(texture: Texture,
|
||||
// Allocate enough memory for all the cubemap faces
|
||||
val storage = ByteBuffer.allocateDirect(faceSize * 6)
|
||||
|
||||
arrayOf("px", "nx", "py", "ny", "pz", "nz").forEachIndexed { _, suffix ->
|
||||
arrayOf("px", "nx", "py", "ny", "pz", "nz").forEach { suffix ->
|
||||
assets.open("$name/$prefix$suffix.rgbm").use {
|
||||
val bitmap = BitmapFactory.decodeStream(it, null, opts)
|
||||
bitmap?.copyPixelsToBuffer(storage)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.2.70'
|
||||
ext.kotlin_version = '1.3.0'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -291,7 +291,7 @@ class MainActivity : Activity() {
|
||||
// Create the indices
|
||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
(0..5).forEach {
|
||||
repeat(5) {
|
||||
val i = (it * 4).toShort()
|
||||
indexData
|
||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.2.70'
|
||||
ext.kotlin_version = '1.3.0'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
13
android/samples/textured-object/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
/.idea/caches
|
||||
/.idea/gradle.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
/app/src/main/assets/materials/*.filamat
|
||||
/app/src/main/assets/envs
|
||||
.externalNativeBuild
|
||||
1
android/samples/textured-object/app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
98
android/samples/textured-object/app/build.gradle
Normal file
@@ -0,0 +1,98 @@
|
||||
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")
|
||||
}
|
||||
|
||||
compileMesh {
|
||||
group 'Filament'
|
||||
description 'Compile mesh'
|
||||
|
||||
inputFile = file("../../../../third_party/shader_ball/shader_ball.obj")
|
||||
outputDir = file("src/main/assets/models")
|
||||
}
|
||||
|
||||
generateIbl {
|
||||
group 'Filament'
|
||||
description 'Generate IBL'
|
||||
|
||||
inputFile = file("../../../../third_party/environments/venetian_crossroads_2k.hdr")
|
||||
outputDir = file("src/main/assets/envs")
|
||||
}
|
||||
|
||||
preBuild.dependsOn compileMaterials
|
||||
preBuild.dependsOn compileMesh
|
||||
preBuild.dependsOn generateIbl
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.textured"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 28
|
||||
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'
|
||||
}
|
||||
21
android/samples/textured-object/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,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.filament.textured">
|
||||
|
||||
<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="com.google.android.filament.textured.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,148 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.textured
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import android.graphics.BitmapFactory
|
||||
|
||||
import com.google.android.filament.Engine
|
||||
import com.google.android.filament.IndirectLight
|
||||
import com.google.android.filament.Skybox
|
||||
import com.google.android.filament.Texture
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
import kotlin.math.log2
|
||||
|
||||
data class Ibl(val indirectLight: IndirectLight,
|
||||
val indirectLightTexture: Texture,
|
||||
val skybox: Skybox,
|
||||
val skyboxTexture: Texture)
|
||||
|
||||
fun loadIbl(assets: AssetManager, name: String, engine: Engine): Ibl {
|
||||
val (ibl, iblTexture) = loadIndirectLight(assets, name, engine)
|
||||
val (skybox, skyboxTexture) = loadSkybox(assets, name, engine)
|
||||
return Ibl(ibl, iblTexture, skybox, skyboxTexture)
|
||||
}
|
||||
|
||||
fun destroyIbl(engine: Engine, ibl: Ibl) {
|
||||
engine.destroySkybox(ibl.skybox)
|
||||
engine.destroyTexture(ibl.skyboxTexture)
|
||||
engine.destroyIndirectLight(ibl.indirectLight)
|
||||
engine.destroyTexture(ibl.indirectLightTexture)
|
||||
}
|
||||
|
||||
private fun peekSize(assets: AssetManager, name: String): Pair<Int, Int> {
|
||||
assets.open(name).use { input ->
|
||||
val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeStream(input, null, opts)
|
||||
return opts.outWidth to opts.outHeight
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadIndirectLight(
|
||||
assets: AssetManager,
|
||||
name: String,
|
||||
engine: Engine): Pair<IndirectLight, Texture> {
|
||||
val (w, h) = peekSize(assets, "$name/nx.rgbm")
|
||||
val texture = Texture.Builder()
|
||||
.width(w)
|
||||
.height(h)
|
||||
.levels(log2(w.toFloat()).toInt() + 1)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.rgbm(true)
|
||||
.sampler(Texture.Sampler.SAMPLER_CUBEMAP)
|
||||
.build(engine)
|
||||
|
||||
repeat(texture.levels) {
|
||||
loadCubemap(texture, assets, name, engine, "m${it}_", it)
|
||||
}
|
||||
|
||||
val sphericalHarmonics = loadSphericalHarmonics(assets, name)
|
||||
|
||||
return IndirectLight.Builder()
|
||||
.reflections(texture)
|
||||
.irradiance(3, sphericalHarmonics)
|
||||
.intensity(30_000.0f)
|
||||
.build(engine) to texture
|
||||
}
|
||||
|
||||
private fun loadSphericalHarmonics(assets: AssetManager, name: String): FloatArray {
|
||||
val re = Regex("""\(\s*([+-]?\d+\.\d+),\s*([+-]?\d+\.\d+),\s*([+-]?\d+\.\d+)\);""")
|
||||
// 3 bands = 9 RGB coefficients, so 9 * 3 floats
|
||||
val sphericalHarmonics = FloatArray(9 * 3)
|
||||
BufferedReader(InputStreamReader(assets.open("$name/sh.txt"))).use { input ->
|
||||
repeat(9) { i ->
|
||||
val line = input.readLine()
|
||||
re.find(line)?.let {
|
||||
sphericalHarmonics[i * 3] = it.groups[1]?.value?.toFloat() ?: 0.0f
|
||||
sphericalHarmonics[i * 3 + 1] = it.groups[2]?.value?.toFloat() ?: 0.0f
|
||||
sphericalHarmonics[i * 3 + 2] = it.groups[3]?.value?.toFloat() ?: 0.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
return sphericalHarmonics
|
||||
}
|
||||
|
||||
private fun loadSkybox(assets: AssetManager, name: String, engine: Engine): Pair<Skybox, Texture> {
|
||||
val (w, h) = peekSize(assets, "$name/nx.rgbm")
|
||||
val texture = Texture.Builder()
|
||||
.width(w)
|
||||
.height(h)
|
||||
.levels(1)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.rgbm(true)
|
||||
.sampler(Texture.Sampler.SAMPLER_CUBEMAP)
|
||||
.build(engine)
|
||||
|
||||
loadCubemap(texture, assets, name, engine)
|
||||
|
||||
return Skybox.Builder().environment(texture).build(engine) to texture
|
||||
}
|
||||
|
||||
private fun loadCubemap(texture: Texture,
|
||||
assets: AssetManager,
|
||||
name: String,
|
||||
engine: Engine,
|
||||
prefix: String = "",
|
||||
level: Int = 0) {
|
||||
// This is important, in the RGBM format the alpha channel does not encode
|
||||
// opacity but a scale factor (to represent HDR data). We must tell Android
|
||||
// to not premultiply the RGB channels by the alpha channel
|
||||
val opts = BitmapFactory.Options().apply { inPremultiplied = false }
|
||||
|
||||
// RGBM is always 4 bytes per pixel
|
||||
val faceSize = texture.getWidth(level) * texture.getHeight(level) * 4
|
||||
val offsets = IntArray(6) { it * faceSize }
|
||||
// Allocate enough memory for all the cubemap faces
|
||||
val storage = ByteBuffer.allocateDirect(faceSize * 6)
|
||||
|
||||
arrayOf("px", "nx", "py", "ny", "pz", "nz").forEach { suffix ->
|
||||
assets.open("$name/$prefix$suffix.rgbm").use {
|
||||
val bitmap = BitmapFactory.decodeStream(it, null, opts)
|
||||
bitmap?.copyPixelsToBuffer(storage)
|
||||
}
|
||||
}
|
||||
|
||||
// Rewind the texture buffer
|
||||
storage.flip()
|
||||
|
||||
val buffer = Texture.PixelBufferDescriptor(storage, Texture.Format.RGBM, Texture.Type.UBYTE)
|
||||
texture.setImage(engine, level, buffer, offsets)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.textured
|
||||
|
||||
import java.io.InputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
fun readIntLE(input: InputStream): Int {
|
||||
return input.read() and 0xff or (
|
||||
input.read() and 0xff shl 8) or (
|
||||
input.read() and 0xff shl 16) or (
|
||||
input.read() and 0xff shl 24)
|
||||
}
|
||||
|
||||
fun readFloat32LE(input: InputStream): Float {
|
||||
val bytes = ByteArray(4)
|
||||
input.read(bytes, 0, 4)
|
||||
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).float
|
||||
}
|
||||
|
||||
fun readUIntLE(input: InputStream): Long {
|
||||
return readIntLE(input).toLong() and 0xFFFFFFFFL
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.textured
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceView
|
||||
import android.view.animation.LinearInterpolator
|
||||
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.android.UiHelper
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.Channels
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class MainActivity : Activity() {
|
||||
// Make sure to initialize Filament first
|
||||
// This loads the JNI library needed by most API calls
|
||||
companion object {
|
||||
init {
|
||||
Filament.init()
|
||||
}
|
||||
}
|
||||
|
||||
// The View we want to render into
|
||||
private lateinit var surfaceView: SurfaceView
|
||||
// UiHelper is provided by Filament to manage SurfaceView and SurfaceTexture
|
||||
private lateinit var uiHelper: UiHelper
|
||||
// Choreographer is used to schedule new frames
|
||||
private lateinit var choreographer: Choreographer
|
||||
|
||||
// Engine creates and destroys Filament resources
|
||||
// Each engine must be accessed from a single thread of your choosing
|
||||
// Resources cannot be shared across engines
|
||||
private lateinit var engine: Engine
|
||||
// A renderer instance is tied to a single surface (SurfaceView, TextureView, etc.)
|
||||
private lateinit var renderer: Renderer
|
||||
// A scene holds all the renderable, lights, etc. to be drawn
|
||||
private lateinit var scene: Scene
|
||||
// A view defines a viewport, a scene and a camera for rendering
|
||||
private lateinit var view: View
|
||||
// Should be pretty obvious :)
|
||||
private lateinit var camera: Camera
|
||||
|
||||
private lateinit var material: Material
|
||||
private lateinit var materialInstance: MaterialInstance
|
||||
|
||||
private lateinit var baseColor: Texture
|
||||
private lateinit var normal: Texture
|
||||
private lateinit var aoRoughnessMetallic: Texture
|
||||
|
||||
private lateinit var mesh: Mesh
|
||||
private lateinit var ibl: Ibl
|
||||
|
||||
// Filament entity representing a renderable object
|
||||
@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, (2.0 * PI).toFloat())
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
surfaceView = SurfaceView(this)
|
||||
setContentView(surfaceView)
|
||||
|
||||
choreographer = Choreographer.getInstance()
|
||||
|
||||
setupSurfaceView()
|
||||
setupFilament()
|
||||
setupView()
|
||||
setupScene()
|
||||
}
|
||||
|
||||
private fun setupSurfaceView() {
|
||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
|
||||
// NOTE: To choose a specific rendering resolution, add the following line:
|
||||
// uiHelper.setDesiredSize(1280, 720)
|
||||
|
||||
uiHelper.attachTo(surfaceView)
|
||||
}
|
||||
|
||||
private fun setupFilament() {
|
||||
engine = Engine.create()
|
||||
renderer = engine.createRenderer()
|
||||
scene = engine.createScene()
|
||||
view = engine.createView()
|
||||
camera = engine.createCamera()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
// Clear the background to middle-grey
|
||||
// Setting up a clear color is useful for debugging but usually
|
||||
// unnecessary when using a skybox
|
||||
view.setClearColor(0.035f, 0.035f, 0.035f, 1.0f)
|
||||
|
||||
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
|
||||
// view.isPostProcessingEnabled = false
|
||||
|
||||
// Tell the view which camera we want to use
|
||||
view.camera = camera
|
||||
|
||||
// Tell the view which scene we want to render
|
||||
view.scene = scene
|
||||
|
||||
// Enable dynamic resolution with a default target frame rate of 60fps
|
||||
val options = View.DynamicResolutionOptions()
|
||||
options.enabled = true
|
||||
|
||||
view.dynamicResolutionOptions = options
|
||||
}
|
||||
|
||||
private fun setupScene() {
|
||||
loadMaterial()
|
||||
setupMaterial()
|
||||
loadImageBasedLight()
|
||||
|
||||
scene.skybox = ibl.skybox
|
||||
scene.indirectLight = ibl.indirectLight
|
||||
|
||||
// This map can contain named materials that will map to the material names
|
||||
// loaded from the filamesh file. The material called "DefaultMaterial" is
|
||||
// applied when no named material can be found
|
||||
val materials = mapOf("DefaultMaterial" to materialInstance)
|
||||
|
||||
// Load the mesh in the filamesh format (see filamesh tool)
|
||||
mesh = loadMesh(assets, "models/shader_ball.filamesh", materials, engine)
|
||||
|
||||
// Move the mesh down
|
||||
// Filament uses column-major matrices
|
||||
engine.transformManager.setTransform(engine.transformManager.getInstance(mesh.renderable),
|
||||
floatArrayOf(
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, -1.2f, 0.0f, 1.0f
|
||||
))
|
||||
|
||||
// Add the entity to the scene to render it
|
||||
scene.addEntity(mesh.renderable)
|
||||
|
||||
// We now need a light, let's create a directional light
|
||||
light = EntityManager.get().create()
|
||||
|
||||
// Create a color from a temperature (D65)
|
||||
val (r, g, b) = Colors.cct(6_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.753f, -1.0f, 0.890f)
|
||||
.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)
|
||||
|
||||
startAnimation()
|
||||
}
|
||||
|
||||
private fun loadMaterial() {
|
||||
readUncompressedAsset("materials/textured_pbr.filamat").let {
|
||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMaterial() {
|
||||
// Create an instance of the material to set different parameters on it
|
||||
materialInstance = material.createInstance()
|
||||
|
||||
// Note that the textures are stored in drawable-nodpi to prevent the system
|
||||
// from automatically resizing them based on the display's density
|
||||
baseColor = loadTexture(engine, resources, R.drawable.floor_basecolor, TextureType.COLOR)
|
||||
normal = loadTexture(engine, resources, R.drawable.floor_normal, TextureType.NORMAL)
|
||||
aoRoughnessMetallic = loadTexture(engine, resources,
|
||||
R.drawable.floor_ao_roughness_metallic, TextureType.DATA)
|
||||
|
||||
// A texture sampler does not need to be kept around or destroyed
|
||||
val sampler = TextureSampler()
|
||||
sampler.anisotropy = 8.0f
|
||||
|
||||
materialInstance.setParameter("baseColor", baseColor, sampler)
|
||||
materialInstance.setParameter("normal", normal, sampler)
|
||||
materialInstance.setParameter("aoRoughnessMetallic", aoRoughnessMetallic, sampler)
|
||||
}
|
||||
|
||||
private fun loadImageBasedLight() {
|
||||
ibl = loadIbl(assets, "envs/venetian_crossroads_2k", engine)
|
||||
ibl.indirectLight.intensity = 40_000.0f
|
||||
}
|
||||
|
||||
private fun startAnimation() {
|
||||
// Animate the triangle
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.duration = 18_000
|
||||
animator.repeatMode = ValueAnimator.RESTART
|
||||
animator.repeatCount = ValueAnimator.INFINITE
|
||||
animator.addUpdateListener { a ->
|
||||
val v = (a.animatedValue as Float)
|
||||
camera.lookAt(cos(v) * 4.5, 1.5, sin(v) * 4.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
||||
}
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
choreographer.postFrameCallback(frameScheduler)
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
// 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
|
||||
Fence.waitAndDestroy(engine.createFence(Fence.Type.SOFT), Fence.Mode.FLUSH)
|
||||
|
||||
// Cleanup all resources
|
||||
destroyMesh(engine, mesh)
|
||||
destroyIbl(engine, ibl)
|
||||
engine.destroyTexture(baseColor)
|
||||
engine.destroyTexture(normal)
|
||||
engine.destroyTexture(aoRoughnessMetallic)
|
||||
engine.destroyEntity(light)
|
||||
engine.destroyRenderer(renderer)
|
||||
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)
|
||||
|
||||
// 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(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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.textured
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import android.util.Log
|
||||
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.VertexBuffer.AttributeType.*
|
||||
import com.google.android.filament.VertexBuffer.VertexAttribute.*
|
||||
|
||||
import java.io.InputStream
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.channels.Channels
|
||||
import java.nio.channels.ReadableByteChannel
|
||||
|
||||
data class Mesh(
|
||||
@Entity val renderable: Int,
|
||||
val indexBuffer: IndexBuffer,
|
||||
val vertexBuffer: VertexBuffer,
|
||||
val aabb: Box)
|
||||
|
||||
fun destroyMesh(engine: Engine, mesh: Mesh) {
|
||||
engine.destroyEntity(mesh.renderable)
|
||||
engine.destroyIndexBuffer(mesh.indexBuffer)
|
||||
engine.destroyVertexBuffer(mesh.vertexBuffer)
|
||||
EntityManager.get().destroy(mesh.renderable)
|
||||
}
|
||||
|
||||
fun loadMesh(assets: AssetManager, name: String,
|
||||
materials: Map<String, MaterialInstance>, engine: Engine): Mesh {
|
||||
// See tools/filamesh/README.md for a description of the filamesh file format
|
||||
assets.open(name).use { input ->
|
||||
val header = readHeader(input)
|
||||
|
||||
val channel = Channels.newChannel(input)
|
||||
val vertexBufferData = readSizedData(channel, header.verticesSizeInBytes)
|
||||
val indexBufferData = readSizedData(channel, header.indicesSizeInBytes)
|
||||
|
||||
val parts = readParts(header, input)
|
||||
val definedMaterials = readMaterials(input)
|
||||
|
||||
val indexBuffer = createIndexBuffer(engine, header, indexBufferData)
|
||||
val vertexBuffer = createVertexBuffer(engine, header, vertexBufferData)
|
||||
|
||||
val renderable = createRenderable(
|
||||
engine, header, indexBuffer, vertexBuffer, parts, definedMaterials, materials)
|
||||
|
||||
return Mesh(renderable, indexBuffer, vertexBuffer, header.aabb)
|
||||
}
|
||||
}
|
||||
|
||||
private const val FILAMESH_FILE_IDENTIFIER = "FILAMESH"
|
||||
private const val MAX_UINT32 = 4294967295
|
||||
|
||||
private class Header {
|
||||
var valid = false
|
||||
var versionNumber = 0L
|
||||
var parts = 0L
|
||||
var aabb = Box()
|
||||
var interleaved = 0L
|
||||
var posOffset = 0L
|
||||
var positionStride = 0L
|
||||
var tangentOffset = 0L
|
||||
var tangentStride = 0L
|
||||
var colorOffset = 0L
|
||||
var colorStride = 0L
|
||||
var uv0Offset = 0L
|
||||
var uv0Stride = 0L
|
||||
var uv1Offset = 0L
|
||||
var uv1Stride = 0L
|
||||
var totalVertices = 0L
|
||||
var verticesSizeInBytes = 0L
|
||||
var indices16Bit = 0L
|
||||
var totalIndices = 0L
|
||||
var indicesSizeInBytes = 0L
|
||||
}
|
||||
|
||||
private class Part {
|
||||
var offset = 0L
|
||||
var indexCount = 0L
|
||||
var minIndex = 0L
|
||||
var maxIndex = 0L
|
||||
var materialID = 0L
|
||||
var aabb = Box()
|
||||
}
|
||||
|
||||
private fun readMagicNumber(input: InputStream): Boolean {
|
||||
val temp = ByteArray(FILAMESH_FILE_IDENTIFIER.length)
|
||||
input.read(temp)
|
||||
val tempS = String(temp, Charset.forName("UTF-8"))
|
||||
return tempS == FILAMESH_FILE_IDENTIFIER
|
||||
}
|
||||
|
||||
private fun readHeader(input: InputStream): Header {
|
||||
val header = Header()
|
||||
|
||||
if (!readMagicNumber(input)) {
|
||||
Log.e("Filament", "Invalid filamesh file.")
|
||||
return header
|
||||
}
|
||||
|
||||
header.versionNumber = readUIntLE(input)
|
||||
header.parts = readUIntLE(input)
|
||||
header.aabb = Box(
|
||||
readFloat32LE(input), readFloat32LE(input), readFloat32LE(input),
|
||||
readFloat32LE(input), readFloat32LE(input), readFloat32LE(input))
|
||||
header.interleaved = readUIntLE(input)
|
||||
header.posOffset = readUIntLE(input)
|
||||
header.positionStride = readUIntLE(input)
|
||||
header.tangentOffset = readUIntLE(input)
|
||||
header.tangentStride = readUIntLE(input)
|
||||
header.colorOffset = readUIntLE(input)
|
||||
header.colorStride = readUIntLE(input)
|
||||
header.uv0Offset = readUIntLE(input)
|
||||
header.uv0Stride = readUIntLE(input)
|
||||
header.uv1Offset = readUIntLE(input)
|
||||
header.uv1Stride = readUIntLE(input)
|
||||
header.totalVertices = readUIntLE(input)
|
||||
header.verticesSizeInBytes = readUIntLE(input)
|
||||
header.indices16Bit = readUIntLE(input)
|
||||
header.totalIndices = readUIntLE(input)
|
||||
header.indicesSizeInBytes = readUIntLE(input)
|
||||
|
||||
header.valid = true
|
||||
return header
|
||||
}
|
||||
|
||||
|
||||
private fun readSizedData(channel: ReadableByteChannel, sizeInBytes: Long): ByteBuffer {
|
||||
val buffer = ByteBuffer.allocateDirect(sizeInBytes.toInt())
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||
channel.read(buffer)
|
||||
buffer.flip()
|
||||
return buffer
|
||||
}
|
||||
|
||||
private fun readParts(header: Header, input: InputStream): List<Part> {
|
||||
return List(header.parts.toInt()) {
|
||||
val p = Part()
|
||||
p.offset = readUIntLE(input)
|
||||
p.indexCount = readUIntLE(input)
|
||||
p.minIndex = readUIntLE(input)
|
||||
p.maxIndex = readUIntLE(input)
|
||||
p.materialID = readUIntLE(input)
|
||||
p.aabb = Box(
|
||||
readFloat32LE(input), readFloat32LE(input), readFloat32LE(input),
|
||||
readFloat32LE(input), readFloat32LE(input), readFloat32LE(input))
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
private fun readMaterials(input: InputStream): List<String> {
|
||||
return List(readUIntLE(input).toInt()) {
|
||||
val data = ByteArray(readUIntLE(input).toInt())
|
||||
input.read(data)
|
||||
// Skip null terminator
|
||||
input.skip(1)
|
||||
data.toString(Charset.forName("UTF-8"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIndexBuffer(engine: Engine, header: Header, data: ByteBuffer): IndexBuffer {
|
||||
val indexType = if (header.indices16Bit != 0L) {
|
||||
IndexBuffer.Builder.IndexType.USHORT
|
||||
} else {
|
||||
IndexBuffer.Builder.IndexType.UINT
|
||||
}
|
||||
|
||||
return IndexBuffer.Builder()
|
||||
.bufferType(indexType)
|
||||
.indexCount(header.totalIndices.toInt())
|
||||
.build(engine)
|
||||
.apply { setBuffer(engine, data) }
|
||||
}
|
||||
|
||||
private fun createVertexBuffer(engine: Engine, header: Header, data: ByteBuffer): VertexBuffer {
|
||||
val vertexBufferBuilder = VertexBuffer.Builder()
|
||||
.bufferCount(1)
|
||||
.vertexCount(header.totalVertices.toInt())
|
||||
// We store colors as unsigned bytes (0..255) but the shader wants values in the 0..1
|
||||
// range so we must mark this attribute normalized
|
||||
.normalized(COLOR)
|
||||
// The same goes for the tangent frame: we store it as a signed short, but we want
|
||||
// values in 0..1 in the shader
|
||||
.normalized(TANGENTS)
|
||||
.attribute(POSITION, 0, HALF4, header.posOffset.toInt(), header.positionStride.toInt())
|
||||
.attribute(TANGENTS, 0, SHORT4, header.tangentOffset.toInt(), header.tangentStride.toInt())
|
||||
.attribute(COLOR, 0, UBYTE4, header.colorOffset.toInt(), header.colorStride.toInt())
|
||||
// UV coordinates are stored in fp16, which gives sub-pixel precision only
|
||||
// for textures up to 1024x1024
|
||||
.attribute(UV0, 0, HALF2, header.uv0Offset.toInt(), header.uv0Stride.toInt())
|
||||
|
||||
if (header.uv1Offset != MAX_UINT32 && header.uv1Stride != MAX_UINT32) {
|
||||
vertexBufferBuilder
|
||||
.attribute(UV1, 0, HALF2, header.uv1Offset.toInt(), header.uv1Stride.toInt())
|
||||
}
|
||||
|
||||
return vertexBufferBuilder.build(engine).apply { setBufferAt(engine, 0, data) }
|
||||
}
|
||||
|
||||
private fun createRenderable(
|
||||
engine: Engine,
|
||||
header: Header,
|
||||
indexBuffer: IndexBuffer,
|
||||
vertexBuffer: VertexBuffer,
|
||||
parts: List<Part>,
|
||||
definedMaterials: List<String>,
|
||||
materials: Map<String, MaterialInstance>): Int {
|
||||
|
||||
val builder = RenderableManager.Builder(header.parts.toInt()).boundingBox(header.aabb)
|
||||
|
||||
repeat(header.parts.toInt()) { i ->
|
||||
builder.geometry(i,
|
||||
RenderableManager.PrimitiveType.TRIANGLES,
|
||||
vertexBuffer,
|
||||
indexBuffer,
|
||||
parts[i].offset.toInt(),
|
||||
parts[i].minIndex.toInt(),
|
||||
parts[i].maxIndex.toInt(),
|
||||
parts[i].indexCount.toInt())
|
||||
|
||||
// Find a material in the supplied material map, otherwise we fall back to
|
||||
// the default material named "DefaultMaterial"
|
||||
val material = materials[definedMaterials[parts[i].materialID.toInt()]]
|
||||
material?.let {
|
||||
builder.material(i, material)
|
||||
} ?: builder.material(i, materials["DefaultMaterial"]!!)
|
||||
}
|
||||
|
||||
return EntityManager.get().create().apply { builder.build(engine, this) }
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.textured
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import com.google.android.filament.Engine
|
||||
import com.google.android.filament.Texture
|
||||
import com.google.android.filament.android.TextureHelper
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
const val SKIP_BITMAP_COPY = true
|
||||
|
||||
enum class TextureType {
|
||||
COLOR,
|
||||
NORMAL,
|
||||
DATA
|
||||
}
|
||||
|
||||
fun loadTexture(engine: Engine, resources: Resources, resourceId: Int, type: TextureType): Texture {
|
||||
val options = BitmapFactory.Options()
|
||||
// Color is the only type of texture we want to pre-multiply with the alpha channel
|
||||
// Pre-multiplication is the default behavior, so we need to turn it off here
|
||||
options.inPremultiplied = type == TextureType.COLOR
|
||||
|
||||
val bitmap = BitmapFactory.decodeResource(resources, resourceId, options)
|
||||
|
||||
val texture = Texture.Builder()
|
||||
.width(bitmap.width)
|
||||
.height(bitmap.height)
|
||||
.sampler(Texture.Sampler.SAMPLER_2D)
|
||||
.format(internalFormat(type))
|
||||
// This tells Filament to figure out the number of mip levels
|
||||
.levels(0xff)
|
||||
.build(engine)
|
||||
|
||||
// TextureHelper offers a method that skips the copy of the bitmap into a ByteBuffer
|
||||
if (SKIP_BITMAP_COPY) {
|
||||
TextureHelper.setBitmap(engine, texture, 0, bitmap)
|
||||
} else {
|
||||
val buffer = ByteBuffer.allocateDirect(bitmap.byteCount)
|
||||
bitmap.copyPixelsToBuffer(buffer)
|
||||
// Do not forget to rewind the buffer!
|
||||
buffer.flip()
|
||||
|
||||
val descriptor = Texture.PixelBufferDescriptor(
|
||||
buffer,
|
||||
format(bitmap),
|
||||
type(bitmap))
|
||||
|
||||
texture.setImage(engine, 0, descriptor)
|
||||
}
|
||||
|
||||
texture.generateMipmaps(engine)
|
||||
|
||||
return texture
|
||||
}
|
||||
|
||||
private fun internalFormat(type: TextureType) = when (type) {
|
||||
TextureType.COLOR -> Texture.InternalFormat.SRGB8_A8
|
||||
TextureType.NORMAL -> Texture.InternalFormat.RGBA8
|
||||
TextureType.DATA -> Texture.InternalFormat.RGBA8
|
||||
}
|
||||
|
||||
// Not required when SKIP_BITMAP_COPY is true
|
||||
private fun format(bitmap: Bitmap) = when (bitmap.config) {
|
||||
Bitmap.Config.ALPHA_8 -> Texture.Format.ALPHA
|
||||
Bitmap.Config.RGB_565 -> Texture.Format.RGB
|
||||
Bitmap.Config.ARGB_8888 -> Texture.Format.RGBA
|
||||
Bitmap.Config.RGBA_F16 -> Texture.Format.RGBA
|
||||
else -> throw IllegalArgumentException("Unknown bitmap configuration")
|
||||
}
|
||||
|
||||
// Not required when SKIP_BITMAP_COPY is true
|
||||
private fun type(bitmap: Bitmap) = when (bitmap.config) {
|
||||
Bitmap.Config.ALPHA_8 -> Texture.Type.UBYTE
|
||||
Bitmap.Config.RGB_565 -> Texture.Type.UBYTE
|
||||
Bitmap.Config.ARGB_8888 -> Texture.Type.UBYTE
|
||||
Bitmap.Config.RGBA_F16 -> Texture.Type.HALF
|
||||
else -> throw IllegalArgumentException("Unsupported bitmap configuration")
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Textured material
|
||||
|
||||
material {
|
||||
name : textured_pbr,
|
||||
shadingModel : lit,
|
||||
parameters : [
|
||||
// Base color sRGB texture
|
||||
{
|
||||
type : sampler2d,
|
||||
name : baseColor
|
||||
},
|
||||
// Packed ambient occlusion/roughness/metallic RGB texture
|
||||
{
|
||||
type : sampler2d,
|
||||
name : aoRoughnessMetallic
|
||||
},
|
||||
// Normal map RGB texture
|
||||
{
|
||||
type : sampler2d,
|
||||
name : normal
|
||||
}
|
||||
],
|
||||
// To sample textures our material must declare that it requires
|
||||
// a set of UV coordinates from the rendered mesh
|
||||
requires: [
|
||||
uv0
|
||||
]
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
// The normal map must be set *before* calling prepareMaterial()
|
||||
material.normal = texture(materialParams_normal, getUV0()).xyz * 2.0 - 1.0;
|
||||
|
||||
prepareMaterial(material);
|
||||
|
||||
material.baseColor = texture(materialParams_baseColor, getUV0());
|
||||
|
||||
vec3 aoRoughnessMetallic = texture(materialParams_aoRoughnessMetallic, getUV0()).rgb;
|
||||
material.ambientOcclusion = aoRoughnessMetallic.r;
|
||||
material.roughness = aoRoughnessMetallic.g;
|
||||
material.metallic = aoRoughnessMetallic.b;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 678 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
@@ -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">Textured Object</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>
|
||||
27
android/samples/textured-object/build.gradle
Normal file
@@ -0,0 +1,27 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.0'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
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/textured-object/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/textured-object/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
android/samples/textured-object/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Tue Aug 28 15:45:13 PDT 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
|
||||
172
android/samples/textured-object/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/textured-object/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/textured-object/settings.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
includeBuild '../../filament-android'
|
||||
|
||||
include ':app'
|
||||
156
build.sh
@@ -3,8 +3,9 @@ set -e
|
||||
|
||||
# NDK API level
|
||||
API_LEVEL=24
|
||||
# Host tools required by Android and WebGL builds
|
||||
# Host tools required by Android, WebGL, and iOS builds
|
||||
HOST_TOOLS="matc cmgen filamesh mipgen"
|
||||
IOS_TOOLCHAIN_URL="https://opensource.apple.com/source/clang/clang-800.0.38/src/cmake/platforms/iOS.cmake"
|
||||
|
||||
function print_help {
|
||||
local SELF_NAME=`basename $0`
|
||||
@@ -26,10 +27,10 @@ function print_help {
|
||||
echo " Do not compile desktop Java projects"
|
||||
echo " -m"
|
||||
echo " Compile with make instead of ninja."
|
||||
echo " -p [desktop|android|webgl|all]"
|
||||
echo " -p [desktop|android|ios|webgl|all]"
|
||||
echo " Platform(s) to build, defaults to desktop."
|
||||
echo " Building android will automatically generate the toolchains if needed and"
|
||||
echo " perform a partial desktop build."
|
||||
echo " Building for Android or iOS will automatically generate / download"
|
||||
echo " the toolchains if needed and perform a partial desktop build."
|
||||
echo " -r"
|
||||
echo " Restrict the number of make/ninja jobs."
|
||||
echo " -t"
|
||||
@@ -38,6 +39,8 @@ function print_help {
|
||||
echo " Run all unit tests, will trigger a debug build if needed."
|
||||
echo " -v"
|
||||
echo " Add Vulkan support to the Android build."
|
||||
echo " -s"
|
||||
echo " Add iOS simulator support to the iOS build."
|
||||
echo ""
|
||||
echo "Build types:"
|
||||
echo " release"
|
||||
@@ -71,6 +74,7 @@ ISSUE_DEBUG_BUILD=false
|
||||
ISSUE_RELEASE_BUILD=false
|
||||
|
||||
ISSUE_ANDROID_BUILD=false
|
||||
ISSUE_IOS_BUILD=false
|
||||
ISSUE_DESKTOP_BUILD=true
|
||||
ISSUE_WEBGL_BUILD=false
|
||||
|
||||
@@ -88,6 +92,8 @@ GENERATE_TOOLCHAINS=false
|
||||
|
||||
VULKAN_ANDROID_OPTION="-DFILAMENT_SUPPORTS_VULKAN=OFF"
|
||||
|
||||
IOS_BUILD_SIMULATOR=false
|
||||
|
||||
BUILD_GENERATOR=Ninja
|
||||
BUILD_COMMAND=ninja
|
||||
BUILD_CUSTOM_TARGETS=
|
||||
@@ -213,12 +219,32 @@ function build_webgl_with_target {
|
||||
${BUILD_COMMAND} ${BUILD_TARGETS}
|
||||
fi
|
||||
|
||||
if [ -d "samples/web/public" ]; then
|
||||
if [ -d "web/filament-js" ]; then
|
||||
if [ "$ISSUE_ARCHIVES" == "true" ]; then
|
||||
|
||||
which -s python3
|
||||
if [ $? == 0 ]; then
|
||||
echo "Generating JavaScript documentation..."
|
||||
local DOCS_FOLDER="web/docs"
|
||||
local DOCS_SCRIPT="../../web/docs/build.py"
|
||||
python3 ${DOCS_SCRIPT} --disable-demo \
|
||||
--output-folder ${DOCS_FOLDER} \
|
||||
--build-folder ${PWD}
|
||||
fi
|
||||
|
||||
echo "Generating out/filament-${LC_TARGET}-web.tgz..."
|
||||
cd samples/web/public
|
||||
tar -czvf ../../../../filament-${LC_TARGET}-web.tgz .
|
||||
# The web archive has the following subfolders:
|
||||
# dist...core WASM module and accompanying JS file.
|
||||
# docs...HTML tutorials for the JS API, accompanying demos, and a reference page.
|
||||
cd web
|
||||
tar -cvf ../../filament-${LC_TARGET}-web.tar -s /^filament-js/dist/ \
|
||||
filament-js/filament.js
|
||||
tar -rvf ../../filament-${LC_TARGET}-web.tar -s /^filament-js/dist/ \
|
||||
filament-js/filament.wasm
|
||||
tar -rvf ../../filament-${LC_TARGET}-web.tar docs
|
||||
cd -
|
||||
gzip -c ../filament-${LC_TARGET}-web.tar > ../filament-${LC_TARGET}-web.tgz
|
||||
rm ../filament-${LC_TARGET}-web.tar
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -346,6 +372,100 @@ function build_android {
|
||||
cd ../..
|
||||
}
|
||||
|
||||
function ensure_ios_toolchain {
|
||||
local TOOLCHAIN_PATH="build/toolchain-mac-ios.cmake"
|
||||
if [ -e ${TOOLCHAIN_PATH} ]; then
|
||||
echo "iOS toolchain file exists."
|
||||
return 0
|
||||
fi
|
||||
echo
|
||||
echo "iOS toolchain file does not exist."
|
||||
echo "It will automatically be downloaded from http://opensource.apple.com."
|
||||
read -p "Continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
|
||||
echo "Toolchain file must be downloaded to continue."
|
||||
exit 1
|
||||
fi
|
||||
curl -o "${TOOLCHAIN_PATH}" "${IOS_TOOLCHAIN_URL}" || {
|
||||
echo "Error downloading iOS toolchain file."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Apple's toolchain hard-codes the PLATFORM_NAME into the toolchain file. Instead, make this a
|
||||
# CACHE variable that can be overriden on the command line.
|
||||
local FIND='SET(PLATFORM_NAME iphoneos)'
|
||||
local REPLACE='SET(PLATFORM_NAME "iphoneos" CACHE STRING "iOS platform to build for")'
|
||||
sed -i '' "s/${FIND}/${REPLACE}/g" ./${TOOLCHAIN_PATH}
|
||||
|
||||
# Append Filament-specific settings.
|
||||
cat build/toolchain-mac-ios.filament.cmake >> ${TOOLCHAIN_PATH}
|
||||
|
||||
echo "Successfully downloaded iOS toolchain file and appended Filament-specific settings."
|
||||
}
|
||||
|
||||
function build_ios_target {
|
||||
local LC_TARGET=`echo $1 | tr '[:upper:]' '[:lower:]'`
|
||||
local ARCH=$2
|
||||
local PLATFORM=$3
|
||||
|
||||
echo "Building iOS $LC_TARGET ($ARCH) for $PLATFORM..."
|
||||
mkdir -p out/cmake-ios-${LC_TARGET}-${ARCH}
|
||||
|
||||
cd out/cmake-ios-${LC_TARGET}-${ARCH}
|
||||
|
||||
if [ ! -d "CMakeFiles" ] || [ "$ISSUE_CMAKE_ALWAYS" == "true" ]; then
|
||||
cmake \
|
||||
-G "$BUILD_GENERATOR" \
|
||||
-DCMAKE_BUILD_TYPE=$1 \
|
||||
-DCMAKE_INSTALL_PREFIX=../ios-${LC_TARGET}/filament \
|
||||
-DIOS_ARCH=${ARCH} \
|
||||
-DPLATFORM_NAME=${PLATFORM} \
|
||||
-DIOS=1 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-mac-ios.cmake \
|
||||
../..
|
||||
fi
|
||||
|
||||
${BUILD_COMMAND} install
|
||||
|
||||
if [ -d "../ios-${LC_TARGET}/filament" ]; then
|
||||
if [ "$ISSUE_ARCHIVES" == "true" ]; then
|
||||
echo "Generating out/filament-${LC_TARGET}-ios.tgz..."
|
||||
cd ../ios-${LC_TARGET}
|
||||
tar -czvf ../filament-${LC_TARGET}-ios.tgz filament
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ../..
|
||||
}
|
||||
|
||||
function build_ios {
|
||||
# Supress intermediate desktop tools install
|
||||
OLD_INSTALL_COMMAND=${INSTALL_COMMAND}
|
||||
INSTALL_COMMAND=
|
||||
build_desktop "${HOST_TOOLS}"
|
||||
INSTALL_COMMAND=${OLD_INSTALL_COMMAND}
|
||||
|
||||
ensure_ios_toolchain
|
||||
|
||||
# In theory, we could support iPhone architectures older than arm64, but
|
||||
# only arm64 devices support OpenGL 3.0 / Metal
|
||||
|
||||
if [ "$ISSUE_DEBUG_BUILD" == "true" ]; then
|
||||
build_ios_target "Debug" "arm64" "iphoneos"
|
||||
if [ "$IOS_BUILD_SIMULATOR" == "true" ]; then
|
||||
build_ios_target "Debug" "x86_64" "iphonesimulator"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ISSUE_RELEASE_BUILD" == "true" ]; then
|
||||
build_ios_target "Release" "arm64" "iphoneos"
|
||||
if [ "$IOS_BUILD_SIMULATOR" == "true" ]; then
|
||||
build_ios_target "Release" "x86_64" "iphonesimulator"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function validate_build_command {
|
||||
set +e
|
||||
# Make sure CMake is installed
|
||||
@@ -354,7 +474,7 @@ function validate_build_command {
|
||||
echo "Error: could not find cmake, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Make sure Ninja is installed
|
||||
if [ "$BUILD_COMMAND" == "ninja" ]; then
|
||||
ninja_binary=`which ninja`
|
||||
@@ -405,7 +525,7 @@ function run_tests {
|
||||
|
||||
pushd `dirname $0` > /dev/null
|
||||
|
||||
while getopts ":hacfijmp:tuv" opt; do
|
||||
while getopts ":hacfijmp:tuvs" opt; do
|
||||
case ${opt} in
|
||||
h)
|
||||
print_help
|
||||
@@ -435,21 +555,31 @@ while getopts ":hacfijmp:tuv" opt; do
|
||||
case $OPTARG in
|
||||
desktop)
|
||||
ISSUE_ANDROID_BUILD=false
|
||||
ISSUE_IOS_BUILD=false
|
||||
ISSUE_DESKTOP_BUILD=true
|
||||
ISSUE_WEBGL_BUILD=false
|
||||
;;
|
||||
android)
|
||||
ISSUE_ANDROID_BUILD=true
|
||||
ISSUE_IOS_BUILD=false
|
||||
ISSUE_DESKTOP_BUILD=false
|
||||
ISSUE_WEBGL_BUILD=false
|
||||
;;
|
||||
ios)
|
||||
ISSUE_ANDROID_BUILD=false
|
||||
ISSUE_IOS_BUILD=true
|
||||
ISSUE_DESKTOP_BUILD=false
|
||||
ISSUE_WEBGL_BUILD=false
|
||||
;;
|
||||
webgl)
|
||||
ISSUE_ANDROID_BUILD=false
|
||||
ISSUE_IOS_BUILD=false
|
||||
ISSUE_DESKTOP_BUILD=false
|
||||
ISSUE_WEBGL_BUILD=true
|
||||
;;
|
||||
all)
|
||||
ISSUE_ANDROID_BUILD=true
|
||||
ISSUE_IOS_BUILD=true
|
||||
ISSUE_DESKTOP_BUILD=true
|
||||
ISSUE_WEBGL_BUILD=false
|
||||
;;
|
||||
@@ -472,6 +602,10 @@ while getopts ":hacfijmp:tuv" opt; do
|
||||
echo "Also be sure to pass Backend::VULKAN to Engine::create."
|
||||
echo ""
|
||||
;;
|
||||
s)
|
||||
IOS_BUILD_SIMULATOR=true
|
||||
echo "iOS simulator support enabled."
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
echo ""
|
||||
@@ -522,6 +656,10 @@ if [ "$ISSUE_ANDROID_BUILD" == "true" ]; then
|
||||
build_android
|
||||
fi
|
||||
|
||||
if [ "$ISSUE_IOS_BUILD" == "true" ]; then
|
||||
build_ios
|
||||
fi
|
||||
|
||||
if [ "$ISSUE_WEBGL_BUILD" == "true" ]; then
|
||||
build_webgl
|
||||
fi
|
||||
|
||||
2
build/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# File is generated by ../build.sh and should not be tracked
|
||||
toolchain-mac-ios.cmake
|
||||
22
build/ios/build.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
source `dirname $0`/../common/ci-common.sh
|
||||
source `dirname $0`/ci-common.sh
|
||||
source `dirname $0`/../common/build-common.sh
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
|
||||
# build.sh prompts the user to download Apple's iOS toolchain
|
||||
yes | ./build.sh -p ios -c $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||
|
||||
6
build/ios/ci-common.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip
|
||||
unzip -q ninja-mac.zip
|
||||
chmod +x ninja
|
||||
export PATH="$PWD:$PATH"
|
||||
10
build/ios/common.cfg
Normal file
@@ -0,0 +1,10 @@
|
||||
# Format: //devtools/kokoro/config/proto/build.proto
|
||||
|
||||
action {
|
||||
define_artifacts {
|
||||
regex: "github/filament/out/*.tgz"
|
||||
regex: "github/filament/out/*.aar"
|
||||
strip_prefix: "github/filament/out"
|
||||
regex: "**/*sponge_log.xml"
|
||||
}
|
||||
}
|
||||
3
build/ios/continuous.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
# Format: //devtools/kokoro/config/proto/build.proto
|
||||
|
||||
build_file: "filament/build/ios/build.sh"
|
||||
3
build/ios/presubmit.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
# Format: //devtools/kokoro/config/proto/build.proto
|
||||
|
||||
build_file: "filament/build/ios/build.sh"
|
||||
3
build/ios/release.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
# Format: //devtools/kokoro/config/proto/build.proto
|
||||
|
||||
build_file: "filament/build/ios/build.sh"
|
||||
15
build/toolchain-mac-ios.filament.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
# ==================================================================================================
|
||||
# Filament-specific settings
|
||||
# The rest of the toolchain is downloaded from Apple Open Source and appended.
|
||||
# ==================================================================================================
|
||||
|
||||
set(CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS")
|
||||
|
||||
# Necessary for correct install location
|
||||
set(DIST_ARCH ${IOS_ARCH})
|
||||
|
||||
add_definitions(-DIOS)
|
||||
|
||||
# ==================================================================================================
|
||||
# End Filament-specific settings
|
||||
# ==================================================================================================
|
||||
@@ -5,6 +5,11 @@ unzip -q ninja-mac.zip
|
||||
chmod +x ninja
|
||||
export PATH="$PWD:$PATH"
|
||||
|
||||
# The Kokoro machines have Python 3.6.3 installed. Let's verify that here, and install the
|
||||
# distributions required for web/docs.
|
||||
python3 --version
|
||||
pip3 install mistletoe pygments jsbeautifier
|
||||
|
||||
curl -L https://github.com/juj/emsdk/archive/0d8576c.zip > emsdk.zip
|
||||
unzip emsdk.zip
|
||||
mv emsdk-* emsdk
|
||||
|
||||
@@ -23,6 +23,9 @@ mkdir out\cmake-release
|
||||
cd out\cmake-release
|
||||
if errorlevel 1 exit /b %errorlevel%
|
||||
|
||||
:: Force Java JDK 8. Kokoro machines default to 9
|
||||
SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0_152
|
||||
|
||||
cmake ..\.. -G Ninja ^
|
||||
-DCMAKE_CXX_COMPILER:PATH="clang-cl.exe" ^
|
||||
-DCMAKE_C_COMPILER:PATH="clang-cl.exe" ^
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
if defined KOKORO_BUILD_ID (
|
||||
choco install llvm --version 6.0.1 -y
|
||||
if errorlevel 1 exit /b %errorlevel%
|
||||
|
||||
:: retry if choco install failed
|
||||
if errorlevel 1 (
|
||||
choco install llvm --version 6.0.1 -y
|
||||
if errorlevel 1 exit /b %errorlevel%
|
||||
)
|
||||
|
||||
:: refreshenv is necessary to put LLVM on path
|
||||
refreshenv
|
||||
|
||||
@@ -3402,7 +3402,7 @@ To compute the specular color of a material we need to evaluate the complex Fres
|
||||
|
||||
We then sum (integrate) and normalize all the samples to obtain $\fNormal$ in the XYZ color space. From there, a simple color space conversion yields a linear sRGB color or a non-linear sRGB color after applying the opto-electronic transfer function (OETF, commonly known as "gamma" curve). Note that for some materials such as gold the final sRGB color might fall out of gamut. We use a simple normalization step as a cheap form of gamut remapping but it would be interesting to consider computing values in a color space with a wider gamut (for instance BT.2020).
|
||||
|
||||
To achieve the desired result we used the ICE 1931 2 degrees CMFs, from 360nm to 830nm at 1nm intervals ([source](http://cvrl.ioo.ucl.ac.uk/cmfs.htm)), and the CIE Standard Illuminant D65 relative spectral power distribution, from 300nm to 830nm, at 5nm intervals ([source](https://cielab.xyz/pdf/CIE_sel_colorimetric_tables.xls)).
|
||||
To achieve the desired result we used the ICE 1931 2 degrees CMFs, from 360nm to 830nm at 1nm intervals ([source](http://cvrl.ioo.ucl.ac.uk/cmfs.htm)), and the CIE Standard Illuminant D65 relative spectral power distribution, from 300nm to 830nm, at 5nm intervals ([source](http://files.cie.co.at/204.xls)).
|
||||
|
||||
Our implementation is presented in listing [specularColorImpl], with the actual data omitted for brevity.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -74,7 +74,6 @@ set(SRCS
|
||||
src/Frustum.cpp
|
||||
src/IndexBuffer.cpp
|
||||
src/IndirectLight.cpp
|
||||
src/GpuLightBuffer.cpp
|
||||
src/Material.cpp
|
||||
src/MaterialInstance.cpp
|
||||
src/PostProcessManager.cpp
|
||||
@@ -110,7 +109,6 @@ set(PRIVATE_HDRS
|
||||
src/details/Froxelizer.h
|
||||
src/details/IndexBuffer.h
|
||||
src/details/IndirectLight.h
|
||||
src/details/GpuLightBuffer.h
|
||||
src/details/Material.h
|
||||
src/details/MaterialInstance.h
|
||||
src/details/RenderPrimitive.h
|
||||
@@ -158,9 +156,14 @@ if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
list(APPEND SRCS src/driver/noop/NoopDriver.cpp)
|
||||
endif()
|
||||
|
||||
if(IOS AND NOT FILAMENT_SUPPORTS_VULKAN)
|
||||
message(FATAL_ERROR "Filament for iOS must be built with Vulkan support.")
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# OS specific
|
||||
# ==================================================================================================
|
||||
|
||||
# Here set the architecture specific sources
|
||||
if (USE_EXTERNAL_GLES3)
|
||||
# Experimental feature; clients provide their own Context Manager.
|
||||
@@ -169,6 +172,8 @@ elseif (ANDROID)
|
||||
list(APPEND SRCS src/driver/android/ExternalTextureManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/driver/android/VirtualMachineEnv.cpp)
|
||||
list(APPEND SRCS src/driver/opengl/PlatformEGL.cpp)
|
||||
elseif (IOS)
|
||||
list(APPEND SRCS src/driver/opengl/PlatformCocoaTouchGL.mm)
|
||||
elseif (APPLE)
|
||||
list(APPEND SRCS src/driver/opengl/PlatformCocoaGL.mm)
|
||||
elseif (WEBGL)
|
||||
@@ -187,8 +192,6 @@ endif()
|
||||
# "2" corresponds to SYSTRACE_TAG_FILEMENT (See: utils/Systrace.h)
|
||||
add_definitions(-DSYSTRACE_TAG=2 )
|
||||
|
||||
add_definitions(-DFILAMENT_DRIVER_SUPPORTS_OPENGL)
|
||||
|
||||
# ==================================================================================================
|
||||
# Vulkan Sources
|
||||
# ==================================================================================================
|
||||
@@ -207,8 +210,10 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
)
|
||||
if (LINUX)
|
||||
list(APPEND SRCS src/driver/vulkan/PlatformVkLinux.cpp)
|
||||
elseif (APPLE)
|
||||
elseif (APPLE AND NOT IOS)
|
||||
list(APPEND SRCS src/driver/vulkan/PlatformVkCocoa.mm)
|
||||
elseif (IOS)
|
||||
list(APPEND SRCS src/driver/vulkan/PlatformVkCocoaTouch.mm)
|
||||
elseif (ANDROID)
|
||||
list(APPEND SRCS src/driver/vulkan/PlatformVkAndroid.cpp)
|
||||
elseif (WIN32)
|
||||
@@ -229,7 +234,7 @@ set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
file(MAKE_DIRECTORY "${GENERATION_ROOT}/generated/material/")
|
||||
|
||||
# Target system.
|
||||
if (ANDROID OR WEBGL)
|
||||
if (ANDROID OR WEBGL OR IOS)
|
||||
set(MATC_TARGET mobile)
|
||||
else()
|
||||
set(MATC_TARGET desktop)
|
||||
@@ -305,17 +310,11 @@ target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
# Dependencies
|
||||
# ==================================================================================================
|
||||
|
||||
set(DARWIN_LINK_LIBRARIES bluegl bluevk)
|
||||
set(WIN32_LINK_LIBRARIES bluegl)
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(${TARGET} PUBLIC GLESv3 EGL android)
|
||||
set(LINUX_LINK_LIBRARIES )
|
||||
else()
|
||||
set(LINUX_LINK_LIBRARIES bluegl)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (APPLE AND NOT IOS)
|
||||
target_link_libraries(${TARGET} PRIVATE "-framework Cocoa")
|
||||
endif()
|
||||
|
||||
@@ -325,6 +324,11 @@ target_link_libraries(${TARGET} PUBLIC filaflat)
|
||||
target_link_libraries(${TARGET} PUBLIC filabridge)
|
||||
target_link_libraries(${TARGET} PUBLIC image_headers)
|
||||
|
||||
# Android and iOS link directly against platform-specific OpenGL ES libraries
|
||||
if(NOT IOS AND NOT ANDROID)
|
||||
target_link_libraries(${TARGET} PRIVATE bluegl)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_SUPPORTS_VULKAN)
|
||||
target_link_libraries(${TARGET} PUBLIC bluevk vkmemalloc)
|
||||
endif()
|
||||
@@ -333,12 +337,6 @@ if (LINUX)
|
||||
target_link_libraries(${TARGET} PRIVATE dl)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET} PRIVATE
|
||||
"$<$<PLATFORM_ID:Darwin>:${DARWIN_LINK_LIBRARIES}>"
|
||||
"$<$<PLATFORM_ID:Linux>:${LINUX_LINK_LIBRARIES}>"
|
||||
"$<$<PLATFORM_ID:Windows>:${WIN32_LINK_LIBRARIES}>"
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Compiler flags
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -11,7 +11,7 @@ Filament. Latest versions are available on the [project page](https://github.com
|
||||
- `matinfo`, Displays information about materials compiled with `matc`
|
||||
- `mipgen`, Generates a series of miplevels from a source image.
|
||||
- `normal-blending`, Tool to blend normal maps
|
||||
- `roughness-prefilter`, Pre-filters a roughness map from a normal map to reduce aliasing
|
||||
- `roughness-prefilter`, Pre-filters a roughness map from a normal map to reduce aliasing
|
||||
- `skygen`, Physically-based sky environment texture generator
|
||||
- `specular-color`, Computes the specular color of conductors based on spectral data
|
||||
|
||||
@@ -29,10 +29,119 @@ Filament is distributed as a set of static libraries you must link against:
|
||||
- `utils`, Support library for Filament
|
||||
|
||||
To use Filament from Java you must use the following two libraries instead:
|
||||
- `filament-java.jar`, Contains Filament's Java classes
|
||||
- `filament-java.jar`, Contains Filament's Java classes
|
||||
- `filament-jni`, Filament's JNI bindings
|
||||
|
||||
To use the Vulkan backend on macOS you must also make the following libraries available at runtime:
|
||||
- `MoltenVK_icd.json`
|
||||
- `libMoltenVK.dylib`
|
||||
- `libMoltenVK.dylib`
|
||||
- `vulkan.1.dylib`
|
||||
|
||||
## Linking against Filament
|
||||
|
||||
This walkthrough will get you successfully compiling and linking native code
|
||||
against Filament with minimum dependencies.
|
||||
|
||||
To start, download Filament's [latest binary release](https://github.com/google/filament/releases)
|
||||
and extract into a directory of your choosing. Binary releases are suffixed
|
||||
with the platform name, for example, `filament-20181009-linux.tgz`.
|
||||
|
||||
Create a file, `main.cpp`, in the same directory with the following contents:
|
||||
|
||||
```
|
||||
#include <filament/FilamentAPI.h>
|
||||
#include <filament/Engine.h>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Engine *engine = Engine::create();
|
||||
engine->destroy(&engine);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The directory should look like:
|
||||
|
||||
```
|
||||
|-- README.md
|
||||
|-- bin
|
||||
|-- docs
|
||||
|-- include
|
||||
|-- lib
|
||||
|-- main.cpp
|
||||
```
|
||||
|
||||
We'll use a platform-specific Makefile to compile and link `main.cpp` with Filament's libraries.
|
||||
Copy your platform's Makefile below into a `Makefile` inside the same directory.
|
||||
|
||||
### Linux
|
||||
|
||||
```
|
||||
FILAMENT_LIBS=-lfilament -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils
|
||||
CC=clang++
|
||||
|
||||
main: main.o
|
||||
$(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) -lpthread -lc++ -ldl -o main
|
||||
|
||||
main.o: main.cpp
|
||||
$(CC) -Iinclude/ -std=c++14 -pthread -c main.cpp
|
||||
|
||||
clean:
|
||||
rm -f main main.o
|
||||
|
||||
.PHONY: clean
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
```
|
||||
FILAMENT_LIBS=-lfilament -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils
|
||||
CC=clang++
|
||||
|
||||
main: main.o
|
||||
$(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) -framework Cocoa -o main
|
||||
|
||||
main.o: main.cpp
|
||||
$(CC) -Iinclude/ -std=c++14 -c main.cpp
|
||||
|
||||
clean:
|
||||
rm -f main main.o
|
||||
|
||||
.PHONY: clean
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
FILAMENT_LIBS=lib/x86_64/filament.lib lib/x86_64/bluegl.lib \
|
||||
lib/x86_64/filabridge.lib lib/x86_64/filaflat.lib lib/x86_64/utils.lib
|
||||
CC=clang-cl.exe
|
||||
|
||||
main.exe: main.obj
|
||||
$(CC) main.obj $(FILAMENT_LIBS) gdi32.lib user32.lib opengl32.lib
|
||||
|
||||
main.obj: main.cpp
|
||||
$(CC) /Iinclude/ /std:c++14 /c main.cpp
|
||||
|
||||
clean:
|
||||
del main.exe main.obj
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
```
|
||||
|
||||
### Compiling
|
||||
|
||||
You should be able to invoke `make` and run the executable successfully:
|
||||
|
||||
```
|
||||
$ make
|
||||
$ ./main
|
||||
FEngine (64 bits) created at 0x106471000 (threading is enabled)
|
||||
```
|
||||
|
||||
On Windows, you'll need to open up a Visual Studio Native Tools Command Prompt
|
||||
and invoke `nmake` instead of `make`.
|
||||
|
||||
|
||||
13
filament/docs/Versioning.md
Normal file
@@ -0,0 +1,13 @@
|
||||
## Versioning
|
||||
|
||||
Filament uses a 3-number versioning scheme that superficially resembles a [semantic
|
||||
version](https://semver.org/) but is actually more interesting because of our material system. Here
|
||||
are the guidelines:
|
||||
|
||||
- Increment the **most significant** number only when making a non-backwards compatible API change,
|
||||
or when introducing a major new API.
|
||||
- Increment the **middle number** only when making a non-backwards compatible change to the material
|
||||
system. When this number gets bumped, users need to rebuild their mat files. Reset the middle
|
||||
number to zero when the most significant number has been incremented.
|
||||
- Increment the **least significant** number each time a new release is published. Reset this number
|
||||
to zero if one of the other two numbers have been incremented.
|
||||
@@ -64,9 +64,9 @@ public:
|
||||
* @param engine Reference to the filament::Engine to associate this IndexBuffer with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occured.
|
||||
* an error occurred.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occured, such as running out of
|
||||
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
* @exception utils::PreConditionPanic if a parameter to a builder function was invalid.
|
||||
*/
|
||||
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
* @param engine Reference to the filament::Engine to associate this IndirectLight with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occured.
|
||||
* an error occurred.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occured, such as running out of
|
||||
* memory or other resources.
|
||||
|
||||
@@ -421,7 +421,7 @@ public:
|
||||
* @error if exceptions are disabled and an error occurs, this function is a no-op.
|
||||
* Success can be checked by looking at the return value.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occured, such as running out of
|
||||
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
* @exception utils::PreConditionPanic if a parameter to a builder function was invalid.
|
||||
*/
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
* @param engine Reference to the filament::Engine to associate this Material with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occured.
|
||||
* an error occurred.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
*
|
||||
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
|
||||
* @param type Whether the color value is encoded as Linear or sRGB/A.
|
||||
* @param color Array of read, green, blue and alpha chanels values.
|
||||
* @param color Array of read, green, blue and alpha channels values.
|
||||
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
|
||||
*/
|
||||
void setParameter(const char* name, RgbaType type, math::float4 color) noexcept;
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
* @param flags One or more MirrorFrameFlag behavior configuration flags.
|
||||
*
|
||||
* @remark
|
||||
* mirrorFrame() should be called after a frme is rendered using render()
|
||||
* mirrorFrame() should be called after a frame is rendered using render()
|
||||
* but before endFrame() is called.
|
||||
*/
|
||||
void mirrorFrame(SwapChain* dstSwapChain, Viewport const& dstViewport, Viewport const& srcViewport,
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
* +--------------------+
|
||||
* | | .stride .alignment
|
||||
* | | ----------------------->-->
|
||||
* | | O----------------------+--+ low adresses
|
||||
* | | O----------------------+--+ low addresses
|
||||
* | | | | | |
|
||||
* | w | | | .top | |
|
||||
* | <---------> | | V | |
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | ^ | | | |
|
||||
* | y | | +----------------------+--+ high adresses
|
||||
* | y | | +----------------------+--+ high addresses
|
||||
* O------------+-------+
|
||||
*
|
||||
* Typically readPixels() will be called after Renderer.beginFrame().
|
||||
@@ -176,6 +176,15 @@ public:
|
||||
*/
|
||||
void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
driver::PixelBufferDescriptor&& buffer) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the presentation time of the currently displayed frame in nanosecond.
|
||||
*
|
||||
* This value can change at any time.
|
||||
*
|
||||
* @return timestamp in nanosecond.
|
||||
*/
|
||||
int64_t getTimestamp() const noexcept;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -175,9 +175,9 @@ public:
|
||||
* @param engine Reference to the filament::Engine to associate this Texture with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occured.
|
||||
* an error occurred.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occured, such as running out of
|
||||
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
* @exception utils::PreConditionPanic if a parameter to a builder function was invalid.
|
||||
*/
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
* @param e An entity.
|
||||
*
|
||||
* @note If this transform had children, these are orphaned, which means their local
|
||||
* transform becomes a world transform. Usually it's not sensical. It's recomanded to make
|
||||
* transform becomes a world transform. Usually it's not sensical. It's recommended to make
|
||||
* sure that a destroyed transform doesn't have have children.
|
||||
*
|
||||
* @see create()
|
||||
|
||||
@@ -69,9 +69,9 @@ public:
|
||||
* @param engine Reference to the filament::Engine to associate this VertexBuffer with.
|
||||
*
|
||||
* @return pointer to the newly created object or nullptr if exceptions are disabled and
|
||||
* an error occured.
|
||||
* an error occurred.
|
||||
*
|
||||
* @exception utils::PostConditionPanic if a runtime error occured, such as running out of
|
||||
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
|
||||
* memory or other resources.
|
||||
* @exception utils::PreConditionPanic if a parameter to a builder function was invalid.
|
||||
*/
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
*
|
||||
* enabled: enable or disables dynamic resolution on a View
|
||||
* homogeneousScaling: by default the system scales the major axis first. Set this to true
|
||||
* to force homegeneous scaling.
|
||||
* to force homogeneous scaling.
|
||||
* scaleRate: rate at which the scale will change to reach the target frame rate
|
||||
* This value can be computed as 1 / N, where N is the number of frames
|
||||
* needed to reach 64% of the target scale factor.
|
||||
@@ -368,7 +368,7 @@ public:
|
||||
* 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 lighits are not expected to be visible.
|
||||
* @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).
|
||||
*
|
||||
|
||||
@@ -66,6 +66,13 @@ public:
|
||||
virtual SwapChain* createSwapChain(void* nativeWindow, uint64_t& flags) noexcept = 0;
|
||||
virtual void destroySwapChain(SwapChain* swapChain) noexcept = 0;
|
||||
|
||||
virtual void createDefaultRenderTarget(uint32_t& framebuffer, uint32_t& colorbuffer,
|
||||
uint32_t& depthbuffer) noexcept {
|
||||
framebuffer = 0;
|
||||
colorbuffer = 0;
|
||||
depthbuffer = 0;
|
||||
}
|
||||
|
||||
// Called to make the OpenGL context active on the calling thread.
|
||||
virtual void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept = 0;
|
||||
|
||||
@@ -73,7 +80,7 @@ public:
|
||||
// swap draw buffers (i.e. for double-buffered rendering).
|
||||
virtual void commit(SwapChain* swapChain) noexcept = 0;
|
||||
|
||||
virtual void setPresentationTime(long time) noexcept = 0;
|
||||
virtual void setPresentationTime(int64_t presentationTimeInNanosecond) noexcept = 0;
|
||||
|
||||
virtual bool canCreateFence() noexcept { return false; }
|
||||
virtual Fence* createFence() noexcept = 0;
|
||||
@@ -90,7 +97,7 @@ public:
|
||||
|
||||
// detach destroys the texture associated to the stream
|
||||
virtual void detach(Stream* stream) noexcept = 0;
|
||||
virtual void updateTexImage(Stream* stream) noexcept = 0;
|
||||
virtual void updateTexImage(Stream* stream, int64_t* timestamp) noexcept = 0;
|
||||
|
||||
// external texture storage
|
||||
virtual ExternalTexture* createExternalTextureStorage() noexcept = 0;
|
||||
|
||||
@@ -35,10 +35,9 @@
|
||||
|
||||
#include "PrecompiledMaterials.h"
|
||||
|
||||
#include <filament/Exposure.h>
|
||||
|
||||
#include <private/filament/SibGenerator.h>
|
||||
#include <private/filament/UibGenerator.h>
|
||||
|
||||
#include <filament/Exposure.h>
|
||||
|
||||
#include <filaflat/MaterialParser.h>
|
||||
#include <filaflat/ShaderBuilder.h>
|
||||
@@ -113,21 +112,6 @@ FEngine* FEngine::create(Backend backend, Platform* platform, void* sharedGLCont
|
||||
return instance;
|
||||
}
|
||||
|
||||
UniformInterfaceBlock FEngine::PerViewUib::getUib() noexcept {
|
||||
return UibGenerator::getPerViewUib();
|
||||
}
|
||||
|
||||
UniformInterfaceBlock FEngine::PostProcessingUib::getUib() noexcept {
|
||||
return UibGenerator::getPostProcessingUib();
|
||||
}
|
||||
|
||||
SamplerInterfaceBlock FEngine::PerViewSib::getSib() noexcept {
|
||||
return SibGenerator::getPerViewSib();
|
||||
}
|
||||
|
||||
SamplerInterfaceBlock FEngine::PostProcessSib::getSib() noexcept {
|
||||
return SibGenerator::getPostProcessSib();
|
||||
}
|
||||
|
||||
// these must be static because only a pointer is copied to the render stream
|
||||
static const half4 sFullScreenTriangleVertices[3] = {
|
||||
@@ -445,9 +429,9 @@ Handle<HwProgram> FEngine::createPostProcessProgram(MaterialParser& parser,
|
||||
.withSamplerBindings(pBindings)
|
||||
.withVertexShader(CString(vShaderBuilder.getShader(), vShaderBuilder.size()))
|
||||
.withFragmentShader(CString(fShaderBuilder.getShader(), fShaderBuilder.size()))
|
||||
.addUniformBlock(BindingPoints::PER_VIEW, &UibGenerator::getPerViewUib())
|
||||
.addUniformBlock(BindingPoints::POST_PROCESS, &UibGenerator::getPostProcessingUib())
|
||||
.addSamplerBlock(BindingPoints::POST_PROCESS, &SibGenerator::getPostProcessSib());
|
||||
.addUniformBlock(BindingPoints::PER_VIEW, &PerViewUib::getUib())
|
||||
.addUniformBlock(BindingPoints::POST_PROCESS, &PostProcessingUib::getUib())
|
||||
.addSamplerBlock(BindingPoints::POST_PROCESS, &PostProcessSib::getSib());
|
||||
auto program = const_cast<DriverApi&>(mCommandStream).createProgram(std::move(pb));
|
||||
assert(program);
|
||||
return program;
|
||||
|
||||
@@ -71,7 +71,6 @@ constexpr size_t FROXEL_BUFFER_HEIGHT = (FROXEL_BUFFER_ENTRY_COUNT_MAX + F
|
||||
|
||||
constexpr size_t RECORD_BUFFER_WIDTH_SHIFT = 5u;
|
||||
constexpr size_t RECORD_BUFFER_WIDTH = 1u << RECORD_BUFFER_WIDTH_SHIFT;
|
||||
constexpr size_t RECORD_BUFFER_WIDTH_MASK = RECORD_BUFFER_WIDTH - 1u;
|
||||
|
||||
constexpr size_t RECORD_BUFFER_HEIGHT = 2048;
|
||||
constexpr size_t RECORD_BUFFER_ENTRY_COUNT = RECORD_BUFFER_WIDTH * RECORD_BUFFER_HEIGHT; // 64K
|
||||
@@ -168,12 +167,12 @@ bool Froxelizer::prepare(
|
||||
|
||||
// froxel buffer (~32 KiB)
|
||||
mFroxelBufferUser = {
|
||||
driverApi.allocatePod<FroxelEntry>(FROXEL_BUFFER_ENTRY_COUNT_MAX, CACHELINE_SIZE),
|
||||
driverApi.allocatePod<FroxelEntry>(FROXEL_BUFFER_ENTRY_COUNT_MAX),
|
||||
FROXEL_BUFFER_ENTRY_COUNT_MAX };
|
||||
|
||||
// record buffer (~64 KiB)
|
||||
mRecordBufferUser = {
|
||||
driverApi.allocatePod<RecordBufferType>(RECORD_BUFFER_ENTRY_COUNT, CACHELINE_SIZE),
|
||||
driverApi.allocatePod<RecordBufferType>(RECORD_BUFFER_ENTRY_COUNT),
|
||||
RECORD_BUFFER_ENTRY_COUNT };
|
||||
|
||||
/*
|
||||
@@ -749,12 +748,7 @@ void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
|
||||
} while(records[i].lights == b.lights);
|
||||
}
|
||||
out_of_memory:
|
||||
|
||||
// froxel buffer is always fully invalidated
|
||||
mFroxelBuffer.invalidate();
|
||||
|
||||
// needed record buffer size may change at each frame
|
||||
mRecordsBuffer.invalidate(0, (offset + RECORD_BUFFER_WIDTH_MASK) >> RECORD_BUFFER_WIDTH_SHIFT);
|
||||
;
|
||||
}
|
||||
|
||||
static inline float2 project(mat4f const& p, float3 const& v) noexcept {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 "details/GpuLightBuffer.h"
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include <filament/EngineEnums.h>
|
||||
|
||||
#include <private/filament/UibGenerator.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace driver;
|
||||
|
||||
namespace details {
|
||||
|
||||
GpuLightBuffer::GpuLightBuffer(FEngine& engine) noexcept
|
||||
: mLightsUb(UibGenerator::getLightsUib()) {
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
mLightUbh = driverApi.createUniformBuffer(mLightsUb.getSize());
|
||||
driverApi.bindUniformBuffer(BindingPoints::LIGHTS, mLightUbh);
|
||||
}
|
||||
|
||||
GpuLightBuffer::~GpuLightBuffer() noexcept = default;
|
||||
|
||||
void GpuLightBuffer::terminate(FEngine& engine) {
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
driverApi.destroyUniformBuffer(mLightUbh);
|
||||
}
|
||||
|
||||
void GpuLightBuffer::commit(FEngine& engine) noexcept {
|
||||
if (UTILS_UNLIKELY(mLightsUb.isDirty())) {
|
||||
commitSlow(engine);
|
||||
}
|
||||
engine.getDriverApi().bindUniformBuffer(BindingPoints::LIGHTS, mLightUbh);
|
||||
}
|
||||
|
||||
void GpuLightBuffer::commitSlow(FEngine& engine) noexcept {
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
driver.updateUniformBuffer(mLightUbh, mLightsUb.toBufferDescriptor(driver));
|
||||
mLightsUb.clean();
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace filament
|
||||
@@ -60,7 +60,8 @@ FIndexBuffer::FIndexBuffer(FEngine& engine, const IndexBuffer::Builder& builder)
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
mHandle = driver.createIndexBuffer(
|
||||
(driver::ElementType)builder->mIndexType,
|
||||
uint32_t(builder->mIndexCount));
|
||||
uint32_t(builder->mIndexCount),
|
||||
driver::BufferUsage::STATIC);
|
||||
}
|
||||
|
||||
void FIndexBuffer::terminate(FEngine& engine) {
|
||||
@@ -75,7 +76,7 @@ void FIndexBuffer::setBuffer(FEngine& engine,
|
||||
byteSize = uint32_t(buffer.size);
|
||||
}
|
||||
|
||||
engine.getDriverApi().loadIndexBuffer(mHandle, std::move(buffer), byteOffset, byteSize);
|
||||
engine.getDriverApi().updateIndexBuffer(mHandle, std::move(buffer), byteOffset, byteSize);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#include <private/filament/UibGenerator.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <filament/SamplerInterfaceBlock.h>
|
||||
#include <filament/UniformInterfaceBlock.h>
|
||||
#include <private/filament/SamplerInterfaceBlock.h>
|
||||
#include <private/filament/UniformInterfaceBlock.h>
|
||||
|
||||
#include <filaflat/MaterialParser.h>
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material)
|
||||
|
||||
if (!material->getUniformInterfaceBlock().isEmpty()) {
|
||||
mUniforms = UniformBuffer(upcast(material)->getDefaultInstance()->mUniforms);
|
||||
mUbHandle = driver.createUniformBuffer(mUniforms.getSize());
|
||||
mUbHandle = driver.createUniformBuffer(mUniforms.getSize(), driver::BufferUsage::DYNAMIC);
|
||||
}
|
||||
|
||||
if (!material->getSamplerInterfaceBlock().isEmpty()) {
|
||||
@@ -63,7 +63,7 @@ void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* ma
|
||||
|
||||
if (!material->getUniformInterfaceBlock().isEmpty()) {
|
||||
mUniforms = UniformBuffer(material->getUniformInterfaceBlock());
|
||||
mUbHandle = driver.createUniformBuffer(mUniforms.getSize());
|
||||
mUbHandle = driver.createUniformBuffer(mUniforms.getSize(), driver::BufferUsage::STATIC);
|
||||
}
|
||||
|
||||
if (!material->getSamplerInterfaceBlock().isEmpty()) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include <private/filament/SibGenerator.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace filament {
|
||||
@@ -37,7 +39,7 @@ void PostProcessManager::init(FEngine& engine) noexcept {
|
||||
// create sampler for post-process FBO
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
mPostProcessSbh = driver.createSamplerBuffer(engine.getPostProcessSib().getSize());
|
||||
mPostProcessUbh = driver.createUniformBuffer(engine.getPerPostProcessUib().getSize());
|
||||
mPostProcessUbh = driver.createUniformBuffer(engine.getPerPostProcessUib().getSize(), driver::BufferUsage::DYNAMIC);
|
||||
driver.bindSamplers(BindingPoints::POST_PROCESS, mPostProcessSbh);
|
||||
driver.bindUniformBuffer(BindingPoints::POST_PROCESS, mPostProcessUbh);
|
||||
}
|
||||
@@ -58,20 +60,20 @@ void PostProcessManager::setSource(uint32_t viewportWidth, uint32_t viewportHeig
|
||||
params.filterMag = SamplerMagFilter::LINEAR;
|
||||
params.filterMin = SamplerMinFilter::LINEAR;
|
||||
SamplerBuffer sb(engine.getPostProcessSib());
|
||||
sb.setSampler(FEngine::PostProcessSib::COLOR_BUFFER, pos->texture, params);
|
||||
sb.setSampler(PostProcessSib::COLOR_BUFFER, pos->texture, params);
|
||||
|
||||
auto duration = engine.getTime();
|
||||
float fraction = (duration.count() % 1000000000) / 1000000000.0f;
|
||||
|
||||
UniformBuffer& ub = mPostProcessUb;
|
||||
ub.setUniform(offsetof(FEngine::PostProcessingUib, time), fraction);
|
||||
ub.setUniform(offsetof(FEngine::PostProcessingUib, uvScale),
|
||||
ub.setUniform(offsetof(PostProcessingUib, time), fraction);
|
||||
ub.setUniform(offsetof(PostProcessingUib, uvScale),
|
||||
math::float2{ viewportWidth, viewportHeight } / math::float2{ pos->w, pos->h });
|
||||
|
||||
// The shader may need to know the offset between the top of the texture and the top
|
||||
// of the rectangle that it actually needs to sample from.
|
||||
const float yOffset = pos->h - viewportHeight;
|
||||
ub.setUniform(offsetof(FEngine::PostProcessingUib, yOffset), yOffset);
|
||||
ub.setUniform(offsetof(PostProcessingUib, yOffset), yOffset);
|
||||
|
||||
driver.updateSamplerBuffer(mPostProcessSbh, std::move(sb));
|
||||
driver.updateUniformBuffer(mPostProcessUbh, ub.toBufferDescriptor(driver));
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
// NOTE: We only need Renderer.h here because the definition of some FRenderer methods are here
|
||||
#include "details/Renderer.h"
|
||||
|
||||
#include <private/filament/UibGenerator.h>
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
@@ -118,7 +120,7 @@ void RenderPass::recordDriverCommands(
|
||||
SYSTRACE_CALL();
|
||||
|
||||
if (!commands.empty()) {
|
||||
Handle<HwUniformBuffer> uboHandle = scene.getUniformBufferHandle();
|
||||
Handle<HwUniformBuffer> uboHandle = scene.getRenderableUBO();
|
||||
FMaterialInstance const* UTILS_RESTRICT previousMi = nullptr;
|
||||
FMaterial const* UTILS_RESTRICT ma = nullptr;
|
||||
Command const* UTILS_RESTRICT c;
|
||||
@@ -129,8 +131,8 @@ void RenderPass::recordDriverCommands(
|
||||
|
||||
// per-renderable uniform
|
||||
PrimitiveInfo const& UTILS_RESTRICT info = c->primitive;
|
||||
size_t offset = info.index * sizeof(FRenderableManager::Transform);
|
||||
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE, uboHandle, offset, sizeof(FRenderableManager::Transform));
|
||||
size_t offset = info.index * sizeof(PerRenderableUib);
|
||||
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE, uboHandle, offset, sizeof(PerRenderableUib));
|
||||
if (info.perRenderableBones) {
|
||||
driver.bindUniformBuffer(BindingPoints::PER_RENDERABLE_BONES, info.perRenderableBones);
|
||||
}
|
||||
@@ -477,7 +479,7 @@ void RenderPass::updateSummedPrimitiveCounts(
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
FRenderer::ColorPass::ColorPass(const char* name,
|
||||
JobSystem& js, JobSystem::Job* jobFroxelize,FView* view, Handle<HwRenderTarget> const rth)
|
||||
JobSystem& js, JobSystem::Job* jobFroxelize, FView& view, Handle<HwRenderTarget> const rth)
|
||||
: RenderPass(name), js(js), jobFroxelize(jobFroxelize), view(view), rth(rth) {
|
||||
}
|
||||
|
||||
@@ -486,7 +488,7 @@ void FRenderer::ColorPass::beginRenderPass(
|
||||
// wait for froxelization to finish
|
||||
// (this could even be a special command between the depth and color passes)
|
||||
js.wait(jobFroxelize);
|
||||
view->commitFroxels(driver);
|
||||
view.commitFroxels(driver);
|
||||
|
||||
// We won't need the depth or stencil buffers after this pass.
|
||||
RenderPassParams params = {};
|
||||
@@ -495,16 +497,16 @@ void FRenderer::ColorPass::beginRenderPass(
|
||||
params.bottom = viewport.bottom;
|
||||
params.width = viewport.width;
|
||||
params.height = viewport.height;
|
||||
params.clearColor = view->getClearColor();
|
||||
params.clearColor = view.getClearColor();
|
||||
params.clearDepth = 1.0;
|
||||
|
||||
if (view->hasPostProcessPass()) {
|
||||
if (view.hasPostProcessPass()) {
|
||||
// When using a post-process pass, composition of Views is done during the post-process
|
||||
// pass, which means it's NOT done here. For this reason, we need to clear the depth/stencil
|
||||
// buffers unconditionally. The color buffer must be cleared to what the user asked for,
|
||||
// since it's akin to a drawing command.
|
||||
// Also, all buffers can be invalidated before rendering.
|
||||
if (view->getClearTargetColor()) {
|
||||
if (view.getClearTargetColor()) {
|
||||
params.clear = TargetBufferFlags::ALL;
|
||||
} else {
|
||||
params.clear = TargetBufferFlags::DEPTH_AND_STENCIL;
|
||||
@@ -512,14 +514,14 @@ void FRenderer::ColorPass::beginRenderPass(
|
||||
params.discardStart = TargetBufferFlags::ALL;
|
||||
driver.beginRenderPass(rth, params);
|
||||
} else {
|
||||
params.discardStart = view->getDiscardedTargetBuffers();
|
||||
if (view->getClearTargetColor()) {
|
||||
params.discardStart = view.getDiscardedTargetBuffers();
|
||||
if (view.getClearTargetColor()) {
|
||||
params.clear |= TargetBufferFlags::COLOR;
|
||||
}
|
||||
if (view->getClearTargetDepth()) {
|
||||
if (view.getClearTargetDepth()) {
|
||||
params.clear |= TargetBufferFlags::DEPTH;
|
||||
}
|
||||
if (view->getClearTargetStencil()) {
|
||||
if (view.getClearTargetStencil()) {
|
||||
params.clear |= TargetBufferFlags::STENCIL;
|
||||
}
|
||||
driver.beginRenderPass(rth, params);
|
||||
@@ -530,7 +532,7 @@ void FRenderer::ColorPass::endRenderPass(DriverApi& driver, Viewport const& view
|
||||
driver.endRenderPass();
|
||||
|
||||
// and we don't need the color buffer in the areas we don't use
|
||||
if (view->hasPostProcessPass()) {
|
||||
if (view.hasPostProcessPass()) {
|
||||
// discard parts of the color buffer we didn't render into
|
||||
const uint32_t large = std::numeric_limits<uint16_t>::max();
|
||||
driver.discardSubRenderTargetBuffers(rth, TargetBufferFlags::COLOR,
|
||||
@@ -541,32 +543,32 @@ void FRenderer::ColorPass::endRenderPass(DriverApi& driver, Viewport const& view
|
||||
}
|
||||
|
||||
void FRenderer::ColorPass::renderColorPass(FEngine& engine, JobSystem& js,
|
||||
Handle<HwRenderTarget> const rth, FView* view, Viewport const& scaledViewport,
|
||||
Handle<HwRenderTarget> const rth, FView& view, Viewport const& scaledViewport,
|
||||
GrowingSlice<Command>& commands) noexcept {
|
||||
|
||||
// start the froxelization immediately, it has no dependencies
|
||||
JobSystem::Job* jobFroxelize = js.createJob(nullptr,
|
||||
[&engine, view](JobSystem&, JobSystem::Job*) { view->froxelize(engine); });
|
||||
js.run(jobFroxelize);
|
||||
[&engine, &view](JobSystem&, JobSystem::Job*) { view.froxelize(engine); });
|
||||
jobFroxelize = js.runAndRetain(jobFroxelize);
|
||||
|
||||
CameraInfo const& cameraInfo = view->getCameraInfo();
|
||||
auto& soa = view->getScene()->getRenderableData();
|
||||
auto vr = view->getVisibleRenderables();
|
||||
CameraInfo const& cameraInfo = view.getCameraInfo();
|
||||
auto& soa = view.getScene()->getRenderableData();
|
||||
auto vr = view.getVisibleRenderables();
|
||||
|
||||
// populate the RenderPrimitive array with the proper LOD
|
||||
view->updatePrimitivesLod(engine, cameraInfo, soa, vr);
|
||||
view.updatePrimitivesLod(engine, cameraInfo, soa, vr);
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
view->prepareCamera(cameraInfo, scaledViewport);
|
||||
view->commitUniforms(driver);
|
||||
view.prepareCamera(cameraInfo, scaledViewport);
|
||||
view.commitUniforms(driver);
|
||||
|
||||
RenderPass::RenderFlags flags = 0;
|
||||
if (view->hasShadowing()) flags |= RenderPass::HAS_SHADOWING;
|
||||
if (view->hasDirectionalLight()) flags |= RenderPass::HAS_DIRECTIONAL_LIGHT;
|
||||
if (view->hasDynamicLighting()) flags |= RenderPass::HAS_DYNAMIC_LIGHTING;
|
||||
if (view.hasShadowing()) flags |= RenderPass::HAS_SHADOWING;
|
||||
if (view.hasDirectionalLight()) flags |= RenderPass::HAS_DIRECTIONAL_LIGHT;
|
||||
if (view.hasDynamicLighting()) flags |= RenderPass::HAS_DYNAMIC_LIGHTING;
|
||||
|
||||
CommandTypeFlags commandType;
|
||||
switch (view->getDepthPrepass()) {
|
||||
switch (view.getDepthPrepass()) {
|
||||
case View::DepthPrepass::DEFAULT:
|
||||
// TODO: better default strategy (can even change on a per-frame basis)
|
||||
#ifdef ANDROID
|
||||
@@ -585,7 +587,7 @@ void FRenderer::ColorPass::renderColorPass(FEngine& engine, JobSystem& js,
|
||||
|
||||
ColorPass colorPass("ColorPass", js, jobFroxelize, view, rth);
|
||||
driver.pushGroupMarker("Color Pass");
|
||||
colorPass.render(engine, js, *view->getScene(), vr, commandType, flags, cameraInfo, scaledViewport, commands);
|
||||
colorPass.render(engine, js, *view.getScene(), vr, commandType, flags, cameraInfo, scaledViewport, commands);
|
||||
driver.popGroupMarker();
|
||||
}
|
||||
|
||||
@@ -601,11 +603,11 @@ void FRenderer::ShadowPass::beginRenderPass(driver::DriverApi& driver, Viewport
|
||||
}
|
||||
|
||||
void FRenderer::ShadowPass::renderShadowMap(FEngine& engine, JobSystem& js,
|
||||
FView* view, GrowingSlice<Command>& commands) noexcept {
|
||||
FView& view, GrowingSlice<Command>& commands) noexcept {
|
||||
|
||||
auto& soa = view->getScene()->getRenderableData();
|
||||
auto vr = view->getVisibleShadowCasters();
|
||||
ShadowMap const& shadowMap = view->getShadowMap();
|
||||
auto& soa = view.getScene()->getRenderableData();
|
||||
auto vr = view.getVisibleShadowCasters();
|
||||
ShadowMap const& shadowMap = view.getShadowMap();
|
||||
Viewport const& viewport = shadowMap.getViewport();
|
||||
FCamera const& camera = shadowMap.getCamera();
|
||||
|
||||
@@ -619,20 +621,20 @@ void FRenderer::ShadowPass::renderShadowMap(FEngine& engine, JobSystem& js,
|
||||
};
|
||||
|
||||
// populate the RenderPrimitive array with the proper LOD
|
||||
view->updatePrimitivesLod(engine, cameraInfo, soa, vr);
|
||||
view.updatePrimitivesLod(engine, cameraInfo, soa, vr);
|
||||
|
||||
driver::DriverApi& driver = engine.getDriverApi();
|
||||
view->prepareCamera(cameraInfo, viewport);
|
||||
view->commitUniforms(driver);
|
||||
view.prepareCamera(cameraInfo, viewport);
|
||||
view.commitUniforms(driver);
|
||||
|
||||
RenderPass::RenderFlags flags = 0;
|
||||
if (view->hasShadowing()) flags |= RenderPass::HAS_SHADOWING;
|
||||
if (view->hasDirectionalLight()) flags |= RenderPass::HAS_DIRECTIONAL_LIGHT;
|
||||
if (view->hasDynamicLighting()) flags |= RenderPass::HAS_DYNAMIC_LIGHTING;
|
||||
if (view.hasShadowing()) flags |= RenderPass::HAS_SHADOWING;
|
||||
if (view.hasDirectionalLight()) flags |= RenderPass::HAS_DIRECTIONAL_LIGHT;
|
||||
if (view.hasDynamicLighting()) flags |= RenderPass::HAS_DYNAMIC_LIGHTING;
|
||||
|
||||
ShadowPass shadowPass("ShadowPass", shadowMap);
|
||||
driver.pushGroupMarker("Shadow map Pass");
|
||||
shadowPass.render(engine, js, *view->getScene(), vr, CommandTypeFlags::SHADOW, flags, cameraInfo, viewport, commands);
|
||||
shadowPass.render(engine, js, *view.getScene(), vr, CommandTypeFlags::SHADOW, flags, cameraInfo, viewport, commands);
|
||||
driver.popGroupMarker();
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ void FRenderer::render(FView const* view) {
|
||||
auto masterJob = js.setMasterJob(js.createJob());
|
||||
|
||||
// execute the render pass
|
||||
renderJob(rootArena, const_cast<FView*>(view));
|
||||
renderJob(rootArena, const_cast<FView&>(*view));
|
||||
|
||||
// make sure to flush the command buffer
|
||||
engine.flush();
|
||||
@@ -122,7 +122,7 @@ void FRenderer::render(FView const* view) {
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
FEngine& engine = getEngine();
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
@@ -132,10 +132,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
// DEBUG: driver commands must all happen from the same thread. Enforce that on debug builds.
|
||||
engine.getDriverApi().debugThreading();
|
||||
|
||||
Viewport const& vp = view->getViewport();
|
||||
const bool hasPostProcess = view->hasPostProcessPass();
|
||||
float2 scale = view->updateScale(mFrameInfoManager.getLastFrameTime());
|
||||
bool useFXAA = view->getAntiAliasing() == View::AntiAliasing::FXAA;
|
||||
Viewport const& vp = view.getViewport();
|
||||
const bool hasPostProcess = view.hasPostProcessPass();
|
||||
float2 scale = view.updateScale(mFrameInfoManager.getLastFrameTime());
|
||||
bool useFXAA = view.getAntiAliasing() == View::AntiAliasing::FXAA;
|
||||
if (!hasPostProcess) {
|
||||
// dynamic scaling and FXAA are part of the post-process phase and can't happen if
|
||||
// it's disabled.
|
||||
@@ -149,7 +149,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view->prepare(engine, driver, arena, svp);
|
||||
view.prepare(engine, driver, arena, svp);
|
||||
// TODO: froxelization could actually start now, instead of in ColorPass::renderColorPass()
|
||||
|
||||
/*
|
||||
@@ -165,7 +165,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
* Shadow pass
|
||||
*/
|
||||
|
||||
if (view->hasShadowing()) {
|
||||
if (view.hasShadowing()) {
|
||||
ShadowPass::renderShadowMap(engine, js, view, commands);
|
||||
recordHighWatermark(commands); // for debugging
|
||||
// reset the command buffer
|
||||
@@ -176,7 +176,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
* Depth + Color passes
|
||||
*/
|
||||
|
||||
const uint8_t useMSAA = view->getSampleCount();
|
||||
const uint8_t useMSAA = view.getSampleCount();
|
||||
const TextureFormat hdrFormat = getHdrFormat();
|
||||
const TextureFormat ldrFormat = getLdrFormat();
|
||||
RenderTargetPool::Target const* colorTarget = nullptr;
|
||||
@@ -226,7 +226,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView* view) {
|
||||
// because it's the last command, the TextureFormat is not relevant
|
||||
ppm.blit();
|
||||
}
|
||||
ppm.finish(view->getDiscardedTargetBuffers(), viewRenderTarget, vp, colorTarget, svp);
|
||||
ppm.finish(view.getDiscardedTargetBuffers(), viewRenderTarget, vp, colorTarget, svp);
|
||||
|
||||
driver.popGroupMarker();
|
||||
}
|
||||
@@ -273,7 +273,7 @@ void FRenderer::mirrorFrame(FSwapChain* dstSwapChain, Viewport const& dstViewpor
|
||||
viewRenderTarget, dstViewport.left, dstViewport.bottom, dstViewport.width, dstViewport.height,
|
||||
viewRenderTarget, srcViewport.left, srcViewport.bottom, srcViewport.width, srcViewport.height);
|
||||
if (flags & SET_PRESENTATION_TIME) {
|
||||
uint64_t monotonic_clock_ns (std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
int64_t monotonic_clock_ns (std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
driver.setPresentationTime(monotonic_clock_ns);
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain) {
|
||||
mSwapChain = swapChain;
|
||||
swapChain->makeCurrent(driver);
|
||||
|
||||
uint64_t monotonic_clock_ns (std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
int64_t monotonic_clock_ns (std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
driver.beginFrame(monotonic_clock_ns, mFrameId);
|
||||
driver.setPresentationTime(monotonic_clock_ns);
|
||||
|
||||
@@ -360,8 +360,7 @@ void FRenderer::endFrame() {
|
||||
// WARNING: while doing this we can't access any component manager
|
||||
auto& js = engine.getJobSystem();
|
||||
|
||||
auto job = jobs::createJob(js, nullptr, &FEngine::gc, &engine); // gc all managers
|
||||
js.run(job);
|
||||
auto job = js.runAndRetain(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
|
||||
|
||||
rtp.gc(); // gc post-processing targets (this can generate driver commands)
|
||||
engine.flush(); // flush command stream
|
||||
|
||||