mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-26 19:15:38 +08:00
feat(gltf): add gltf support (#8643)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_VG_LITE - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
Co-authored-by: Matt Kimball <greyworld@gmail.com> Co-authored-by: Liam Howatt <30486941+liamHowatt@users.noreply.github.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file lv_demo_gltf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DEMO_GLTF_H
|
||||
#define LV_DEMO_GLTF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../lv_demos.h"
|
||||
|
||||
#if LV_USE_DEMO_GLTF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
lv_obj_t * lv_demo_gltf(const char * path);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DEMO_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DEMO_GLTF_H*/
|
||||
@@ -43,6 +43,10 @@ extern "C" {
|
||||
#include "render/lv_demo_render.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_DEMO_GLTF
|
||||
#include "gltf/lv_demo_gltf.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
.. _gltf:
|
||||
|
||||
====
|
||||
glTF
|
||||
====
|
||||
|
||||
**glTF** (GL Transmission Format) is a royalty-free specification for efficient transmission and loading of 3D scenes and models.
|
||||
|
||||
The glTF extension in LVGL provides 3D model loading, rendering, and animation capabilities. It supports the full glTF 2.0 specification with advanced rendering features.
|
||||
|
||||
For a detailed introduction to glTF, see: https://www.khronos.org/gltf/
|
||||
|
||||
Features
|
||||
********
|
||||
|
||||
LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
|
||||
|
||||
**File Format Support:**
|
||||
|
||||
* Loading glTF (.gltf) and binary GLB (.glb) files from local filesystem
|
||||
* Support for hex-encoded bytes in source include files when filesystem is not available
|
||||
* JPG, PNG, and WebP compressed texture support
|
||||
* External texture files or textures embedded within the glTF source
|
||||
|
||||
**Rendering & Lighting:**
|
||||
|
||||
* Image-Based Lighting (IBL) for realistic environmental lighting
|
||||
* Punctual lighting support with animated light sources
|
||||
* Physically Based Rendering (PBR) materials with full texture support:
|
||||
|
||||
* Diffuse/albedo textures
|
||||
* Roughness and metallic workflow textures
|
||||
* Normal maps for surface detail
|
||||
* Ambient occlusion textures
|
||||
|
||||
**Advanced Materials:**
|
||||
|
||||
* Emissive materials for glowing effects and self-illuminated surfaces
|
||||
* Refractive materials with realistic distortion effects revealing geometry behind surfaces
|
||||
* Clearcoat material support for multi-layer surface effects (like automotive paint finishes)
|
||||
* Full transparency support with alpha blending
|
||||
|
||||
**Animation System:**
|
||||
|
||||
* Keyframe-based animations for object transformations
|
||||
* Single-skeleton skinned character animations
|
||||
* Animated punctual lights with dynamic lighting effects
|
||||
* Parameter binding for real-time monitoring and control of object properties (position, rotation, scale)
|
||||
* Dynamic parameter override from host application
|
||||
|
||||
**Camera & Viewport:**
|
||||
|
||||
* Programmatic viewport control with full camera manipulation
|
||||
* Support for cameras defined within 3D editor software
|
||||
* Multiple camera switching for different scene perspectives
|
||||
* Orthographic and perspective projection modes
|
||||
|
||||
**Rendering Quality:**
|
||||
|
||||
* Configurable antialiasing with multiple modes:
|
||||
|
||||
* Always-on for consistent quality
|
||||
* Always-off for maximum performance
|
||||
* Auto-on that activates when scene movement stops
|
||||
|
||||
* Flexible background rendering:
|
||||
|
||||
* Environment-based backgrounds using IBL
|
||||
* Solid color backgrounds
|
||||
* Transparent backgrounds for overlay effects
|
||||
|
||||
What is glTF?
|
||||
*************
|
||||
|
||||
glTF (Graphics Library Transmission Format) is a 3D file format that stores 3D model information in JSON format. It supports:
|
||||
|
||||
- **Geometry**: Meshes, primitives, and vertex data
|
||||
- **Materials**: PBR (Physically Based Rendering) materials with textures
|
||||
- **Animations**: Keyframe-based animations for nodes
|
||||
- **Cameras**: Perspective and orthographic camera definitions
|
||||
- **Scenes**: Hierarchical scene graphs with node transformations
|
||||
|
||||
glTF files can be stored as:
|
||||
|
||||
- **.gltf**: JSON format with external binary and image files
|
||||
- **.glb**: Binary format with all assets embedded in a single file
|
||||
|
||||
Features
|
||||
********
|
||||
|
||||
LVGL's glTF implementation provides comprehensive 3D rendering capabilities:
|
||||
|
||||
**File Format Support:**
|
||||
|
||||
* Loading glTF (.gltf) and binary GLB (.glb) files from local filesystem
|
||||
* Support for hex-encoded bytes in source include files when filesystem is not available
|
||||
* JPG, PNG, and WebP compressed texture support
|
||||
* External texture files or textures embedded within the glTF source
|
||||
|
||||
**Rendering & Lighting:**
|
||||
|
||||
* Image-Based Lighting (IBL) for realistic environmental lighting
|
||||
* Punctual lighting support with animated light sources
|
||||
* Physically Based Rendering (PBR) materials with full texture support:
|
||||
|
||||
* Diffuse/albedo textures
|
||||
* Roughness and metallic workflow textures
|
||||
* Normal maps for surface detail
|
||||
* Ambient occlusion textures
|
||||
|
||||
**Advanced Materials:**
|
||||
|
||||
* Emissive materials for glowing effects and self-illuminated surfaces
|
||||
* Refractive materials with realistic distortion effects revealing geometry behind surfaces
|
||||
* Clearcoat material support for multi-layer surface effects (like automotive paint finishes)
|
||||
* Full transparency support with alpha blending
|
||||
|
||||
**Animation System:**
|
||||
|
||||
* Keyframe-based animations for object transformations
|
||||
* Single-skeleton skinned character animations
|
||||
* Animated punctual lights with dynamic lighting effects
|
||||
* Parameter binding for real-time monitoring and control of object properties (position, rotation, scale)
|
||||
* Dynamic parameter override from host application
|
||||
|
||||
**Camera & Viewport:**
|
||||
|
||||
* Programmatic viewport control with full camera manipulation
|
||||
* Support for cameras defined within 3D editor software
|
||||
* Multiple camera switching for different scene perspectives
|
||||
* Orthographic and perspective projection modes
|
||||
|
||||
**Rendering Quality:**
|
||||
|
||||
* Configurable antialiasing with multiple modes:
|
||||
|
||||
* Always-on for consistent quality
|
||||
* Always-off for maximum performance
|
||||
* Auto-on that activates when scene movement stops
|
||||
|
||||
* Flexible background rendering:
|
||||
|
||||
* Environment-based backgrounds using IBL
|
||||
* Solid color backgrounds
|
||||
* Transparent backgrounds for overlay effects
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
The glTF extension relies on **OpenGL ES 3.0** for 3D rendering. LVGL includes built-in support for OpenGL ES through the GLFW driver, which provides cross-platform window management and OpenGL context creation.
|
||||
|
||||
The renderer uses OpenGL ES 3.0 shaders (GLSL version 300 es) to provide modern PBR (Physically Based Rendering) capabilities.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The glTF extension requires the following external libraries:
|
||||
|
||||
:fastgltf: A C++20 library for parsing glTF files (https://github.com/spnda/fastgltf)
|
||||
:libwebp: WebP image format support for textures (https://github.com/webmproject/libwebp)
|
||||
|
||||
Setup
|
||||
*****
|
||||
|
||||
1. **Install Dependencies with CMake**
|
||||
|
||||
The recommended way to integrate the required libraries is using CMake's FetchContent:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(FetchContent)
|
||||
# Set policy to allow to run the target_link_libraries cmd on targets that are
|
||||
# build in another directory. Currently, the linking is not handled by
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
# Fetch fastgltf library
|
||||
FetchContent_Declare(
|
||||
fastgltf
|
||||
GIT_REPOSITORY https://github.com/spnda/fastgltf
|
||||
GIT_TAG 4e2261350888bae7c35a1f39991f6233d57795f5)
|
||||
set(FASTGLTF_ENABLE_DEPRECATED_EXT
|
||||
ON
|
||||
CACHE BOOL "" FORCE)
|
||||
set(FASTGLTF_DIFFUSE_TRANSMISSION_SUPPORT
|
||||
ON
|
||||
CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(fastgltf)
|
||||
|
||||
# Fetch libwebp library
|
||||
FetchContent_Declare(
|
||||
webp
|
||||
GIT_REPOSITORY https://github.com/webmproject/libwebp
|
||||
GIT_TAG fa6f56496a442eed59b103250021e4b14ebf1427)
|
||||
FetchContent_MakeAvailable(webp)
|
||||
|
||||
# Link libraries to LVGL
|
||||
target_link_libraries(lvgl PUBLIC webp fastgltf)
|
||||
|
||||
2. **Enable glTF Support**
|
||||
|
||||
Set :c:macro:`LV_USE_GLTF` to ``1`` in ``lv_conf.h``.
|
||||
|
||||
Also enable other required dependencies by setting the following defines to ``1``:
|
||||
|
||||
- :c:macro:`LV_USE_OPENGLES`
|
||||
- :c:macro:`LV_USE_DRAW_OPENGLES`
|
||||
- :c:macro:`LV_USE_3DTEXTURE`
|
||||
|
||||
3. **Setup OpenGL ES Driver**
|
||||
|
||||
Follow the OpenGL ES driver setup documentation (:ref:``opengl_es_driver``) to configure GLFW and OpenGL ES support for your platform.
|
||||
|
||||
4. **Basic Setup Example**
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
|
||||
/* GLFW setup */
|
||||
lv_glfw_window_t *window = lv_glfw_window_create(WINDOW_WIDTH, WINDOW_HEIGHT, true);
|
||||
lv_display_t *display = lv_opengles_texture_create(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
unsigned int texture_id = lv_opengles_texture_get_texture_id(display);
|
||||
lv_glfw_window_add_texture(window, texture_id, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
|
||||
/* Load and display glTF demo */
|
||||
lv_demo_gltf("A:<path/to/gltf>");
|
||||
|
||||
while (1) {
|
||||
uint32_t time_until_next = lv_timer_handler();
|
||||
if (time_until_next == LV_NO_TIMER_READY) {
|
||||
time_until_next = LV_DEF_REFR_PERIOD;
|
||||
}
|
||||
lv_delay_ms(time_until_next);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Demo Application
|
||||
----------------
|
||||
|
||||
LVGL provides a complete glTF demo that showcases the capabilities of the 3D viewer:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_demo_gltf("A:<path/to/your/model.glb>");
|
||||
|
||||
This demo creates an interactive 3D viewer with:
|
||||
|
||||
- Mouse/touch controls for camera rotation
|
||||
- Zoom controls
|
||||
- Animation playback controls
|
||||
- Camera switching
|
||||
- Visual settings adjustment
|
||||
|
||||
Basic glTF Viewer Creation
|
||||
--------------------------
|
||||
|
||||
Here's how to create a basic glTF viewer and load a model:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Create a glTF viewer object */
|
||||
lv_obj_t * gltf = lv_gltf_create(lv_screen_active());
|
||||
|
||||
/* Load a glTF model from file */
|
||||
lv_gltf_model_t * model = lv_gltf_load_model_from_file(gltf,
|
||||
"A:path/to/your/model.glb");
|
||||
|
||||
if (model == NULL) {
|
||||
LV_LOG_ERROR("Failed to load glTF model");
|
||||
return;
|
||||
}
|
||||
|
||||
Camera Controls
|
||||
---------------
|
||||
|
||||
The glTF viewer provides comprehensive camera controls:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Set camera rotation */
|
||||
lv_gltf_set_yaw(gltf, 45.0f); /* Horizontal rotation */
|
||||
lv_gltf_set_pitch(gltf, -30.0f); /* Vertical rotation */
|
||||
|
||||
/* Set camera distance */
|
||||
lv_gltf_set_distance(gltf, 5.0f);
|
||||
|
||||
/* Set field of view (0 for orthographic) */
|
||||
lv_gltf_set_fov(gltf, 60.0f);
|
||||
|
||||
/* Set the focal point - The position the camera is pointing at */
|
||||
lv_gltf_set_focal_x(gltf, 0.0f);
|
||||
lv_gltf_set_focal_y(gltf, 0.0f);
|
||||
lv_gltf_set_focal_z(gltf, 0.0f);
|
||||
|
||||
/* Recenter camera on model */
|
||||
lv_gltf_recenter(gltf, model);
|
||||
|
||||
Animation Control
|
||||
-----------------
|
||||
|
||||
Control model animations with these functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Get number of animations */
|
||||
size_t anim_count = lv_gltf_model_get_animation_count(model);
|
||||
|
||||
/* Play a specific animation */
|
||||
lv_gltf_model_play_animation(model, 0);
|
||||
|
||||
/* Control animation speed */
|
||||
lv_gltf_set_animation_speed(gltf, LV_GLTF_ANIM_SPEED_2X);
|
||||
|
||||
/* Pause/resume animation */
|
||||
lv_gltf_model_pause_animation(model);
|
||||
bool is_paused = lv_gltf_model_is_animation_paused(model);
|
||||
|
||||
Visual Settings
|
||||
---------------
|
||||
|
||||
Customize the visual appearance of your 3D scene:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Background settings */
|
||||
lv_gltf_set_background_mode(gltf, LV_GLTF_BG_ENVIRONMENT);
|
||||
lv_gltf_set_background_blur(gltf, 50);
|
||||
|
||||
/* Lighting and exposure */
|
||||
lv_gltf_set_env_brightness(gltf, 150);
|
||||
lv_gltf_set_image_exposure(gltf, 1.2f);
|
||||
|
||||
/* Anti-aliasing */
|
||||
lv_gltf_set_antialiasing_mode(gltf, LV_GLTF_AA_DYNAMIC);
|
||||
|
||||
Multi-Model Support
|
||||
-------------------
|
||||
|
||||
Load and manage multiple glTF models in a single viewer:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Load multiple models */
|
||||
lv_gltf_model_t * model1 = lv_gltf_load_model_from_file(gltf, "A:model1.glb");
|
||||
lv_gltf_model_t * model2 = lv_gltf_load_model_from_file(gltf, "A:model2.glb");
|
||||
|
||||
/* Get model information */
|
||||
size_t model_count = lv_gltf_get_model_count(gltf);
|
||||
lv_gltf_model_t * primary = lv_gltf_get_primary_model(gltf);
|
||||
lv_gltf_model_t * specific = lv_gltf_get_model_by_index(gltf, 1);
|
||||
|
||||
Model Inspection
|
||||
----------------
|
||||
|
||||
Query model properties to understand its structure:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Get model component counts */
|
||||
size_t mesh_count = lv_gltf_model_get_mesh_count(model);
|
||||
size_t material_count = lv_gltf_model_get_material_count(model);
|
||||
size_t texture_count = lv_gltf_model_get_texture_count(model);
|
||||
size_t image_count = lv_gltf_model_get_image_count(model);
|
||||
size_t node_count = lv_gltf_model_get_node_count(model);
|
||||
size_t scene_count = lv_gltf_model_get_scene_count(model);
|
||||
size_t camera_count = lv_gltf_model_get_camera_count(model);
|
||||
|
||||
Widget Architecture
|
||||
*******************
|
||||
|
||||
The glTF widget extends the ``lv_3dtexture`` widget, which means:
|
||||
|
||||
- All standard ``lv_obj`` functions work with glTF widgets (positioning, sizing, styling, etc.)
|
||||
- All ``lv_3dtexture`` functions are also available for advanced 3D texture management
|
||||
|
||||
Animation Speed System
|
||||
----------------------
|
||||
|
||||
Animation speeds use integer values to avoid floating-point arithmetic:
|
||||
|
||||
- The speed ratio is calculated as: ``speed_value / LV_GLTF_ANIM_SPEED_NORMAL``
|
||||
- ``LV_GLTF_ANIM_SPEED_NORMAL`` equals 1000, representing 1.0x (normal) speed
|
||||
- Values greater than 1000 speed up animations (e.g., 2000 = 2.0x speed)
|
||||
- Values less than 1000 slow down animations (e.g., 500 = 0.5x speed)
|
||||
|
||||
.. _gltf_example:
|
||||
|
||||
Examples
|
||||
********
|
||||
|
||||
.. include:: ../../examples/libs/gltf/index.rst
|
||||
|
||||
.. _gltf_api:
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
.. API startswith: lv_gltf_
|
||||
@@ -17,6 +17,7 @@
|
||||
freetype
|
||||
fs
|
||||
gif
|
||||
gltf
|
||||
lfs
|
||||
libjpeg_turbo
|
||||
libpng
|
||||
|
||||
@@ -59,6 +59,7 @@ get_directory_property(HAS_PARENT_SCOPE PARENT_DIRECTORY)
|
||||
|
||||
# Set sources used for LVGL components
|
||||
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c
|
||||
${LVGL_ROOT_DIR}/src/*.cpp
|
||||
${LVGL_ROOT_DIR}/src/*.S)
|
||||
file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
|
||||
file(GLOB_RECURSE DEMO_SOURCES ${LVGL_ROOT_DIR}/demos/*.c)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Open a GLTF from a file and make it spin forever like a platter
|
||||
---------------------------------------------------------------
|
||||
|
||||
.. lv_example:: libs/gltf/lv_example_gltf_1
|
||||
:language: c
|
||||
|
||||
|
||||
Open a GLTF from a file and iterate through each camera
|
||||
-------------------------------------------------------
|
||||
|
||||
.. lv_example:: libs/gltf/lv_example_gltf_2
|
||||
:language: c
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file lv_example_gltf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_EXAMPLE_GLTF_H
|
||||
#define LV_EXAMPLE_GLTF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_examples.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_example_gltf_1(void);
|
||||
void lv_example_gltf_2(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_EXAMPLE_GLTF_H*/
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "lv_example_gltf.h"
|
||||
|
||||
#if LV_BUILD_EXAMPLES
|
||||
|
||||
#if LV_USE_GLTF
|
||||
/**
|
||||
* Timer callback to continuously rotate the model
|
||||
*/
|
||||
static void spin_timer_cb(lv_timer_t * timer)
|
||||
{
|
||||
lv_obj_t * gltf = lv_timer_get_user_data(timer);
|
||||
|
||||
float yaw = lv_gltf_get_yaw(gltf);
|
||||
yaw += 1.0f;
|
||||
if(yaw >= 360.0f) {
|
||||
yaw = 0.0f;
|
||||
}
|
||||
lv_gltf_set_yaw(gltf, yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a GLTF from a file and make it spin forever like a platter
|
||||
*/
|
||||
void lv_example_gltf_1(void)
|
||||
{
|
||||
lv_obj_t * gltf = lv_gltf_create(lv_screen_active());
|
||||
lv_gltf_model_t * model = lv_gltf_load_model_from_file(gltf,
|
||||
"A:lvgl/examples/libs/gltf/webp_diffuse_transmission_plant.glb");
|
||||
lv_obj_set_size(gltf, LV_PCT(100), LV_PCT(100));
|
||||
|
||||
lv_gltf_model_play_animation(model, 0);
|
||||
lv_gltf_set_pitch(gltf, -45.f);
|
||||
lv_timer_create(spin_timer_cb, LV_DEF_REFR_PERIOD, gltf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void lv_example_gltf_1(void)
|
||||
{
|
||||
/*TODO
|
||||
*fallback for online examples*/
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "glTF web support is coming soon");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "lv_example_gltf.h"
|
||||
|
||||
#if LV_BUILD_EXAMPLES
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
static size_t camera_count;
|
||||
static size_t current_camera;
|
||||
static uint32_t current_speed = LV_GLTF_ANIM_SPEED_HALF;
|
||||
|
||||
/**
|
||||
* Timer callback that updates the current camera and the current animation speed
|
||||
*/
|
||||
static void timer_cb(lv_timer_t * timer)
|
||||
{
|
||||
lv_obj_t * gltf = (lv_obj_t *) lv_timer_get_user_data(timer);
|
||||
current_camera = (current_camera + 1) % (camera_count + 1);
|
||||
current_speed *= 2;
|
||||
|
||||
if(current_speed > LV_GLTF_ANIM_SPEED_4X) {
|
||||
current_speed = LV_GLTF_ANIM_SPEED_HALF;
|
||||
}
|
||||
|
||||
LV_LOG_USER("Setting camera %zu and animation speed %" PRIu32, current_camera, current_speed);
|
||||
lv_gltf_set_camera(gltf, current_camera);
|
||||
lv_gltf_set_animation_speed(gltf, current_speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a GLTF from a file and loop through the model cameras and multiple animation speeds
|
||||
*/
|
||||
void lv_example_gltf_2(void)
|
||||
{
|
||||
lv_obj_t * gltf = lv_gltf_create(lv_screen_active());
|
||||
lv_gltf_model_t * model = lv_gltf_load_model_from_file(gltf,
|
||||
"A:lvgl/examples/libs/gltf/webp_diffuse_transmission_plant.glb");
|
||||
|
||||
|
||||
lv_gltf_set_animation_speed(gltf, current_speed);
|
||||
lv_gltf_model_play_animation(model, 0);
|
||||
lv_obj_set_size(gltf, LV_PCT(100), LV_PCT(100));
|
||||
camera_count = lv_gltf_get_camera_count(gltf);
|
||||
lv_gltf_set_pitch(gltf, -45.f);
|
||||
lv_timer_create(timer_cb, 5000, gltf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void lv_example_gltf_2(void)
|
||||
{
|
||||
/*TODO
|
||||
*fallback for online examples*/
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "glTF web support is coming soon");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
Binary file not shown.
@@ -18,6 +18,7 @@ extern "C" {
|
||||
#include "ffmpeg/lv_example_ffmpeg.h"
|
||||
#include "freetype/lv_example_freetype.h"
|
||||
#include "gif/lv_example_gif.h"
|
||||
#include "gltf/lv_example_gltf.h"
|
||||
#include "lodepng/lv_example_lodepng.h"
|
||||
#include "libpng/lv_example_libpng.h"
|
||||
#include "qrcode/lv_example_qrcode.h"
|
||||
|
||||
@@ -986,6 +986,9 @@
|
||||
/** Rlottie library */
|
||||
#define LV_USE_RLOTTIE 0
|
||||
|
||||
/** Requires `LV_USE_3DTEXTURE = 1` */
|
||||
#define LV_USE_GLTF 0
|
||||
|
||||
/** Enable Vector Graphic APIs
|
||||
* - Requires `LV_USE_MATRIX = 1` */
|
||||
#define LV_USE_VECTOR_GRAPHIC 0
|
||||
@@ -1409,6 +1412,9 @@
|
||||
/** Vector graphic demo */
|
||||
#define LV_USE_DEMO_VECTOR_GRAPHIC 0
|
||||
|
||||
/** GLTF demo */
|
||||
#define LV_USE_DEMO_GLTF 0
|
||||
|
||||
/*---------------------------
|
||||
* Demos from lvgl/lv_demos
|
||||
---------------------------*/
|
||||
|
||||
@@ -107,6 +107,8 @@ extern "C" {
|
||||
#include "src/libs/fsdrv/lv_fsdrv.h"
|
||||
#include "src/libs/lodepng/lv_lodepng.h"
|
||||
#include "src/libs/libpng/lv_libpng.h"
|
||||
#include "src/libs/gltf/gltf_data/lv_gltf_model.h"
|
||||
#include "src/libs/gltf/gltf_view/lv_gltf.h"
|
||||
#include "src/libs/gif/lv_gif.h"
|
||||
#include "src/libs/qrcode/lv_qrcode.h"
|
||||
#include "src/libs/tjpgd/lv_tjpgd.h"
|
||||
|
||||
@@ -41,6 +41,8 @@ void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc)
|
||||
lv_memzero(dsc, sizeof(lv_draw_3d_dsc_t));
|
||||
dsc->base.dsc_size = sizeof(lv_draw_3d_dsc_t);
|
||||
dsc->tex_id = LV_3DTEXTURE_ID_NULL;
|
||||
dsc->h_flip = false;
|
||||
dsc->v_flip = false;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ extern "C" {
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
lv_3dtexture_id_t tex_id;
|
||||
bool h_flip;
|
||||
bool v_flip;
|
||||
lv_opa_t opa;
|
||||
} lv_draw_3d_dsc_t;
|
||||
|
||||
|
||||
@@ -416,7 +416,15 @@ static void blend_texture_layer(lv_draw_task_t * t)
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
// TODO rotation
|
||||
lv_opengles_render_texture(src_texture, &area, draw_dsc->opa, targ_tex_w, targ_tex_h, &t->clip_area, false);
|
||||
bool h_flip = false;
|
||||
bool v_flip = false;
|
||||
if(t->type == LV_DRAW_TASK_TYPE_3D) {
|
||||
lv_draw_3d_dsc_t * _3d_dsc = (lv_draw_3d_dsc_t *)t->draw_dsc;
|
||||
h_flip = _3d_dsc->h_flip;
|
||||
v_flip = _3d_dsc->v_flip;
|
||||
}
|
||||
lv_opengles_render_texture(src_texture, &area, draw_dsc->opa, targ_tex_w, targ_tex_h, &t->clip_area, h_flip,
|
||||
v_flip);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
@@ -430,7 +438,13 @@ static void draw_from_cached_texture(lv_draw_task_t * t)
|
||||
lv_draw_opengles_unit_t * u = (lv_draw_opengles_unit_t *)t->draw_unit;
|
||||
cache_data_t data_to_find;
|
||||
data_to_find.draw_dsc = (lv_draw_dsc_base_t *)t->draw_dsc;
|
||||
|
||||
bool h_flip = false;
|
||||
bool v_flip = false;
|
||||
if(t->type == LV_DRAW_TASK_TYPE_3D) {
|
||||
lv_draw_3d_dsc_t * _3d_dsc = (lv_draw_3d_dsc_t *)t->draw_dsc;
|
||||
h_flip = _3d_dsc->h_flip;
|
||||
v_flip = _3d_dsc->v_flip;
|
||||
}
|
||||
data_to_find.w = lv_area_get_width(&t->_real_area);
|
||||
data_to_find.h = lv_area_get_height(&t->_real_area);
|
||||
data_to_find.texture = 0;
|
||||
@@ -503,7 +517,7 @@ static void draw_from_cached_texture(lv_draw_task_t * t)
|
||||
lv_area_move(&t->clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_area_t render_area = t->_real_area;
|
||||
lv_area_move(&render_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_opengles_render_texture(texture, &render_area, 0xff, targ_tex_w, targ_tex_h, &t->clip_area, true);
|
||||
lv_opengles_render_texture(texture, &render_area, 0xff, targ_tex_w, targ_tex_h, &t->clip_area, h_flip, v_flip);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
@@ -624,7 +638,8 @@ static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc
|
||||
lv_area_t clip_area = t->clip_area;
|
||||
lv_area_move(&clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
|
||||
lv_opengles_render_texture(dsc->tex_id, coords, dsc->opa, targ_tex_w, targ_tex_h, &clip_area, true);
|
||||
lv_opengles_render_texture(dsc->tex_id, coords, dsc->opa, targ_tex_w, targ_tex_h, &clip_area, dsc->h_flip,
|
||||
!dsc->v_flip);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#if LV_USE_OPENGLES
|
||||
#include <stdlib.h>
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "../../stdlib/lv_sprintf.h"
|
||||
#include "../../stdlib/lv_string.h"
|
||||
#include "../../core/lv_global.h"
|
||||
#include "../../display/lv_display_private.h"
|
||||
@@ -67,30 +68,41 @@ static lv_ll_t glfw_window_ll;
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool use_mouse_indev)
|
||||
lv_glfw_window_t * lv_glfw_window_create_ex(int32_t hor_res, int32_t ver_res, bool use_mouse_indev, bool h_flip,
|
||||
bool v_flip, const char * title)
|
||||
{
|
||||
LV_ASSERT_NULL(title);
|
||||
if(lv_glfw_init() != 0) {
|
||||
LV_LOG_ERROR("Failed to init glfw");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_glfw_window_t * window = lv_ll_ins_tail(&glfw_window_ll);
|
||||
LV_ASSERT_MALLOC(window);
|
||||
if(window == NULL) return NULL;
|
||||
if(window == NULL) {
|
||||
LV_LOG_ERROR("Failed to create glfw window");
|
||||
return NULL;
|
||||
}
|
||||
lv_memzero(window, sizeof(*window));
|
||||
|
||||
/* Create window with graphics context */
|
||||
lv_glfw_window_t * existing_window = lv_ll_get_head(&glfw_window_ll);
|
||||
window->window = glfwCreateWindow(hor_res, ver_res, "LVGL Simulator", NULL,
|
||||
window->window = glfwCreateWindow(hor_res, ver_res, title, NULL,
|
||||
existing_window ? existing_window->window : NULL);
|
||||
if(window->window == NULL) {
|
||||
LV_LOG_ERROR("glfwCreateWindow fail.");
|
||||
LV_LOG_ERROR("glfwCreateWindow fail");
|
||||
lv_ll_remove(&glfw_window_ll, window);
|
||||
lv_free(window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
glfwSetWindowTitle(window->window, title);
|
||||
|
||||
window->h_flip = h_flip;
|
||||
window->v_flip = v_flip;
|
||||
window->hor_res = hor_res;
|
||||
window->ver_res = ver_res;
|
||||
|
||||
lv_ll_init(&window->textures, sizeof(lv_glfw_texture_t));
|
||||
window->use_indev = use_mouse_indev;
|
||||
|
||||
@@ -104,6 +116,16 @@ lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool
|
||||
return window;
|
||||
}
|
||||
|
||||
lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool use_mouse_indev)
|
||||
{
|
||||
return lv_glfw_window_create_ex(hor_res, ver_res, use_mouse_indev, false, false, "LVGL Simulator");
|
||||
}
|
||||
|
||||
void lv_glfw_window_set_title(lv_glfw_window_t * window, const char * new_title)
|
||||
{
|
||||
glfwSetWindowTitle(window->window, new_title);
|
||||
}
|
||||
|
||||
void lv_glfw_window_delete(lv_glfw_window_t * window)
|
||||
{
|
||||
glfwDestroyWindow(window->window);
|
||||
@@ -127,6 +149,12 @@ void * lv_glfw_window_get_glfw_window(lv_glfw_window_t * window)
|
||||
return (void *)(window->window);
|
||||
}
|
||||
|
||||
void lv_glfw_window_set_flip(lv_glfw_window_t * window, bool h_flip, bool v_flip)
|
||||
{
|
||||
window->h_flip = h_flip;
|
||||
window->v_flip = v_flip;
|
||||
}
|
||||
|
||||
lv_glfw_texture_t * lv_glfw_window_add_texture(lv_glfw_window_t * window, unsigned int texture_id, int32_t w, int32_t h)
|
||||
{
|
||||
lv_glfw_texture_t * texture = lv_ll_ins_tail(&window->textures);
|
||||
@@ -308,10 +336,10 @@ static void window_update_handler(lv_timer_t * t)
|
||||
lv_area_t clip_area = texture->area;
|
||||
#if LV_USE_DRAW_OPENGLES
|
||||
lv_opengles_render_texture(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res,
|
||||
&clip_area, texture_disp == NULL);
|
||||
&clip_area, window->h_flip, texture_disp == NULL ? window->v_flip : !window->v_flip);
|
||||
#else
|
||||
lv_opengles_render_texture(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res,
|
||||
&clip_area, true);
|
||||
&clip_area, window->h_flip, window->v_flip);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -371,8 +399,18 @@ static void proc_mouse(lv_glfw_window_t * window)
|
||||
LV_LL_READ_BACK(&window->textures, texture) {
|
||||
if(lv_area_is_point_on(&texture->area, &window->mouse_last_point, 0)) {
|
||||
/* adjust the mouse pointer coordinates so that they are relative to the texture */
|
||||
texture->indev_last_point.x = window->mouse_last_point.x - texture->area.x1;
|
||||
texture->indev_last_point.y = window->mouse_last_point.y - texture->area.y1;
|
||||
if(window->h_flip) {
|
||||
texture->indev_last_point.x = texture->area.x2 - window->mouse_last_point.x;
|
||||
}
|
||||
else {
|
||||
texture->indev_last_point.x = window->mouse_last_point.x - texture->area.x1;
|
||||
}
|
||||
if(window->v_flip) {
|
||||
texture->indev_last_point.y = (texture->area.y2 - window->mouse_last_point.y);
|
||||
}
|
||||
else {
|
||||
texture->indev_last_point.y = (window->mouse_last_point.y - texture->area.y1);
|
||||
}
|
||||
texture->indev_last_state = window->mouse_last_state;
|
||||
lv_indev_read(texture->indev);
|
||||
break;
|
||||
|
||||
@@ -41,12 +41,40 @@ extern "C" {
|
||||
*/
|
||||
lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool use_mouse_indev);
|
||||
|
||||
/**
|
||||
* Create a GLFW window with no textures and initialize OpenGL
|
||||
* @param hor_res width in pixels of the window
|
||||
* @param ver_res height in pixels of the window
|
||||
* @param use_mouse_indev send pointer indev input to LVGL display textures
|
||||
* @param h_flip Should the window contents be horizontally mirrored?
|
||||
* @param v_flip Should the window contents be vertically mirrored?
|
||||
* @param title The window title
|
||||
* @return the new GLFW window handle
|
||||
*/
|
||||
lv_glfw_window_t * lv_glfw_window_create_ex(int32_t hor_res, int32_t ver_res, bool use_mouse_indev, bool h_flip,
|
||||
bool v_flip, const char * title);
|
||||
|
||||
/**
|
||||
* Set the window's title text
|
||||
* @param window GLFW window to configure
|
||||
* @param new_title The new title text
|
||||
*/
|
||||
void lv_glfw_window_set_title(lv_glfw_window_t * window, const char * new_title);
|
||||
|
||||
/**
|
||||
* Delete a GLFW window. If it is the last one, the process will exit
|
||||
* @param window GLFW window to delete
|
||||
*/
|
||||
void lv_glfw_window_delete(lv_glfw_window_t * window);
|
||||
|
||||
/**
|
||||
* Set the horizontal / vertical flipping of a GLFW window
|
||||
* @param window GLFW window to configure
|
||||
* @param h_flip Should the window contents be horizontally mirrored?
|
||||
* @param v_flip Should the window contents be vertically mirrored?
|
||||
*/
|
||||
void lv_glfw_window_set_flip(lv_glfw_window_t * window, bool h_flip, bool v_flip);
|
||||
|
||||
/**
|
||||
* Get the GLFW window handle for an lv_glfw_window
|
||||
* @param window GLFW window to return the handle of
|
||||
|
||||
@@ -36,6 +36,8 @@ struct _lv_glfw_window_t {
|
||||
GLFWwindow * window;
|
||||
int32_t hor_res;
|
||||
int32_t ver_res;
|
||||
bool h_flip;
|
||||
bool v_flip;
|
||||
lv_ll_t textures;
|
||||
lv_point_t mouse_last_point;
|
||||
lv_indev_state_t mouse_last_state;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#if LV_USE_OPENGLES
|
||||
|
||||
#include "../../misc/lv_types.h"
|
||||
#include "lv_opengles_debug.h"
|
||||
#include "lv_opengles_driver.h"
|
||||
|
||||
@@ -28,7 +29,8 @@
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void lv_opengles_render_internal(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
|
||||
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area, bool flip, lv_color_t fill_color);
|
||||
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area,
|
||||
bool h_flip, bool v_flip, lv_color_t fill_color);
|
||||
static void lv_opengles_enable_blending(void);
|
||||
static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size);
|
||||
static void lv_opengles_vertex_buffer_deinit(void);
|
||||
@@ -178,14 +180,15 @@ void lv_opengles_deinit(void)
|
||||
}
|
||||
|
||||
void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
|
||||
int32_t disp_h, const lv_area_t * texture_clip_area, bool flip)
|
||||
int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip)
|
||||
{
|
||||
lv_opengles_render_internal(texture, texture_area, opa, disp_w, disp_h, texture_clip_area, flip, lv_color_black());
|
||||
lv_opengles_render_internal(texture, texture_area, opa, disp_w, disp_h, texture_clip_area, h_flip, v_flip,
|
||||
lv_color_black());
|
||||
}
|
||||
|
||||
void lv_opengles_render_fill(lv_color_t color, const lv_area_t * area, lv_opa_t opa, int32_t disp_w, int32_t disp_h)
|
||||
{
|
||||
lv_opengles_render_internal(0, area, opa, disp_w, disp_h, area, false, color);
|
||||
lv_opengles_render_internal(0, area, opa, disp_w, disp_h, area, false, false, color);
|
||||
}
|
||||
|
||||
void lv_opengles_render_clear(void)
|
||||
@@ -203,7 +206,7 @@ void lv_opengles_viewport(int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
**********************/
|
||||
|
||||
static void lv_opengles_render_internal(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa,
|
||||
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area, bool flip, lv_color_t fill_color)
|
||||
int32_t disp_w, int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip, lv_color_t fill_color)
|
||||
{
|
||||
lv_area_t intersection;
|
||||
if(!lv_area_intersect(&intersection, texture_area, texture_clip_area)) return;
|
||||
@@ -218,7 +221,8 @@ static void lv_opengles_render_internal(unsigned int texture, const lv_area_t *
|
||||
float ver_scale = tex_h / (float)disp_h;
|
||||
float hor_translate = (float)intersection.x1 / (float)disp_w * 2.0f - (1.0f - hor_scale);
|
||||
float ver_translate = -((float)intersection.y1 / (float)disp_h * 2.0f - (1.0f - ver_scale));
|
||||
if(flip) ver_scale = -ver_scale;
|
||||
hor_scale = h_flip ? -hor_scale : hor_scale;
|
||||
ver_scale = v_flip ? -ver_scale : ver_scale;
|
||||
float matrix[9] = {
|
||||
hor_scale, 0.0f, hor_translate,
|
||||
0.0f, ver_scale, ver_translate,
|
||||
@@ -228,20 +232,22 @@ static void lv_opengles_render_internal(unsigned int texture, const lv_area_t *
|
||||
if(texture != 0) {
|
||||
float x_coef = 1.0f / (float)(2 * lv_area_get_width(texture_area));
|
||||
float y_coef = 1.0f / (float)(2 * lv_area_get_height(texture_area));
|
||||
float tex_clip_x1 = lv_opengles_map_float(texture_clip_area->x1, texture_area->x1, texture_area->x2, x_coef,
|
||||
1.0f - x_coef);
|
||||
float tex_clip_x2 = lv_opengles_map_float(texture_clip_area->x2, texture_area->x1, texture_area->x2, x_coef,
|
||||
1.0f - x_coef);
|
||||
float tex_clip_y1 = lv_opengles_map_float(texture_clip_area->y1, texture_area->y1, texture_area->y2, y_coef,
|
||||
1.0f - y_coef);
|
||||
float tex_clip_y2 = lv_opengles_map_float(texture_clip_area->y2, texture_area->y1, texture_area->y2, y_coef,
|
||||
1.0f - y_coef);
|
||||
float ix_co = 1.0f - x_coef;
|
||||
float iy_co = 1.0f - y_coef;
|
||||
float clip_x1 = h_flip ? lv_opengles_map_float(texture_clip_area->x2, texture_area->x2, texture_area->x1, x_coef, ix_co)
|
||||
: lv_opengles_map_float(texture_clip_area->x1, texture_area->x1, texture_area->x2, x_coef, ix_co);
|
||||
float clip_x2 = h_flip ? lv_opengles_map_float(texture_clip_area->x1, texture_area->x2, texture_area->x1, x_coef, ix_co)
|
||||
: lv_opengles_map_float(texture_clip_area->x2, texture_area->x1, texture_area->x2, x_coef, ix_co);
|
||||
float clip_y1 = v_flip ? lv_opengles_map_float(texture_clip_area->y1, texture_area->y1, texture_area->y2, y_coef, iy_co)
|
||||
: lv_opengles_map_float(texture_clip_area->y2, texture_area->y2, texture_area->y1, y_coef, iy_co);
|
||||
float clip_y2 = v_flip ? lv_opengles_map_float(texture_clip_area->y2, texture_area->y1, texture_area->y2, y_coef, iy_co)
|
||||
: lv_opengles_map_float(texture_clip_area->y1, texture_area->y2, texture_area->y1, y_coef, iy_co);
|
||||
|
||||
float positions[LV_OPENGLES_VERTEX_BUFFER_LEN] = {
|
||||
-1.0f, 1.0f, tex_clip_x1, tex_clip_y2,
|
||||
1.0f, 1.0f, tex_clip_x2, tex_clip_y2,
|
||||
1.0f, -1.0f, tex_clip_x2, tex_clip_y1,
|
||||
-1.0f, -1.0f, tex_clip_x1, tex_clip_y1
|
||||
-1.f, 1.0f, clip_x1, clip_y2,
|
||||
1.0f, 1.0f, clip_x2, clip_y2,
|
||||
1.0f, -1.0f, clip_x2, clip_y1,
|
||||
-1.f, -1.0f, clip_x1, clip_y1
|
||||
};
|
||||
lv_opengles_vertex_buffer_init(positions, sizeof(positions));
|
||||
}
|
||||
|
||||
@@ -51,9 +51,11 @@ void lv_opengles_deinit(void);
|
||||
* @param opa opacity to blend the texture with existing contents
|
||||
* @param disp_w width of the window/framebuffer being rendered to
|
||||
* @param disp_h height of the window/framebuffer being rendered to
|
||||
* @param h_flip horizontal flip
|
||||
* @param v_flip vertical flip
|
||||
*/
|
||||
void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
|
||||
int32_t disp_h, const lv_area_t * texture_clip_area, bool flip);
|
||||
int32_t disp_h, const lv_area_t * texture_clip_area, bool h_flip, bool v_flip);
|
||||
|
||||
/**
|
||||
* Render a fill
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file lv_fastgltf.hpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
#include <fastgltf/util.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace fastgltf
|
||||
{
|
||||
FASTGLTF_EXPORT template <typename AssetType, typename Callback>
|
||||
#if FASTGLTF_HAS_CONCEPTS
|
||||
requires std::same_as<std::remove_cvref_t<AssetType>, Asset> &&
|
||||
std::is_invocable_v<Callback, fastgltf::Node &, std::string &,
|
||||
std::string &, std::size_t, std::size_t>
|
||||
#endif
|
||||
void namegen_iterate_scene_nodes(AssetType &&asset,
|
||||
std::size_t sceneIndex,
|
||||
Callback callback)
|
||||
{
|
||||
auto &scene = asset.scenes[sceneIndex];
|
||||
|
||||
std::string _id = std::string("");
|
||||
std::string _ip = std::string("");
|
||||
if (asset.scenes.size() > 1) {
|
||||
_id = "scene_" + std::to_string(sceneIndex);
|
||||
_ip = std::to_string(sceneIndex);
|
||||
}
|
||||
auto function = [&](std::size_t nodeIndex, std::string &parentId,
|
||||
std::string &parentIp, std::size_t __child_index,
|
||||
auto &self) -> void {
|
||||
assert(asset.nodes.size() > nodeIndex);
|
||||
auto &node = asset.nodes[nodeIndex];
|
||||
std::string _nodeId =
|
||||
parentId + std::string("/") + std::string(node.name);
|
||||
std::string _nodeIp = parentIp + std::string(".") +
|
||||
std::to_string(__child_index);
|
||||
std::invoke(callback, node, _nodeId, _nodeIp, nodeIndex,
|
||||
__child_index);
|
||||
std::size_t ____child_index = 0;
|
||||
for (auto &child : node.children) {
|
||||
self(child, _nodeId, _nodeIp, ____child_index, self);
|
||||
____child_index += 1;
|
||||
}
|
||||
};
|
||||
std::size_t child_index = 0;
|
||||
for (auto &sceneNode : scene.nodeIndices) {
|
||||
function(sceneNode, _id, _ip, child_index, function);
|
||||
child_index += 1;
|
||||
}
|
||||
}
|
||||
FASTGLTF_EXPORT template <typename AssetType, typename Callback>
|
||||
#if FASTGLTF_HAS_CONCEPTS
|
||||
requires std::same_as<std::remove_cvref_t<AssetType>, Asset> &&
|
||||
std::is_invocable_v<Callback, fastgltf::Node &, fastgltf::math::fmat4x4 &, fastgltf::math::fmat4x4 &>
|
||||
#endif
|
||||
void
|
||||
findlight_iterate_scene_nodes(AssetType &&asset, std::size_t sceneIndex,
|
||||
math::fmat4x4 *initial, Callback callback)
|
||||
{
|
||||
auto &scene = asset.scenes[sceneIndex];
|
||||
auto function = [&](std::size_t nodeIndex,
|
||||
math::fmat4x4 &parentWorldMatrix,
|
||||
auto &self) -> void {
|
||||
assert(asset.nodes.size() > nodeIndex);
|
||||
auto &node = asset.nodes[nodeIndex];
|
||||
auto _localMat = getTransformMatrix(node, math::fmat4x4());
|
||||
std::invoke(callback, node, parentWorldMatrix, _localMat);
|
||||
for (auto &child : node.children) {
|
||||
math::fmat4x4 _parentWorldTemp =
|
||||
parentWorldMatrix * _localMat;
|
||||
self(child, _parentWorldTemp, self);
|
||||
}
|
||||
};
|
||||
for (auto &sceneNode : scene.nodeIndices) {
|
||||
auto tmat2 = fastgltf::math::fmat4x4(*initial);
|
||||
function(sceneNode, tmat2, function);
|
||||
}
|
||||
}
|
||||
FASTGLTF_EXPORT template <typename AssetType, typename Callback>
|
||||
#if FASTGLTF_HAS_CONCEPTS
|
||||
requires std::same_as<std::remove_cvref_t<AssetType>, Asset>
|
||||
&& std::is_invocable_v<Callback, fastgltf::Node &, fastgltf::math::fmat4x4 &, fastgltf::math::fmat4x4 &>
|
||||
#endif
|
||||
inline void custom_iterate_scene_nodes(AssetType&& asset, std::size_t sceneIndex, math::fmat4x4 * initial,
|
||||
Callback callback)
|
||||
{
|
||||
auto & scene = asset.scenes[sceneIndex];
|
||||
auto & nodes = asset.nodes;
|
||||
auto function = [&](std::size_t nodeIndex, math::fmat4x4 & parentWorldMatrix, auto & self) -> void {
|
||||
//assert(asset.nodes.size() > nodeIndex);
|
||||
auto & node = nodes[nodeIndex];
|
||||
auto _localMat = getTransformMatrix(node, math::fmat4x4());
|
||||
std::invoke(callback, node, parentWorldMatrix, _localMat);
|
||||
uint32_t num_children = node.children.size();
|
||||
if(num_children > 0) {
|
||||
math::fmat4x4 _parentWorldTemp = parentWorldMatrix * _localMat;
|
||||
if(num_children > 1) {
|
||||
math::fmat4x4 per_child_copy = math::fmat4x4(_parentWorldTemp);
|
||||
for(auto & child : node.children) self(child, per_child_copy, self);
|
||||
}
|
||||
else {
|
||||
self(node.children[0], _parentWorldTemp, self);
|
||||
}
|
||||
}
|
||||
};
|
||||
// auto tempmat = fastgltf::math::fmat4x4(*initial);
|
||||
//for (auto& sceneNode : scene.nodeIndices) function(sceneNode, &tempmat, function);
|
||||
for(auto & sceneNode : scene.nodeIndices) function(sceneNode, *initial, function);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,155 @@
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <lvgl.h>
|
||||
|
||||
#include <fastgltf/core.hpp>
|
||||
#include <fastgltf/types.hpp>
|
||||
#include <fastgltf/tools.hpp>
|
||||
|
||||
#include "lv_gltf_bind.h"
|
||||
|
||||
static uint32_t bind_count = 0;
|
||||
|
||||
void lv_gltf_bind_set(lv_gltf_bind_t * bind, uint8_t channel, float data)
|
||||
{
|
||||
LV_ASSERT_NULL(bind);
|
||||
LV_ASSERT(channel < LV_GLTF_BIND_MAX_CHANNELS);
|
||||
|
||||
if(data != bind->data[channel]) {
|
||||
bind->data[channel] = data;
|
||||
bind->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
float lv_gltf_bind_get(lv_gltf_bind_t * bind, uint8_t channel)
|
||||
{
|
||||
LV_ASSERT_NULL(bind);
|
||||
LV_ASSERT(channel < LV_GLTF_BIND_MAX_CHANNELS);
|
||||
return bind->data[channel];
|
||||
}
|
||||
|
||||
void lv_gltf_bind_bind_clean(lv_gltf_bind_t * bind)
|
||||
{
|
||||
bind->dirty = false;
|
||||
}
|
||||
|
||||
lv_gltf_bind_t * add_by_node(lv_gltf_model_t * gltf_data, fastgltf::Node * node, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask,
|
||||
lv_gltf_bind_dir_t dir)
|
||||
{
|
||||
if(node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lv_gltf_bind_t new_bind;
|
||||
new_bind.id = bind_count++;
|
||||
new_bind.prop = which_prop;
|
||||
new_bind.data_mask = data_mask;
|
||||
new_bind.data[0] = new_bind.data[1] = new_bind.data[2] = which_prop == LV_GLTF_BIND_PROP_SCALE ? 1.f : 0.f;
|
||||
new_bind.dir = dir;
|
||||
new_bind.dirty = true;
|
||||
new_bind.next_bind = nullptr;
|
||||
|
||||
// Check if an bind already exists for this node
|
||||
if(gltf_data->node_binds.find(node) != gltf_data->node_binds.end()) {
|
||||
// Get the existing bind
|
||||
lv_gltf_bind_t * existingbind = gltf_data->node_binds[node];
|
||||
|
||||
// Traverse to the end of the linked list of binds
|
||||
while(existingbind->next_bind != nullptr)
|
||||
existingbind = existingbind->next_bind;
|
||||
|
||||
lv_array_push_back(&gltf_data->binds, &new_bind);
|
||||
existingbind->next_bind = (lv_gltf_bind_t *)lv_array_at(&gltf_data->binds, lv_array_size(&gltf_data->binds) - 1);
|
||||
return existingbind->next_bind;
|
||||
}
|
||||
else {
|
||||
// No existing bind, insert the new one
|
||||
lv_array_push_back(&gltf_data->binds, &new_bind);
|
||||
gltf_data->node_binds[node] = (lv_gltf_bind_t *)lv_array_at(&gltf_data->binds, lv_array_size(&gltf_data->binds) - 1);
|
||||
return gltf_data->node_binds[node];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_index(lv_gltf_model_t * data, size_t index, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask,
|
||||
lv_gltf_bind_dir_t dir)
|
||||
{
|
||||
lv_gltf_data_node_t * node = lv_gltf_data_node_get_by_index(data, index);
|
||||
if(!node) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return add_by_node(data, node->node, which_prop, data_mask, dir);
|
||||
}
|
||||
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_ip(lv_gltf_model_t * data, const char * ip, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask,
|
||||
lv_gltf_bind_dir_t dir)
|
||||
{
|
||||
lv_gltf_data_node_t * node = lv_gltf_data_node_get_by_ip(data, ip);
|
||||
if(!node) {
|
||||
return nullptr;
|
||||
}
|
||||
return add_by_node(data, node->node, which_prop, data_mask, dir);
|
||||
}
|
||||
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_path(lv_gltf_model_t * data, const char * path, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask, lv_gltf_bind_dir_t dir)
|
||||
{
|
||||
lv_gltf_data_node_t * node = lv_gltf_data_node_get_by_path(data, path);
|
||||
|
||||
if(!node) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return add_by_node(data, node->node, which_prop, data_mask, dir);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_bind_remove(lv_gltf_model_t * gltf_data, lv_gltf_bind_t * bind_to_remove)
|
||||
{
|
||||
for(auto pair : gltf_data->node_binds) {
|
||||
lv_gltf_bind_t * currentbind = pair.second;
|
||||
lv_gltf_bind_t * previousbind = nullptr;
|
||||
|
||||
while(currentbind != nullptr) {
|
||||
if(currentbind->id == bind_to_remove->id) {
|
||||
// Found the bind to remove
|
||||
if(previousbind != nullptr) {
|
||||
// Link the previous bind to the next one
|
||||
previousbind->next_bind = currentbind->next_bind;
|
||||
}
|
||||
else {
|
||||
gltf_data->node_binds[pair.first] = currentbind->next_bind;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < lv_array_size(&gltf_data->binds); ++i) {
|
||||
const lv_gltf_bind_t * current_entry = (const lv_gltf_bind_t *)lv_array_at(&gltf_data->binds, i);
|
||||
if(current_entry->id == bind_to_remove->id) {
|
||||
lv_array_remove(&gltf_data->binds, i);
|
||||
}
|
||||
}
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
previousbind = currentbind;
|
||||
if(currentbind != nullptr) {
|
||||
if(currentbind->next_bind != nullptr) {
|
||||
currentbind = currentbind->next_bind;
|
||||
}
|
||||
else {
|
||||
currentbind = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,106 @@
|
||||
#ifndef LV_GLTF_BIND_H
|
||||
#define LV_GLTF_BIND_H
|
||||
|
||||
#include "lv_gltf_model.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LV_GLTF_BIND_PROP_VISIBILITY,
|
||||
LV_GLTF_BIND_PROP_POSITION,
|
||||
LV_GLTF_BIND_PROP_ROTATION,
|
||||
LV_GLTF_BIND_PROP_SCALE,
|
||||
LV_GLTF_BIND_PROP_BASE_COLOR,
|
||||
LV_GLTF_BIND_PROP_ALPHA_FACTOR,
|
||||
LV_GLTF_BIND_PROP_EMIS_COLOR,
|
||||
LV_GLTF_BIND_PROP_WORLD_POSITION
|
||||
} lv_gltf_bind_prop_t;
|
||||
|
||||
#define LV_GLTF_BIND_MAX_CHANNELS 4
|
||||
#define LV_GLTF_BIND_CHANNEL_0 (0x01)
|
||||
#define LV_GLTF_BIND_CHANNEL_1 (0x02)
|
||||
#define LV_GLTF_BIND_CHANNEL_2 (0x04)
|
||||
#define LV_GLTF_BIND_CHANNEL_3 (0x08)
|
||||
|
||||
typedef enum { LV_GLTF_BIND_DIR_READ, LV_GLTF_BIND_DIR_WRITE } lv_gltf_bind_dir_t;
|
||||
|
||||
struct _lv_gltf_bind {
|
||||
struct _lv_gltf_bind * next_bind;
|
||||
lv_gltf_bind_prop_t prop;
|
||||
lv_gltf_bind_dir_t dir;
|
||||
uint32_t id;
|
||||
uint32_t data_mask;
|
||||
float data[LV_GLTF_BIND_MAX_CHANNELS];
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
typedef struct _lv_gltf_bind lv_gltf_bind_t;
|
||||
|
||||
void lv_gltf_bind_set(lv_gltf_bind_t * bind, uint8_t channel, float data);
|
||||
float lv_gltf_bind_get(lv_gltf_bind_t * bind, uint8_t channel);
|
||||
|
||||
/**
|
||||
* @brief Reset the dirty flag for a given bind.
|
||||
*
|
||||
* @param bind Pointer to the lv_gltf_bind_t to reset the dirty flag for.
|
||||
*/
|
||||
void lv_gltf_bind_bind_clean(lv_gltf_bind_t * bind);
|
||||
|
||||
/**
|
||||
* @brief Add an bind to a GLTF data object by node index.
|
||||
*
|
||||
* @param gltf_data Pointer to the lv_gltf_data_t object to which the bind will be added.
|
||||
* @param nodeIndex The index of the node to bind.
|
||||
* @param which_prop The property to bind.
|
||||
* @param data_mask A mask indicating which data fields to bind.
|
||||
* @return Pointer to the newly created lv_gltf_bind_t object, or NULL if the operation failed.
|
||||
*/
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_index(lv_gltf_model_t * data, size_t index, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask,
|
||||
lv_gltf_bind_dir_t dir);
|
||||
|
||||
/**
|
||||
* @brief Add an bind to a GLTF data object by node IP address.
|
||||
*
|
||||
* @param gltf_data Pointer to the lv_gltf_data_t object to which the bind will be added.
|
||||
* @param nodeIp The IP address of the node to bind.
|
||||
* @param which_prop The property to bind.
|
||||
* @param data_mask A mask indicating which data fields to bind.
|
||||
* @return Pointer to the newly created lv_gltf_bind_t object, or NULL if the operation failed.
|
||||
*/
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_ip(lv_gltf_model_t * data, const char * node_ip, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask, lv_gltf_bind_dir_t dir);
|
||||
|
||||
/**
|
||||
* @brief Add an bind to a GLTF data object by node ID.
|
||||
*
|
||||
* @param gltf_data Pointer to the lv_gltf_data_t object to which the bind will be added.
|
||||
* @param nodeId The ID of the node to bind.
|
||||
* @param which_prop The property to bind.
|
||||
* @param data_mask A mask indicating which data fields to bind.
|
||||
* @return Pointer to the newly created lv_gltf_bind_t object, or NULL if the operation failed.
|
||||
*/
|
||||
lv_gltf_bind_t * lv_gltf_bind_add_by_path(lv_gltf_model_t * data, const char * path, lv_gltf_bind_prop_t which_prop,
|
||||
uint32_t data_mask, lv_gltf_bind_dir_t dir);
|
||||
|
||||
/**
|
||||
* @brief Remove an bind from a GLTF data object.
|
||||
*
|
||||
* @param gltf_data Pointer to the lv_gltf_data_t object from which the bind will be removed.
|
||||
* @param bind The bind to be removed.
|
||||
* @param which_prop The property to bind.
|
||||
* @param data_mask A mask indicating which data fields to bind.
|
||||
* @return True on success, False on failure.
|
||||
*/
|
||||
lv_result_t lv_gltf_bind_remove(lv_gltf_model_t * _data, lv_gltf_bind_t * bind);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /*LV_GLTF_BIND_H*/
|
||||
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* @file lv_gltf_data.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/tools.hpp>
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../core/lv_obj_pos.h"
|
||||
#include "../../../misc/lv_timer.h"
|
||||
#include "../gltf_view/lv_gltf_view_internal.h"
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void update_animation_cb(lv_timer_t * timer);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
lv_gltf_model_t * lv_gltf_data_create_internal(const char * gltf_path,
|
||||
fastgltf::Asset asset)
|
||||
{
|
||||
lv_gltf_model_t * data = (lv_gltf_model_t *)lv_zalloc(sizeof(*data));
|
||||
LV_ASSERT_MALLOC(data);
|
||||
new(data) lv_gltf_model_t;
|
||||
new(&data->asset) fastgltf::Asset(std::move(asset));
|
||||
data->filename = gltf_path;
|
||||
data->last_camera_index = -5;
|
||||
data->last_anim_num = -5;
|
||||
data->current_animation_max_time = 0;
|
||||
data->local_timestamp = 0.0f;
|
||||
data->last_material_index = 99999;
|
||||
data->last_frame_was_antialiased = false;
|
||||
data->last_frame_no_motion = false;
|
||||
data->_last_frame_no_motion = false;
|
||||
|
||||
data->animation_update_timer = lv_timer_create(update_animation_cb, LV_DEF_REFR_PERIOD, data);
|
||||
lv_timer_pause(data->animation_update_timer);
|
||||
LV_ASSERT_NULL(data->animation_update_timer);
|
||||
|
||||
new(&data->node_binds) NodeOverrideMap();
|
||||
new(&data->node_transform_cache) NodeTransformMap();
|
||||
new(&data->opaque_nodes_by_material_index) MaterialIndexMap();
|
||||
new(&data->blended_nodes_by_material_index) MaterialIndexMap();
|
||||
new(&data->validated_skins) LongVector();
|
||||
new(&data->skin_tex) IntVector();
|
||||
new(&data->local_mesh_to_center_points_by_primitive)
|
||||
NodePrimCenterMap();
|
||||
new(&data->node_by_light_index) NodeVector();
|
||||
new(&data->meshes) std::vector<lv_gltf_mesh_data_t>();
|
||||
new(&data->textures) std::vector<GLuint>();
|
||||
|
||||
lv_array_init(&data->binds, 0, sizeof(lv_gltf_bind_t));
|
||||
lv_array_init(&data->compiled_shaders, 1, sizeof(lv_gltf_compiled_shader_t));
|
||||
return data;
|
||||
}
|
||||
|
||||
void lv_gltf_data_destroy(lv_gltf_model_t * data)
|
||||
{
|
||||
lv_gltf_data_destroy_textures(data);
|
||||
lv_free(data);
|
||||
}
|
||||
|
||||
const char * lv_gltf_get_filename(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->filename;
|
||||
}
|
||||
|
||||
size_t lv_gltf_model_get_image_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.images.size();
|
||||
}
|
||||
|
||||
size_t lv_gltf_model_get_texture_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.textures.size();
|
||||
}
|
||||
|
||||
GLuint lv_gltf_data_get_texture(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
LV_ASSERT(index < data->textures.size());
|
||||
return data->textures[index];
|
||||
}
|
||||
|
||||
size_t lv_gltf_model_get_material_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.materials.size();
|
||||
}
|
||||
size_t lv_gltf_model_get_camera_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.cameras.size();
|
||||
}
|
||||
size_t lv_gltf_model_get_node_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.nodes.size();
|
||||
}
|
||||
size_t lv_gltf_model_get_mesh_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.meshes.size();
|
||||
}
|
||||
size_t lv_gltf_model_get_scene_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.scenes.size();
|
||||
}
|
||||
size_t lv_gltf_model_get_animation_count(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->asset.animations.size();
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_play_animation(lv_gltf_model_t * model, size_t index)
|
||||
{
|
||||
LV_ASSERT_NULL(model);
|
||||
if(index >= model->asset.animations.size()) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
if(lv_timer_get_paused(model->animation_update_timer)) {
|
||||
model->last_tick = lv_tick_get();
|
||||
lv_timer_resume(model->animation_update_timer);
|
||||
}
|
||||
|
||||
model->current_animation_max_time = lv_gltf_data_get_animation_total_time(model, index);
|
||||
model->current_animation = index;
|
||||
model->is_animation_enabled = true;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
void lv_gltf_model_pause_animation(lv_gltf_model_t * model)
|
||||
{
|
||||
LV_ASSERT_NULL(model);
|
||||
model->is_animation_enabled = false;
|
||||
lv_timer_pause(model->animation_update_timer);
|
||||
}
|
||||
|
||||
bool lv_gltf_model_is_animation_paused(lv_gltf_model_t * model)
|
||||
{
|
||||
|
||||
LV_ASSERT_NULL(model);
|
||||
return !model->is_animation_enabled;
|
||||
}
|
||||
|
||||
size_t lv_gltf_model_get_animation(lv_gltf_model_t * model)
|
||||
{
|
||||
|
||||
LV_ASSERT_NULL(model);
|
||||
return model->current_animation;
|
||||
}
|
||||
|
||||
lv_gltf_model_t *
|
||||
lv_gltf_data_load_from_file(const char * file_path,
|
||||
lv_opengl_shader_manager_t * shader_manager)
|
||||
{
|
||||
return lv_gltf_data_load_internal(file_path, 0, shader_manager);
|
||||
}
|
||||
|
||||
lv_gltf_model_t *
|
||||
lv_gltf_data_load_from_bytes(const uint8_t * data, size_t data_size,
|
||||
lv_opengl_shader_manager_t * shader_manager)
|
||||
{
|
||||
return lv_gltf_data_load_internal(data, data_size, shader_manager);
|
||||
}
|
||||
|
||||
fastgltf::Asset * lv_gltf_data_get_asset(lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return &data->asset;
|
||||
}
|
||||
double lv_gltf_data_get_radius(lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->bound_radius;
|
||||
}
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_center(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->vertex_cen;
|
||||
}
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_bounds_min(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->vertex_min;
|
||||
}
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_bounds_max(const lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
return data->vertex_max;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void lv_gltf_data_copy_bounds_info(lv_gltf_model_t * to, lv_gltf_model_t * from)
|
||||
{
|
||||
{
|
||||
to->vertex_min[0] = from->vertex_min[0];
|
||||
to->vertex_min[1] = from->vertex_min[1];
|
||||
to->vertex_min[2] = from->vertex_min[2];
|
||||
}
|
||||
{
|
||||
to->vertex_max[0] = from->vertex_max[0];
|
||||
to->vertex_max[1] = from->vertex_max[1];
|
||||
to->vertex_max[2] = from->vertex_max[2];
|
||||
}
|
||||
{
|
||||
to->vertex_cen[0] = from->vertex_cen[0];
|
||||
to->vertex_cen[1] = from->vertex_cen[1];
|
||||
to->vertex_cen[2] = from->vertex_cen[2];
|
||||
}
|
||||
to->bound_radius = from->bound_radius;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void update_animation_cb(lv_timer_t * timer)
|
||||
{
|
||||
lv_gltf_model_t * model = (lv_gltf_model_t *)lv_timer_get_user_data(timer);
|
||||
|
||||
const uint32_t current_tick = lv_tick_get();
|
||||
const uint32_t delta = lv_tick_diff(current_tick, model->last_tick);
|
||||
|
||||
model->last_tick = current_tick;
|
||||
model->local_timestamp += (delta * model->viewer->desc.animation_speed_ratio) / 1000;
|
||||
|
||||
if(model->local_timestamp >= model->current_animation_max_time) {
|
||||
model->local_timestamp = 50;
|
||||
}
|
||||
lv_obj_invalidate((lv_obj_t *)model->viewer);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @file lv_gltf_data_animations.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include <fastgltf/tools.hpp>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define TIME_LOC_PREPASS_COUNT 16
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#include "fastgltf/math.hpp"
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
static fastgltf::math::fvec3 animation_get_vec3_at_timestamp(lv_gltf_model_t * data,
|
||||
fastgltf::AnimationSampler * sampler,
|
||||
float seconds);
|
||||
|
||||
static fastgltf::math::fquat animation_get_quat_at_timestamp(lv_gltf_model_t * data,
|
||||
fastgltf::AnimationSampler * sampler,
|
||||
float _seconds);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
uint32_t lv_gltf_data_get_animation_total_time(lv_gltf_model_t * data, uint32_t index)
|
||||
{
|
||||
LV_ASSERT(data->asset.animations.size() > index);
|
||||
auto & animation = data->asset.animations[index];
|
||||
float max_time = -1.0f;
|
||||
for(uint64_t i = 0; i < animation.channels.size(); i++) {
|
||||
auto & accessor = data->asset.accessors[animation.samplers[i].inputAccessor];
|
||||
max_time = std::max(max_time, fastgltf::getAccessorElement<float>(data->asset, accessor, accessor.count - 1));
|
||||
}
|
||||
return (uint32_t)(max_time * 1000);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> * lv_gltf_data_animation_get_channel_set(std::size_t anim_num, lv_gltf_model_t * data,
|
||||
fastgltf::Node & node)
|
||||
{
|
||||
const auto & asset = lv_gltf_data_get_asset(data);
|
||||
size_t animation_count = lv_gltf_model_get_animation_count(data);
|
||||
if(data->channel_set_cache.find(&node) == data->channel_set_cache.end()) {
|
||||
std::vector<uint32_t> new_cache = std::vector<uint32_t>();
|
||||
if(animation_count > anim_num) {
|
||||
auto & anim = asset->animations[anim_num];
|
||||
|
||||
for(uint64_t c = 0; c < anim.channels.size(); c++) {
|
||||
auto & channel = anim.channels[c];
|
||||
if(&(asset->nodes[channel.nodeIndex.value()]) == &node) {
|
||||
new_cache.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
data->channel_set_cache[&node] = new_cache;
|
||||
}
|
||||
return &data->channel_set_cache[&node];
|
||||
}
|
||||
|
||||
void lv_gltf_data_animation_matrix_apply(float timestamp, std::size_t anim_num, lv_gltf_model_t * gltf_data,
|
||||
fastgltf::Node & node,
|
||||
fastgltf::math::fmat4x4 & matrix)
|
||||
{
|
||||
const auto & asset = lv_gltf_data_get_asset(gltf_data);
|
||||
|
||||
size_t animation_count = lv_gltf_model_get_animation_count(gltf_data);
|
||||
auto _channel_set = lv_gltf_data_animation_get_channel_set(anim_num, gltf_data, node);
|
||||
if(_channel_set->size() == 0) {
|
||||
return;
|
||||
}
|
||||
if(animation_count > anim_num) {
|
||||
auto & anim = asset->animations[anim_num];
|
||||
fastgltf::math::fvec3 newPos, newScale;
|
||||
fastgltf::math::fmat3x3 rotmat;
|
||||
for(const auto & c : (*_channel_set)) {
|
||||
switch(anim.channels[c].path) {
|
||||
case fastgltf::AnimationPath::Translation:
|
||||
newPos = animation_get_vec3_at_timestamp(gltf_data, &anim.samplers[c], timestamp);
|
||||
matrix[3][0] = newPos[0];
|
||||
matrix[3][1] = newPos[1];
|
||||
matrix[3][2] = newPos[2];
|
||||
break;
|
||||
case fastgltf::AnimationPath::Rotation:
|
||||
rotmat = fastgltf::math::asMatrix(animation_get_quat_at_timestamp(gltf_data, &anim.samplers[c], timestamp));
|
||||
matrix[0][0] = rotmat[0][0];
|
||||
matrix[0][1] = rotmat[0][1];
|
||||
matrix[0][2] = rotmat[0][2];
|
||||
|
||||
matrix[1][0] = rotmat[1][0];
|
||||
matrix[1][1] = rotmat[1][1];
|
||||
matrix[1][2] = rotmat[1][2];
|
||||
|
||||
matrix[2][0] = rotmat[2][0];
|
||||
matrix[2][1] = rotmat[2][1];
|
||||
matrix[2][2] = rotmat[2][2];
|
||||
break;
|
||||
case fastgltf::AnimationPath::Scale:
|
||||
newScale = animation_get_vec3_at_timestamp(gltf_data, &anim.samplers[c], timestamp);
|
||||
for(int32_t rs = 0; rs < 3; ++rs) {
|
||||
matrix[0][rs] *= newScale[0];
|
||||
matrix[1][rs] *= newScale[1];
|
||||
matrix[2][rs] *= newScale[2];
|
||||
}
|
||||
break;
|
||||
case fastgltf::AnimationPath::Weights:
|
||||
LV_LOG_WARN("Unhandled weights animation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static fastgltf::math::fquat animation_get_quat_at_timestamp(lv_gltf_model_t * data,
|
||||
fastgltf::AnimationSampler * sampler,
|
||||
float _seconds)
|
||||
{
|
||||
const auto & asset = lv_gltf_data_get_asset(data);
|
||||
auto & _inAcc = asset->accessors[sampler->inputAccessor];
|
||||
auto & _outAcc = asset->accessors[sampler->outputAccessor];
|
||||
std::size_t _inAccCount = _inAcc.count;
|
||||
float _maxTime = fastgltf::getAccessorElement<float>(*asset, _inAcc, _inAccCount - 1);
|
||||
std::size_t _lowerIndex = 0;
|
||||
float _lowerTimestamp = 0.0f;
|
||||
|
||||
if(_seconds < 0.001f) {
|
||||
_lowerIndex = 0;
|
||||
}
|
||||
else {
|
||||
std::size_t _firstCheckOffset = 0;
|
||||
std::size_t _lastCheckOffset = _inAccCount;
|
||||
std::size_t _prepassLeft = TIME_LOC_PREPASS_COUNT;
|
||||
while(_prepassLeft > 0) {
|
||||
_prepassLeft -= 1;
|
||||
if(_seconds >= fastgltf::getAccessorElement<float>(*asset, _inAcc, (_firstCheckOffset + _lastCheckOffset) >> 1)) {
|
||||
_firstCheckOffset = (_firstCheckOffset + _lastCheckOffset) >> 1;
|
||||
}
|
||||
else {
|
||||
_lastCheckOffset = (_firstCheckOffset + _lastCheckOffset) >> 1;
|
||||
if(_lastCheckOffset <= _firstCheckOffset + 1) {
|
||||
_prepassLeft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(uint64_t ii = _firstCheckOffset; ii < _inAccCount; ii++) {
|
||||
float _stampTime = fastgltf::getAccessorElement<float>(*asset, _inAcc, ii);
|
||||
if(_stampTime > _seconds) {
|
||||
_lowerIndex = ii - 1;
|
||||
break;
|
||||
}
|
||||
_lowerTimestamp = _stampTime;
|
||||
}
|
||||
}
|
||||
|
||||
fastgltf::math::fquat _lowerValue = fastgltf::getAccessorElement<fastgltf::math::fquat>(*asset, _outAcc, _lowerIndex);
|
||||
if(_seconds >= _maxTime || _seconds <= 0.0f) {
|
||||
return _lowerValue;
|
||||
}
|
||||
std::size_t _upperIndex = _lowerIndex + 1;
|
||||
float _linDist = fastgltf::getAccessorElement<float>(*asset, _inAcc, _upperIndex) - _lowerTimestamp;
|
||||
return fastgltf::math::slerp(_lowerValue, fastgltf::getAccessorElement<fastgltf::math::fquat>(*asset, _outAcc,
|
||||
_upperIndex), (_seconds - _lowerTimestamp) / _linDist);
|
||||
}
|
||||
|
||||
fastgltf::math::fvec3 animation_get_vec3_at_timestamp(lv_gltf_model_t * data, fastgltf::AnimationSampler * sampler,
|
||||
float _seconds)
|
||||
{
|
||||
const auto & asset = lv_gltf_data_get_asset(data);
|
||||
auto & _inAcc = asset->accessors[sampler->inputAccessor];
|
||||
auto & _outAcc = asset->accessors[sampler->outputAccessor];
|
||||
std::size_t _inAccCount = _inAcc.count;
|
||||
float _maxTime = fastgltf::getAccessorElement<float>(*asset, _inAcc, _inAccCount - 1);
|
||||
std::size_t _lowerIndex = 0;
|
||||
float _lowerTimestamp = 0.0f;
|
||||
|
||||
if(_seconds < 0.001f) {
|
||||
_lowerIndex = 0;
|
||||
}
|
||||
else {
|
||||
std::size_t _firstCheckOffset = 0;
|
||||
std::size_t _lastCheckOffset = _inAccCount;
|
||||
std::size_t _prepassLeft = TIME_LOC_PREPASS_COUNT;
|
||||
while(_prepassLeft > 0) {
|
||||
_prepassLeft -= 1;
|
||||
if(_seconds >= fastgltf::getAccessorElement<float>(*asset, _inAcc, (_firstCheckOffset + _lastCheckOffset) >> 1)) {
|
||||
_firstCheckOffset = (_firstCheckOffset + _lastCheckOffset) >> 1;
|
||||
}
|
||||
else {
|
||||
_lastCheckOffset = (_firstCheckOffset + _lastCheckOffset) >> 1;
|
||||
if(_lastCheckOffset <= _firstCheckOffset + 1) {
|
||||
_prepassLeft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(uint64_t ii = _firstCheckOffset; ii < _inAccCount; ii++) {
|
||||
float _stampTime = fastgltf::getAccessorElement<float>(*asset, _inAcc, ii);
|
||||
if(_stampTime > _seconds) {
|
||||
_lowerIndex = ii - 1;
|
||||
break;
|
||||
}
|
||||
_lowerTimestamp = _stampTime;
|
||||
}
|
||||
}
|
||||
|
||||
fastgltf::math::fvec3 _lowerValue = fastgltf::getAccessorElement<fastgltf::math::fvec3>(*asset, _outAcc, _lowerIndex);
|
||||
if(_seconds >= _maxTime || _seconds <= 0.0f) {
|
||||
return _lowerValue;
|
||||
}
|
||||
std::size_t _upperIndex = _lowerIndex + 1;
|
||||
fastgltf::math::fvec3 _upperValue = fastgltf::getAccessorElement<fastgltf::math::fvec3>(*asset, _outAcc, _upperIndex);
|
||||
float _upperTimestamp = fastgltf::getAccessorElement<float>(*asset, _inAcc, _upperIndex);
|
||||
return fastgltf::math::lerp(_lowerValue, _upperValue,
|
||||
(_seconds - _lowerTimestamp) / (_upperTimestamp - _lowerTimestamp));
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file lv_gltf_data_cache.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
fastgltf::math::fmat4x4 lv_gltf_data_get_cached_transform(lv_gltf_model_t * data,
|
||||
fastgltf::Node * node)
|
||||
{
|
||||
return data->node_transform_cache[node];
|
||||
}
|
||||
|
||||
bool lv_gltf_data_has_cached_transform(lv_gltf_model_t * data, fastgltf::Node * node)
|
||||
{
|
||||
return (data->node_transform_cache.find(node) !=
|
||||
data->node_transform_cache.end());
|
||||
}
|
||||
void lv_gltf_data_set_cached_transform(lv_gltf_model_t * data, fastgltf::Node * node,
|
||||
fastgltf::math::fmat4x4 M)
|
||||
{
|
||||
data->node_transform_cache[node] = M;
|
||||
}
|
||||
void lv_gltf_data_clear_transform_cache(lv_gltf_model_t * data)
|
||||
{
|
||||
data->node_transform_cache.clear();
|
||||
}
|
||||
bool lv_gltf_data_transform_cache_is_empty(lv_gltf_model_t * data)
|
||||
{
|
||||
return data->node_transform_cache.size() == 0;
|
||||
}
|
||||
|
||||
void recache_centerpoint(lv_gltf_model_t * data, size_t index_mesh, int32_t primitive)
|
||||
{
|
||||
data->local_mesh_to_center_points_by_primitive[index_mesh][primitive] =
|
||||
lv_gltf_get_primitive_centerpoint(data, data->asset.meshes[index_mesh],
|
||||
primitive);
|
||||
}
|
||||
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_centerpoint(lv_gltf_model_t * gltf_data,
|
||||
fastgltf::math::fmat4x4 matrix,
|
||||
size_t mesh_index, int32_t elem)
|
||||
{
|
||||
if(!lv_gltf_data_centerpoint_cache_contains(gltf_data, mesh_index, elem)) {
|
||||
recache_centerpoint(gltf_data, mesh_index, elem);
|
||||
}
|
||||
return get_cached_centerpoint(gltf_data, mesh_index, elem, matrix);
|
||||
}
|
||||
bool lv_gltf_data_centerpoint_cache_contains(lv_gltf_model_t * data, size_t index, int32_t element)
|
||||
{
|
||||
return data->local_mesh_to_center_points_by_primitive.find(index) !=
|
||||
data->local_mesh_to_center_points_by_primitive.end() &&
|
||||
data->local_mesh_to_center_points_by_primitive[index].find(element) !=
|
||||
data->local_mesh_to_center_points_by_primitive[index].end();
|
||||
}
|
||||
|
||||
fastgltf::math::fvec3 get_cached_centerpoint(lv_gltf_model_t * data, size_t index,
|
||||
int32_t element,
|
||||
fastgltf::math::fmat4x4 matrix)
|
||||
{
|
||||
fastgltf::math::fvec4 tv = fastgltf::math::fvec4(
|
||||
data->local_mesh_to_center_points_by_primitive[index][element]);
|
||||
tv[3] = 1.f;
|
||||
tv = matrix * tv;
|
||||
return fastgltf::math::fvec3(tv[0], tv[1], tv[2]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
||||
#ifndef LV_GLTFDATA_PRIVATE_H
|
||||
#define LV_GLTFDATA_PRIVATE_H
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
#if LV_USE_GLTF
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include "../opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../../../draw/lv_image_dsc.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
|
||||
typedef struct {
|
||||
GLuint count;
|
||||
GLuint instanceCount;
|
||||
GLuint firstIndex;
|
||||
GLint baseVertex;
|
||||
GLuint baseInstance;
|
||||
} IndirectDrawCommand;
|
||||
|
||||
typedef struct {
|
||||
IndirectDrawCommand draw;
|
||||
GLenum primitiveType;
|
||||
GLenum indexType;
|
||||
GLuint vertexArray;
|
||||
|
||||
GLuint vertexBuffer;
|
||||
GLuint indexBuffer;
|
||||
|
||||
GLuint materialUniformsIndex;
|
||||
GLuint albedoTexture;
|
||||
GLuint emissiveTexture;
|
||||
GLuint metalRoughTexture;
|
||||
GLuint occlusionTexture;
|
||||
GLuint normalTexture;
|
||||
GLuint diffuseTransmissionTexture;
|
||||
GLuint diffuseTransmissionColorTexture;
|
||||
GLuint transmissionTexture;
|
||||
GLuint transmissionTexcoordIndex;
|
||||
|
||||
GLint baseColorTexcoordIndex;
|
||||
GLint emissiveTexcoordIndex;
|
||||
|
||||
GLint metallicRoughnessTexcoordIndex;
|
||||
GLint occlusionTexcoordIndex;
|
||||
GLint normalTexcoordIndex;
|
||||
GLint diffuseTransmissionTexcoordIndex;
|
||||
GLint diffuseTransmissionColorTexcoordIndex;
|
||||
|
||||
GLint clearcoatTexture;
|
||||
GLint clearcoatRoughnessTexture;
|
||||
GLint clearcoatNormalTexture;
|
||||
GLint clearcoatTexcoordIndex;
|
||||
GLint clearcoatRoughnessTexcoordIndex;
|
||||
GLint clearcoatNormalTexcoordIndex;
|
||||
|
||||
GLuint thicknessTexture;
|
||||
GLint thicknessTexcoordIndex;
|
||||
|
||||
GLuint diffuseTexture;
|
||||
GLint diffuseTexcoordIndex;
|
||||
|
||||
GLuint specularGlossinessTexture;
|
||||
GLint specularGlossinessTexcoordIndex;
|
||||
|
||||
} lv_gltf_primitive_t;
|
||||
|
||||
typedef struct {
|
||||
GLint camera;
|
||||
GLint view_projection_matrix;
|
||||
GLint model_matrix;
|
||||
GLint view_matrix;
|
||||
GLint projection_matrix;
|
||||
|
||||
GLint env_intensity;
|
||||
GLint env_diffuse_sampler;
|
||||
GLint env_specular_sampler;
|
||||
GLint env_sheen_sampler;
|
||||
GLint env_ggx_lut_sampler;
|
||||
GLint env_charlie_lut_sampler;
|
||||
GLint env_mip_count;
|
||||
|
||||
GLint exposure;
|
||||
GLint roughness_factor;
|
||||
|
||||
GLint base_color_factor;
|
||||
GLint base_color_sampler;
|
||||
GLint base_color_uv_set;
|
||||
GLint base_color_uv_transform;
|
||||
|
||||
GLint emissive_factor;
|
||||
GLint emissive_sampler;
|
||||
GLint emissive_uv_set;
|
||||
GLint emissive_uv_transform;
|
||||
GLint emissive_strength;
|
||||
|
||||
GLint metallic_factor;
|
||||
GLint metallic_roughness_sampler;
|
||||
GLint metallic_roughness_uv_set;
|
||||
GLint metallic_roughness_uv_transform;
|
||||
|
||||
GLint occlusion_strength;
|
||||
GLint occlusion_sampler;
|
||||
GLint occlusion_uv_set;
|
||||
GLint occlusion_uv_transform;
|
||||
|
||||
GLint normal_scale;
|
||||
GLint normal_sampler;
|
||||
GLint normal_uv_set;
|
||||
GLint normal_uv_transform;
|
||||
|
||||
GLint clearcoat_factor;
|
||||
GLint clearcoat_roughness_factor;
|
||||
GLint clearcoat_sampler;
|
||||
GLint clearcoat_uv_set;
|
||||
GLint clearcoat_uv_transform;
|
||||
GLint clearcoat_roughness_sampler;
|
||||
GLint clearcoat_roughness_uv_set;
|
||||
GLint clearcoat_roughness_uv_transform;
|
||||
GLint clearcoat_normal_scale;
|
||||
GLint clearcoat_normal_sampler;
|
||||
GLint clearcoat_normal_uv_set;
|
||||
GLint clearcoat_normal_uv_transform;
|
||||
|
||||
GLint thickness;
|
||||
GLint thickness_sampler;
|
||||
GLint thickness_uv_set;
|
||||
GLint thickness_uv_transform;
|
||||
|
||||
GLint diffuse_transmission_sampler;
|
||||
GLint diffuse_transmission_uv_set;
|
||||
GLint diffuse_transmission_uv_transform;
|
||||
|
||||
GLint diffuse_transmission_color_sampler;
|
||||
GLint diffuse_transmission_color_uv_set;
|
||||
GLint diffuse_transmission_color_uv_transform;
|
||||
|
||||
GLint sheen_color_factor;
|
||||
GLint sheen_roughness_factor;
|
||||
|
||||
GLint specular_color_factor;
|
||||
GLint specular_factor;
|
||||
|
||||
GLint diffuse_transmission_color_factor;
|
||||
GLint diffuse_transmission_factor;
|
||||
|
||||
GLint ior;
|
||||
GLint alpha_cutoff;
|
||||
|
||||
GLint dispersion;
|
||||
GLint screen_size;
|
||||
GLint transmission_factor;
|
||||
GLint transmission_sampler;
|
||||
GLint transmission_uv_set;
|
||||
GLint transmission_uv_transform;
|
||||
GLint transmission_framebuffer_sampler;
|
||||
GLint transmission_framebuffer_size;
|
||||
|
||||
GLint attenuation_distance;
|
||||
GLint attenuation_color;
|
||||
|
||||
GLint joints_sampler;
|
||||
|
||||
GLint diffuse_factor;
|
||||
GLint glossiness_factor;
|
||||
|
||||
GLint diffuse_sampler;
|
||||
GLint diffuse_uv_set;
|
||||
GLint diffuse_uv_transform;
|
||||
GLint specular_glossiness_sampler;
|
||||
GLint specular_glossiness_uv_set;
|
||||
GLint specular_glossiness_uv_transform;
|
||||
|
||||
} lv_gltf_uniform_locations_t;
|
||||
|
||||
lv_gltf_uniform_locations_t lv_gltf_uniform_locations_create(GLuint program);
|
||||
|
||||
typedef struct {
|
||||
GLuint program;
|
||||
uint32_t bg_program;
|
||||
uint32_t vert;
|
||||
uint32_t frag;
|
||||
} lv_gltf_shaderset_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gltf_uniform_locations_t uniforms;
|
||||
lv_gltf_shaderset_t shaderset;
|
||||
} lv_gltf_compiled_shader_t;
|
||||
|
||||
void lv_gltf_store_compiled_shader(lv_gltf_model_t * data, size_t identifier, lv_gltf_compiled_shader_t * shader);
|
||||
lv_gltf_compiled_shader_t * lv_gltf_get_compiled_shader(lv_gltf_model_t * data, size_t identifier);
|
||||
|
||||
/**
|
||||
* @brief Load the gltf file at the specified filepath
|
||||
*
|
||||
* @param gltf_path The gltf filename
|
||||
* @param ret_data Pointer to the data container that will be populated.
|
||||
* @param shaders Pointer to the shader cache object this file uses.
|
||||
*/
|
||||
lv_gltf_model_t *
|
||||
lv_gltf_data_load_from_file(const char * file_path,
|
||||
lv_opengl_shader_manager_t * shader_manager);
|
||||
|
||||
/**
|
||||
* @brief Load the gltf file encoded within the supplied byte array
|
||||
*
|
||||
* @param gltf_path The gltf filename
|
||||
* @param gltf_data_size if gltf_path is instead a byte array, pass the size of that array in through this variable (or 0 if it's a file path).
|
||||
* @param ret_data Pointer to the data container that will be populated.
|
||||
* @param shaders Pointer to the shader cache object this file uses.
|
||||
*/
|
||||
|
||||
lv_gltf_model_t *
|
||||
lv_gltf_data_load_from_bytes(const uint8_t * data, size_t data_size,
|
||||
lv_opengl_shader_manager_t * shader_manager);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the radius of the GLTF data object.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object from which to get the radius.
|
||||
* @return The radius of the GLTF data object.
|
||||
*/
|
||||
double lv_gltf_data_get_radius(lv_gltf_model_t * D);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destroy a GLTF data object and free associated resources.
|
||||
*
|
||||
* @param _data Pointer to the lv_gltf_data_t object to be destroyed.
|
||||
*/
|
||||
void lv_gltf_data_destroy(lv_gltf_model_t * _data);
|
||||
|
||||
/**
|
||||
* @brief Copy the bounds information from one GLTF data object to another.
|
||||
*
|
||||
* @param to Pointer to the destination lv_gltf_data_t object.
|
||||
* @param from Pointer to the source lv_gltf_data_t object.
|
||||
*/
|
||||
void lv_gltf_data_copy_bounds_info(lv_gltf_model_t * to, lv_gltf_model_t * from);
|
||||
|
||||
/**
|
||||
* @brief Retrieve information about a specific texture in a GLTF model.
|
||||
*
|
||||
* @param data_obj Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param model_texture_index The index of the texture in the model.
|
||||
* @param mipmapnum The mipmap level to retrieve information for.
|
||||
* @param byte_count Pointer to a size_t variable to store the byte count of the texture.
|
||||
* @param width Pointer to a uint32_t variable to store the width of the texture.
|
||||
* @param height Pointer to a uint32_t variable to store the height of the texture.
|
||||
* @param has_alpha Pointer to a bool variable to indicate if the texture has an alpha channel.
|
||||
* @return True if the texture information was successfully retrieved, false otherwise.
|
||||
*/
|
||||
bool lv_gltf_data_get_texture_info(lv_gltf_model_t * data_obj,
|
||||
uint32_t model_texture_index,
|
||||
uint32_t mipmapnum, size_t * byte_count,
|
||||
uint32_t * width, uint32_t * height,
|
||||
bool * has_alpha);
|
||||
|
||||
/**
|
||||
* @brief Swap the red and blue channels in a pixel buffer.
|
||||
*
|
||||
* @param pixel_buffer Pointer to the pixel buffer containing the image data.
|
||||
* @param byte_total_count The total number of bytes in the pixel buffer.
|
||||
* @param has_alpha Flag indicating whether the pixel buffer includes an alpha channel.
|
||||
*/
|
||||
void lv_gltf_data_rgb_to_bgr(uint8_t * pixel_buffer,
|
||||
size_t byte_total_count,
|
||||
bool has_alpha);
|
||||
|
||||
/**
|
||||
* @brief Convert a texture from a GLTF model to an image descriptor.
|
||||
*
|
||||
* @param new_image_dsc Pointer to the lv_image_dsc_t structure to be populated with the image data.
|
||||
* @param data_obj Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param model_texture_index The index of the texture in the model to convert.
|
||||
*/
|
||||
void lv_gltf_data_texture_to_image_dsc(lv_image_dsc_t * new_image_dsc,
|
||||
lv_gltf_model_t * data_obj,
|
||||
uint32_t model_texture_index);
|
||||
|
||||
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /* LV_GLTFDATA_PRIVATE_H */
|
||||
@@ -0,0 +1,373 @@
|
||||
#ifndef LV_GLTFDATA_HPP
|
||||
#define LV_GLTFDATA_HPP
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
#include "lv_gltf_data_internal.h"
|
||||
#include "lv_gltf_bind.h"
|
||||
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include <GL/gl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <fastgltf/types.hpp>
|
||||
|
||||
// Vector of int32_t's
|
||||
using UintVector = std::vector<uint32_t>;
|
||||
// Vector of int32_t's
|
||||
using IntVector = std::vector<int32_t>;
|
||||
// Vector of int64_t's
|
||||
using LongVector = std::vector<int64_t>;
|
||||
// Pointer to fastgltf::Node
|
||||
using NodePtr = fastgltf::Node *;
|
||||
// A standard 4x4 transform matrix
|
||||
using Transform = fastgltf::math::fmat4x4;
|
||||
// Pair of Node pointer and int32_t
|
||||
using NodeIndexPair = std::pair<NodePtr, size_t>;
|
||||
// Pair of float and Node/Index pair
|
||||
using NodeIndexDistancePair = std::pair<float, NodeIndexPair>;
|
||||
// Vector of NodeIndexPair
|
||||
using NodePairVector = std::vector<NodeIndexPair>;
|
||||
// Vector of NodeIndexDistancePair
|
||||
using NodeDistanceVector = std::vector<NodeIndexDistancePair>;
|
||||
// Map of uint32_t to NodePairVector
|
||||
using MaterialIndexMap = std::map<uint32_t, NodePairVector>;
|
||||
// Map of Node Pointers to Transforms
|
||||
using NodeTransformMap = std::map<NodePtr, Transform>;
|
||||
// Map of Nodes by string (name)
|
||||
using StringNodeMap = std::map<std::string, NodePtr>;
|
||||
// Map of Nodes by string (name)
|
||||
using NodeIntMap = std::map<NodePtr, uint32_t>;
|
||||
// Map of Nodes by string (name)
|
||||
using NodeVector = std::vector<NodePtr>;
|
||||
// Map of Node Index to Map of Prim Index to CenterXYZ+RadiusW Vec4
|
||||
using NodePrimCenterMap = std::map<uint32_t, std::map<uint32_t, fastgltf::math::fvec4> >;
|
||||
// Map of Overrides by Node
|
||||
using NodeOverrideMap = std::map<fastgltf::Node *, lv_gltf_bind_t *>;
|
||||
// Map of Overrides by Node
|
||||
using OverrideVector = std::vector<lv_gltf_bind_t>;
|
||||
|
||||
typedef struct {
|
||||
GLuint drawsBuffer;
|
||||
std::vector<lv_gltf_primitive_t> primitives;
|
||||
} lv_gltf_mesh_data_t;
|
||||
|
||||
typedef struct {
|
||||
const char *ip;
|
||||
const char *path;
|
||||
fastgltf::Node *node;
|
||||
} lv_gltf_data_node_t;
|
||||
|
||||
|
||||
struct _lv_gltf_model_t {
|
||||
const char *filename;
|
||||
fastgltf::Asset asset;
|
||||
lv_array_t nodes;
|
||||
NodeVector node_by_light_index;
|
||||
NodeTransformMap node_transform_cache;
|
||||
MaterialIndexMap opaque_nodes_by_material_index;
|
||||
MaterialIndexMap blended_nodes_by_material_index;
|
||||
NodeOverrideMap node_binds;
|
||||
lv_array_t binds;
|
||||
std::vector<size_t> validated_skins;
|
||||
std::vector<GLuint> skin_tex;
|
||||
NodePrimCenterMap local_mesh_to_center_points_by_primitive;
|
||||
lv_gltf_t* viewer;
|
||||
|
||||
std::vector<lv_gltf_mesh_data_t> meshes;
|
||||
std::vector<GLuint> textures;
|
||||
lv_array_t compiled_shaders;
|
||||
std::map<fastgltf::Node *, std::vector<uint32_t> > channel_set_cache;
|
||||
fastgltf::math::fmat4x4 view_mat;
|
||||
fastgltf::math::fvec3 view_pos;
|
||||
fastgltf::math::fvec3 vertex_max;
|
||||
fastgltf::math::fvec3 vertex_min;
|
||||
fastgltf::math::fvec3 vertex_cen;
|
||||
|
||||
lv_timer_t* animation_update_timer;
|
||||
|
||||
size_t current_animation;
|
||||
size_t last_material_index;
|
||||
|
||||
uint32_t last_camera_index;
|
||||
int32_t last_anim_num;
|
||||
|
||||
float bound_radius;
|
||||
|
||||
uint32_t current_animation_max_time;
|
||||
uint32_t local_timestamp;
|
||||
uint32_t last_tick;
|
||||
uint32_t camera;
|
||||
|
||||
bool is_animation_enabled;
|
||||
bool last_pass_was_transmission;
|
||||
bool last_frame_was_antialiased;
|
||||
bool last_frame_no_motion;
|
||||
bool _last_frame_no_motion;
|
||||
struct _lv_gltf_model_t *linked_view_source;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Retrieve a specific texture from the GLTF model data.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param index The index of the texture to retrieve.
|
||||
* @return Pointer to the texture object.
|
||||
*/
|
||||
GLuint lv_gltf_data_get_texture(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the minimum bounds (X/Y/Z) of the model from the GLTF data.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return Pointer to a 3-element float array representing the minimum bounds.
|
||||
*/
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_bounds_min(const lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the maximum bounds (X/Y/Z) of the model from the GLTF data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return Pointer to a 3-element float array representing the maximum bounds.
|
||||
*/
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_bounds_max(const lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the center coordinates of the GLTF data object.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object from which to get the center.
|
||||
* @return Pointer to an array containing the center coordinates (x, y, z).
|
||||
*/
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_center(const lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the filename of the GLTF model.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return Pointer to a constant character string representing the filename.
|
||||
*/
|
||||
const char *lv_gltf_get_filename(const lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Check if the centerpoint cache contains a specific entry.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param index The index of the entry to check.
|
||||
* @param element The specific parameter to check within the cache.
|
||||
* @return True if the cache contains the entry, false otherwise.
|
||||
*/
|
||||
bool lv_gltf_data_centerpoint_cache_contains(lv_gltf_model_t *data, size_t index, int32_t element);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a specific primitive from a mesh.
|
||||
*
|
||||
* @param M Pointer to the MeshData structure containing the mesh data.
|
||||
* @param I The index of the primitive to retrieve.
|
||||
* @return Pointer to the primitive data.
|
||||
*/
|
||||
lv_gltf_primitive_t *lv_gltf_data_get_primitive_from_mesh(lv_gltf_mesh_data_t *M, size_t I);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the asset associated with the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return Pointer to the asset data.
|
||||
*/
|
||||
fastgltf::Asset *lv_gltf_data_get_asset(lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve mesh data for a specific index from the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param I The index of the mesh data to retrieve.
|
||||
* @return Pointer to the MeshData structure containing the mesh data.
|
||||
*/
|
||||
lv_gltf_mesh_data_t *lv_gltf_data_get_mesh(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the skin texture index for a specific entry in the GLTF model data.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param index The index of the entry for which to retrieve the skin texture index.
|
||||
* @return The skin texture index.
|
||||
*/
|
||||
GLuint lv_gltf_data_get_skin_texture_at(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Check if the validated skins contain a specific entry.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param index The index of the skin to check.
|
||||
* @return True if the validated skins contain the entry, false otherwise.
|
||||
*/
|
||||
bool lv_gltf_data_validated_skins_contains(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Validate a specific skin in the GLTF model data.
|
||||
*
|
||||
* @param data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param index The index of the skin to validate.
|
||||
*/
|
||||
void lv_gltf_data_validate_skin(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Add an opaque node primitive to the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param I The index of the primitive to add.
|
||||
* @param N Pointer to the NodePtr representing the node to add.
|
||||
* @param P The specific parameter associated with the primitive.
|
||||
*/
|
||||
void lv_gltf_data_add_opaque_node_primitive(lv_gltf_model_t *data, size_t index, fastgltf::Node *node, size_t primitive_index);
|
||||
|
||||
/**
|
||||
* @brief Add a blended node primitive to the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param I The index of the primitive to add.
|
||||
* @param N Pointer to the NodePtr representing the node to add.
|
||||
* @param P The specific parameter associated with the primitive.
|
||||
*/
|
||||
void lv_gltf_data_add_blended_node_primitive(lv_gltf_model_t *data, size_t mesh_index, fastgltf::Node *node,
|
||||
size_t primitive_index);
|
||||
|
||||
/**
|
||||
* @brief Set the cached transformation matrix for a specific node in the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param N Pointer to the NodePtr representing the node for which to set the transformation.
|
||||
* @param M The transformation matrix to cache.
|
||||
*/
|
||||
void lv_gltf_data_set_cached_transform(lv_gltf_model_t* data, fastgltf::Node* node, fastgltf::math::fmat4x4 M);
|
||||
|
||||
/**
|
||||
* @brief Clear the transformation cache for the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
*/
|
||||
void lv_gltf_data_clear_transform_cache(lv_gltf_model_t* data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the cached transformation matrix for a specific node in the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param N Pointer to the NodePtr representing the node for which to retrieve the transformation.
|
||||
* @return The cached transformation matrix.
|
||||
*/
|
||||
fastgltf::math::fmat4x4 lv_gltf_data_get_cached_transform(lv_gltf_model_t* data, fastgltf::Node* node);
|
||||
|
||||
/**
|
||||
* @brief Check if a cached transformation matrix exists for a given node.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param N Pointer to the NodePtr representing the node for which to retrieve the transformation.
|
||||
* @return true if a cache item exists, false otherwise
|
||||
int32_t*/
|
||||
bool lv_gltf_data_has_cached_transform(lv_gltf_model_t* data, fastgltf::Node* node);
|
||||
|
||||
/**
|
||||
* @brief Check if the transformation cache is empty.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return True if the transformation cache is empty, false otherwise.
|
||||
*/
|
||||
bool lv_gltf_data_transform_cache_is_empty(lv_gltf_model_t* data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the size of the skins in the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @return The size of the skins.
|
||||
*/
|
||||
size_t lv_gltf_data_get_skins_size(lv_gltf_model_t *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a specific skin from the GLTF model data.
|
||||
*
|
||||
* @param D Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param I The index of the skin to retrieve.
|
||||
* @return The skin index.
|
||||
*/
|
||||
size_t lv_gltf_data_get_skin(lv_gltf_model_t *data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Ingest and discover defines for a specific node and primitive in the GLTF model data.
|
||||
*
|
||||
* @param data_obj Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param node Pointer to the node for which to ingest defines.
|
||||
* @param prim Pointer to the primitive for which to ingest defines.
|
||||
*/
|
||||
void lv_gltf_data_injest_discover_defines(lv_gltf_model_t *data, fastgltf::Node *node, fastgltf::Primitive *prim);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the center point of a specific mesh element from the GLTF model data.
|
||||
*
|
||||
* @param gltf_data Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param matrix The transformation matrix to apply when calculating the center point.
|
||||
* @param meshIndex The index of the mesh from which to retrieve the center point.
|
||||
* @param elem The specific element index within the mesh.
|
||||
* @return The center point as a fastgltf::math::fvec3 structure.
|
||||
*/
|
||||
fastgltf::math::fvec3 lv_gltf_data_get_centerpoint(lv_gltf_model_t *gltf_data, fastgltf::math::fmat4x4 matrix, size_t mesh_index,
|
||||
int32_t elem);
|
||||
|
||||
|
||||
lv_gltf_mesh_data_t *lv_gltf_get_new_meshdata(lv_gltf_model_t *_data);
|
||||
|
||||
lv_gltf_model_t *lv_gltf_data_create_internal(const char *gltf_path, fastgltf::Asset);
|
||||
|
||||
lv_gltf_model_t *lv_gltf_data_load_internal(const void *data_source, size_t data_size, lv_opengl_shader_manager_t *shaders);
|
||||
|
||||
/*void set_node_at_path(lv_gltf_data_t *data, const std::string &path,*/
|
||||
/* fastgltf::Node *node);*/
|
||||
/*void set_node_at_ip(lv_gltf_data_t *data, const std::string &ip,*/
|
||||
/* fastgltf::Node *node);*/
|
||||
/*void set_node_index(lv_gltf_data_t *data, size_t index, fastgltf::Node *node);*/
|
||||
|
||||
fastgltf::math::fvec4 lv_gltf_get_primitive_centerpoint(lv_gltf_model_t *data, fastgltf::Mesh &mesh, uint32_t prim_num);
|
||||
|
||||
fastgltf::math::fvec3 get_cached_centerpoint(lv_gltf_model_t *data, size_t index, int32_t element,
|
||||
fastgltf::math::fmat4x4 matrix);
|
||||
|
||||
void lv_gltf_data_destroy_textures(lv_gltf_model_t *data);
|
||||
GLuint lv_gltf_data_create_texture(lv_gltf_model_t *data);
|
||||
void lv_gltf_data_nodes_init(lv_gltf_model_t *data, size_t size);
|
||||
void lv_gltf_data_node_init(lv_gltf_data_node_t * node, fastgltf::Node * fastgltf_node, const char * path, const char * ip);
|
||||
void lv_gltf_data_node_add(lv_gltf_model_t *data, const lv_gltf_data_node_t *data_node);
|
||||
void lv_gltf_data_node_delete(lv_gltf_data_node_t *node);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the pixel data for a specific texture in a GLTF model.
|
||||
*
|
||||
* @param pixels Pointer to the memory where the pixel data will be stored.
|
||||
* @param data_obj Pointer to the lv_gltf_data_t object containing the model data.
|
||||
* @param model_texture_index The index of the texture in the model.
|
||||
* @param mipmapnum The mipmap level to retrieve pixel data for.
|
||||
* @param width The width of the texture.
|
||||
* @param height The height of the texture.
|
||||
* @param has_alpha Flag indicating whether the texture includes an alpha channel.
|
||||
* @return True if the pixel data was successfully retrieved, false otherwise.
|
||||
*/
|
||||
bool lv_gltf_data_get_texture_pixels(void *pixels, lv_gltf_model_t *data_obj, uint32_t model_texture_index, uint32_t mipmapnum,
|
||||
uint32_t width, uint32_t height, bool has_alpha);
|
||||
|
||||
lv_gltf_data_node_t *lv_gltf_data_node_get_by_index(lv_gltf_model_t *data, size_t index);
|
||||
lv_gltf_data_node_t *lv_gltf_data_node_get_by_ip(lv_gltf_model_t *data, const char *ip);
|
||||
lv_gltf_data_node_t *lv_gltf_data_node_get_by_path(lv_gltf_model_t *data, const char *path);
|
||||
uint32_t lv_gltf_data_get_animation_total_time(lv_gltf_model_t *data, uint32_t index);
|
||||
std::vector<uint32_t> *lv_gltf_data_animation_get_channel_set(std::size_t anim_num, lv_gltf_model_t *data, fastgltf::Node &node);
|
||||
void lv_gltf_data_animation_matrix_apply(float timestamp, std::size_t anim_num, lv_gltf_model_t *gltf_data, fastgltf::Node &node,
|
||||
fastgltf::math::fmat4x4 &matrix);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /*LV_GLTFVIEW_H*/
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file lv_gltf_data_mesh.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_gltf_mesh_data_t * lv_gltf_get_new_meshdata(lv_gltf_model_t * data)
|
||||
{
|
||||
data->meshes.emplace_back(lv_gltf_mesh_data_t {});
|
||||
return &(data->meshes[data->meshes.size() - 1]);
|
||||
}
|
||||
|
||||
|
||||
lv_gltf_mesh_data_t * lv_gltf_data_get_mesh(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
return &data->meshes[index];
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file lv_gltf_data_node.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
#include "fastgltf/types.hpp"
|
||||
#include "lv_gltf_model.h"
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gltf_data_nodes_init(lv_gltf_model_t * data, size_t size)
|
||||
{
|
||||
lv_array_init(&data->nodes, size, sizeof(lv_gltf_data_node_t));
|
||||
}
|
||||
|
||||
void lv_gltf_data_node_init(lv_gltf_data_node_t * node, fastgltf::Node * fastgltf_node, const char * path,
|
||||
const char * ip)
|
||||
{
|
||||
LV_ASSERT_NULL(node);
|
||||
node->node = fastgltf_node;
|
||||
node->path = lv_strdup(path);
|
||||
node->ip = lv_strdup(ip);
|
||||
|
||||
LV_ASSERT_MALLOC(path);
|
||||
LV_ASSERT_MALLOC(ip);
|
||||
}
|
||||
|
||||
void lv_gltf_data_node_add(lv_gltf_model_t * data, const lv_gltf_data_node_t * data_node)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
lv_array_push_back(&data->nodes, data_node);
|
||||
}
|
||||
|
||||
lv_gltf_data_node_t * lv_gltf_data_node_get_by_index(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
if(index >= lv_array_size(&data->nodes)) {
|
||||
return nullptr;
|
||||
}
|
||||
return (lv_gltf_data_node_t *)lv_array_at(&data->nodes, index);
|
||||
}
|
||||
|
||||
lv_gltf_data_node_t * lv_gltf_data_node_get_by_ip(lv_gltf_model_t * data, const char * ip)
|
||||
{
|
||||
for(size_t i = 0; i < data->nodes.size; ++i) {
|
||||
lv_gltf_data_node_t * entry = (lv_gltf_data_node_t *) lv_array_at(&data->nodes, i);
|
||||
if(lv_streq(entry->ip, ip)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lv_gltf_data_node_t * lv_gltf_data_node_get_by_path(lv_gltf_model_t * data, const char * path)
|
||||
{
|
||||
|
||||
for(size_t i = 0; i < data->nodes.size; ++i) {
|
||||
lv_gltf_data_node_t * entry = (lv_gltf_data_node_t *) lv_array_at(&data->nodes, i);
|
||||
if(lv_streq(entry->path, path)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @file lv_gltf_data_primitive.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
#include "../../../misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_gltf_primitive_t * lv_gltf_data_get_primitive_from_mesh(lv_gltf_mesh_data_t * mesh, uint64_t index)
|
||||
{
|
||||
return &(mesh->primitives[index]);
|
||||
}
|
||||
|
||||
void lv_gltf_data_add_opaque_node_primitive(lv_gltf_model_t * data, size_t index,
|
||||
fastgltf::Node * node, size_t primitive_index)
|
||||
{
|
||||
data->opaque_nodes_by_material_index[index].emplace_back(
|
||||
std::make_pair(node, primitive_index));
|
||||
}
|
||||
|
||||
void lv_gltf_data_add_blended_node_primitive(lv_gltf_model_t * data, size_t index,
|
||||
fastgltf::Node * node, size_t primitive_index)
|
||||
{
|
||||
data->blended_nodes_by_material_index[index].push_back(
|
||||
std::make_pair(node, primitive_index));
|
||||
}
|
||||
|
||||
fastgltf::math::fvec4 lv_gltf_get_primitive_centerpoint(lv_gltf_model_t * data,
|
||||
fastgltf::Mesh & mesh,
|
||||
uint32_t prim_num)
|
||||
{
|
||||
fastgltf::math::fvec4 result{ 0.f };
|
||||
fastgltf::math::fvec3 v_min{ 999999999.f };
|
||||
fastgltf::math::fvec3 v_max{ -999999999.f };
|
||||
fastgltf::math::fvec3 v_cen{ 0.f };
|
||||
float radius = 0.f;
|
||||
|
||||
if(mesh.primitives.size() <= prim_num) {
|
||||
return result;
|
||||
}
|
||||
const auto & it = mesh.primitives[prim_num];
|
||||
const auto & asset = data->asset;
|
||||
|
||||
const auto * positionIt = it.findAttribute("POSITION");
|
||||
const auto & positionAccessor =
|
||||
asset.accessors[positionIt->accessorIndex];
|
||||
if(!positionAccessor.bufferViewIndex.has_value()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!(positionAccessor.min.has_value() &&
|
||||
positionAccessor.max.has_value())) {
|
||||
LV_LOG_ERROR(
|
||||
"Could not get primitive center point. Missing min/max values");
|
||||
return result;
|
||||
}
|
||||
|
||||
fastgltf::math::fvec4 t_min{
|
||||
(float)(positionAccessor.min.value().get<double>((size_t)0)),
|
||||
(float)(positionAccessor.min.value().get<double>((size_t)1)),
|
||||
(float)(positionAccessor.min.value().get<double>((size_t)2)),
|
||||
0.f
|
||||
};
|
||||
fastgltf::math::fvec4 t_max{
|
||||
(float)(positionAccessor.max.value().get<double>((size_t)0)),
|
||||
(float)(positionAccessor.max.value().get<double>((size_t)1)),
|
||||
(float)(positionAccessor.max.value().get<double>((size_t)2)),
|
||||
0.f
|
||||
};
|
||||
|
||||
v_max[0] = LV_MAX(t_min.x(), t_max.x());
|
||||
v_max[1] = LV_MAX(t_min.y(), t_max.y());
|
||||
v_max[2] = LV_MAX(t_min.z(), t_max.z());
|
||||
v_min[0] = LV_MIN(t_min.x(), t_max.x());
|
||||
v_min[1] = LV_MIN(t_min.y(), t_max.y());
|
||||
v_min[2] = LV_MIN(t_min.z(), t_max.z());
|
||||
v_cen[0] = (v_max[0] + v_min[0]) / 2.0f;
|
||||
v_cen[1] = (v_max[1] + v_min[1]) / 2.0f;
|
||||
v_cen[2] = (v_max[2] + v_min[2]) / 2.0f;
|
||||
float size_x = v_max[0] - v_min[0];
|
||||
float size_y = v_max[1] - v_min[1];
|
||||
float size_z = v_max[2] - v_min[2];
|
||||
radius = std::sqrt((size_x * size_x) + (size_y * size_y) +
|
||||
(size_z * size_z)) /
|
||||
2.0f;
|
||||
result[0] = v_cen[0];
|
||||
result[1] = v_cen[1];
|
||||
result[2] = v_cen[2];
|
||||
result[3] = radius;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file lv_gltf_data_shader.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include "../../../misc/lv_array.h"
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gltf_store_compiled_shader(lv_gltf_model_t * data, size_t identifier, lv_gltf_compiled_shader_t * shader)
|
||||
{
|
||||
const size_t index = identifier - 1;
|
||||
bool has_to_resize = index >= lv_array_size(&data->compiled_shaders);
|
||||
if(!has_to_resize) {
|
||||
lv_array_assign(&data->compiled_shaders, index, shader);
|
||||
}
|
||||
while(index >= lv_array_size(&data->compiled_shaders)) {
|
||||
lv_array_push_back(&data->compiled_shaders, shader);
|
||||
}
|
||||
}
|
||||
|
||||
lv_gltf_compiled_shader_t * lv_gltf_get_compiled_shader(lv_gltf_model_t * data, size_t identifier)
|
||||
{
|
||||
const size_t index = identifier - 1;
|
||||
LV_ASSERT(index < lv_array_size(&data->compiled_shaders));
|
||||
return (lv_gltf_compiled_shader_t *)lv_array_at(&data->compiled_shaders, index);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file lv_gltf_data_skin.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include <algorithm>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
GLuint lv_gltf_data_get_skin_texture_at(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
return data->skin_tex[index];
|
||||
}
|
||||
|
||||
bool lv_gltf_data_validated_skins_contains(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
return ((std::find(data->validated_skins.begin(),
|
||||
data->validated_skins.end(),
|
||||
index) != data->validated_skins.end()));
|
||||
}
|
||||
|
||||
void lv_gltf_data_validate_skin(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
data->validated_skins.push_back(index);
|
||||
}
|
||||
|
||||
size_t lv_gltf_data_get_skins_size(lv_gltf_model_t * data)
|
||||
{
|
||||
return data->validated_skins.size();
|
||||
}
|
||||
size_t lv_gltf_data_get_skin(lv_gltf_model_t * data, size_t index)
|
||||
{
|
||||
return data->validated_skins[index];
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @file lv_gltf_data_texture.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <cstdint>
|
||||
#include "../../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gltf_data_destroy_textures(lv_gltf_model_t * data)
|
||||
{
|
||||
glDeleteTextures(data->skin_tex.size(), data->skin_tex.data());
|
||||
data->skin_tex.clear();
|
||||
}
|
||||
|
||||
GLuint lv_gltf_data_create_texture(lv_gltf_model_t * data)
|
||||
{
|
||||
GLuint texture;
|
||||
GL_CALL(glGenTextures(1, &texture));
|
||||
data->skin_tex.push_back(texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool lv_gltf_data_get_texture_pixels(uint8_t * pixels, lv_gltf_model_t * data_obj, uint32_t model_texture_index,
|
||||
uint32_t mipmapnum,
|
||||
uint32_t width, uint32_t height, bool has_alpha)
|
||||
{
|
||||
// This parameter is specified because WebGL can't read a texture's width from the GPU, however this isn't yet implemented so for now it either uses the GPU or it fails.
|
||||
LV_UNUSED(width);
|
||||
LV_UNUSED(height);
|
||||
|
||||
if(model_texture_index >= data_obj->textures.size()) {
|
||||
return false;
|
||||
}
|
||||
GLuint texid = data_obj->textures[model_texture_index];
|
||||
// Bind the texture
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, texid));
|
||||
GL_CALL(glGetTexImage(GL_TEXTURE_2D, mipmapnum, (has_alpha) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
void lv_gltf_data_texture_to_image_dsc(lv_image_dsc_t * new_image_dsc, lv_gltf_model_t * data_obj,
|
||||
uint32_t model_texture_index)
|
||||
{
|
||||
size_t byte_total_count = 0;
|
||||
uint32_t source_pixel_width = 0;
|
||||
uint32_t source_pixel_height = 0;
|
||||
bool has_alpha = false;
|
||||
uint8_t * pixel_buffer;
|
||||
if(lv_gltf_data_get_texture_info(data_obj, model_texture_index, 0, &byte_total_count, &source_pixel_width,
|
||||
&source_pixel_height, &has_alpha)) {
|
||||
pixel_buffer = (uint8_t *)lv_malloc(byte_total_count);
|
||||
if(lv_gltf_data_get_texture_pixels(pixel_buffer, data_obj, model_texture_index, 0, source_pixel_width,
|
||||
source_pixel_height, has_alpha)) {
|
||||
if(pixel_buffer == NULL || byte_total_count == 0 || source_pixel_width == 0)
|
||||
return;
|
||||
|
||||
if(new_image_dsc->data_size > 0) {
|
||||
lv_free((uint8_t *)new_image_dsc->data);
|
||||
new_image_dsc->data = NULL;
|
||||
new_image_dsc->data_size = 0;
|
||||
}
|
||||
|
||||
lv_gltf_data_rgb_to_bgr(pixel_buffer, byte_total_count, has_alpha);
|
||||
size_t bytes_per_pixel = has_alpha ? 4 : 3;
|
||||
size_t pixel_count = (byte_total_count / bytes_per_pixel);
|
||||
|
||||
new_image_dsc->data = (const uint8_t *)pixel_buffer;
|
||||
new_image_dsc->data_size = byte_total_count;
|
||||
new_image_dsc->header.w = source_pixel_width;
|
||||
new_image_dsc->header.h = (uint16_t)(pixel_count / source_pixel_width);
|
||||
new_image_dsc->header.cf = has_alpha ? LV_COLOR_FORMAT_ARGB8888 : LV_COLOR_FORMAT_RGB888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool lv_gltf_data_get_texture_info(lv_gltf_model_t * data_obj, uint32_t model_texture_index, uint32_t mipmapnum,
|
||||
size_t * byte_count,
|
||||
uint32_t * width, uint32_t * height, bool * has_alpha)
|
||||
{
|
||||
*byte_count = 0;
|
||||
if(model_texture_index >= data_obj->textures.size()) {
|
||||
return false;
|
||||
}
|
||||
GLuint texid = data_obj->textures[model_texture_index];
|
||||
// Bind the texture
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, texid));
|
||||
int32_t gl_color_format;
|
||||
GL_CALL(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &gl_color_format));
|
||||
|
||||
// Determine if the texture has an alpha channel
|
||||
*has_alpha = false;
|
||||
bool not_valid = false;
|
||||
|
||||
switch(gl_color_format) {
|
||||
case GL_RGBA:
|
||||
case GL_BGRA:
|
||||
case GL_RGBA8:
|
||||
*has_alpha = true;
|
||||
break;
|
||||
case GL_RGB:
|
||||
case GL_BGR:
|
||||
case GL_RGB8:
|
||||
*has_alpha = false;
|
||||
break;
|
||||
default:
|
||||
LV_LOG_ERROR("Unhandled texture color format %d", gl_color_format);
|
||||
not_valid = true;
|
||||
break;
|
||||
}
|
||||
// even if the pixel format is invalid, we can still get the width and height
|
||||
GLint texture_width;
|
||||
GLint texture_height;
|
||||
GL_CALL(glGetTexLevelParameteriv(GL_TEXTURE_2D, mipmapnum, GL_TEXTURE_WIDTH, &texture_width));
|
||||
GL_CALL(glGetTexLevelParameteriv(GL_TEXTURE_2D, mipmapnum, GL_TEXTURE_HEIGHT, &texture_height));
|
||||
*width = (uint32_t)(texture_width);
|
||||
*height = (uint32_t)(texture_height);
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
if(not_valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*byte_count = texture_width * texture_height * (*has_alpha ? 4 : 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
void lv_gltf_data_rgb_to_bgr(uint8_t * pixels, size_t byte_total_count, bool has_alpha)
|
||||
{
|
||||
size_t bytes_per_pixel = has_alpha ? 4 : 3;
|
||||
size_t pixel_count = (byte_total_count / bytes_per_pixel);
|
||||
if(bytes_per_pixel == 4) {
|
||||
for(size_t p = 0; p < pixel_count; p++) {
|
||||
size_t index = p << 2;
|
||||
uint8_t r = pixels[index + 0];
|
||||
uint8_t g = pixels[index + 1];
|
||||
uint8_t b = pixels[index + 2];
|
||||
uint8_t a = pixels[index + 3];
|
||||
pixels[index + 0] = b;
|
||||
pixels[index + 1] = g;
|
||||
pixels[index + 2] = r;
|
||||
pixels[index + 3] = a;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(size_t p = 0; p < pixel_count; p++) {
|
||||
size_t index = p * 3;
|
||||
uint8_t r = pixels[index + 0];
|
||||
uint8_t g = pixels[index + 1];
|
||||
uint8_t b = pixels[index + 2];
|
||||
pixels[index + 0] = b;
|
||||
pixels[index + 1] = g;
|
||||
pixels[index + 2] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,135 @@
|
||||
#ifndef LV_GLTF_MODEL_H
|
||||
#define LV_GLTF_MODEL_H
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../misc/lv_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* @brief Get the number of images in the glTF model
|
||||
*
|
||||
* Images in glTF are used as sources for textures and can be stored either as external files
|
||||
* or embedded as base64-encoded model within the glTF file.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of images in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_image_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of textures in the glTF model
|
||||
*
|
||||
* Textures define how images are sampled and applied to materials. Each texture references
|
||||
* an image and may specify sampling parameters like filtering and wrapping modes.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of textures in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_texture_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of materials in the glTF model
|
||||
*
|
||||
* Materials define the visual appearance of mesh primitives, including properties like
|
||||
* base color, metallic/roughness values, normal maps, and other surface characteristics.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of materials in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_material_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of cameras in the glTF model
|
||||
*
|
||||
* Cameras define viewpoints within the 3D scene and can be either perspective or
|
||||
* orthographic. They are typically attached to nodes in the scene graph.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of cameras in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_camera_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of nodes in the glTF model
|
||||
*
|
||||
* Nodes form the scene graph hierarchy and can contain transformations, meshes, cameras,
|
||||
* or other nodes as children. They define the spatial relationships between objects in the scene.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of nodes in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_node_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of meshes in the glTF model
|
||||
*
|
||||
* Meshes contain the geometric model for 3D objects, including vertex positions, normals,
|
||||
* texture coordinates, and indices. Each mesh can have multiple primitives with different materials.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of meshes in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_mesh_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of scenes in the glTF model
|
||||
*
|
||||
* Scenes define the root nodes of the scene graph. A glTF file can contain multiple scenes,
|
||||
* though typically only one is designated as the default scene to be displayed.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of scenes in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_scene_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the number of animations in the glTF model
|
||||
*
|
||||
* Animations define keyframe-based motion for nodes in the scene, including transformations
|
||||
* like translation, rotation, and scaling over time.
|
||||
*
|
||||
* @param model Pointer to the glTF model data structure
|
||||
* @return Number of animations in the model
|
||||
*/
|
||||
size_t lv_gltf_model_get_animation_count(const lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Select and start playing an animation
|
||||
*
|
||||
* @param model Pointer to the glTF model structure
|
||||
* @param index Animation number to start playing
|
||||
* @return LV_RESULT_OK if the animation was started else LV_RESULT_INVALID
|
||||
*/
|
||||
lv_result_t lv_gltf_model_play_animation(lv_gltf_model_t * model, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Pause the current animation
|
||||
*
|
||||
* @param model Pointer to the glTF model structure
|
||||
*/
|
||||
void lv_gltf_model_pause_animation(lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Check if an animation is currently being played
|
||||
*
|
||||
* @param model Pointer to the glTF model structure
|
||||
*/
|
||||
bool lv_gltf_model_is_animation_paused(lv_gltf_model_t * model);
|
||||
|
||||
/**
|
||||
* @brief Get the current selected animation. To see if it's playing see `lv_gltf_model_is_animation_paused`
|
||||
*
|
||||
* @param model Pointer to the glTF model structure
|
||||
*/
|
||||
size_t lv_gltf_model_get_animation(lv_gltf_model_t * model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /*LV_GLTF_MODEL_H*/
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
lv_gltf_uniform_locations_t lv_gltf_uniform_locations_create(GLuint program)
|
||||
{
|
||||
lv_gltf_uniform_locations_t uniforms;
|
||||
lv_memset(&uniforms, 0, sizeof(uniforms));
|
||||
|
||||
// *** IMAGE QUALITY UNIFORMS ***********************************************************************
|
||||
uniforms.exposure = glGetUniformLocation(program, "u_Exposure");
|
||||
// *** CAMERA/VIEW/PROJECTION/MODEL MATRIX UNIFORMS *************************************************
|
||||
uniforms.camera = glGetUniformLocation(program, "u_Camera");
|
||||
uniforms.model_matrix = glGetUniformLocation(program, "u_ModelMatrix");
|
||||
uniforms.view_projection_matrix = glGetUniformLocation(program, "u_ViewProjectionMatrix");
|
||||
uniforms.view_matrix = glGetUniformLocation(program, "u_ViewMatrix");
|
||||
uniforms.projection_matrix = glGetUniformLocation(program, "u_ProjectionMatrix");
|
||||
// *** IMAGE BASED LIGHTING (IBL) UNIFORMS **********************************************************
|
||||
uniforms.env_intensity = glGetUniformLocation(program, "u_EnvIntensity");
|
||||
uniforms.env_diffuse_sampler = glGetUniformLocation(program, "u_LambertianEnvSampler");
|
||||
uniforms.env_specular_sampler = glGetUniformLocation(program, "u_GGXEnvSampler");
|
||||
uniforms.env_sheen_sampler = glGetUniformLocation(program, "u_CharlieEnvSampler");
|
||||
uniforms.env_ggx_lut_sampler = glGetUniformLocation(program, "u_GGXLUT");
|
||||
uniforms.env_charlie_lut_sampler = glGetUniformLocation(program, "u_CharlieLUT");
|
||||
uniforms.env_mip_count = glGetUniformLocation(program, "u_MipCount");
|
||||
// *** BASE COLOR / TEXTURE UNIFORMS ****************************************************************
|
||||
uniforms.base_color_factor = glGetUniformLocation(program, "u_BaseColorFactor");
|
||||
uniforms.base_color_sampler = glGetUniformLocation(program, "u_BaseColorSampler");
|
||||
uniforms.base_color_uv_set = glGetUniformLocation(program, "u_BaseColorUVSet");
|
||||
uniforms.base_color_uv_transform = glGetUniformLocation(program, "u_BaseColorUVTransform");
|
||||
// *** CUTOFF / IOR / DISPERSION UNIFORMS ***********************************************************
|
||||
uniforms.alpha_cutoff = glGetUniformLocation(program, "u_AlphaCutoff");
|
||||
uniforms.ior = glGetUniformLocation(program, "u_Ior");
|
||||
uniforms.dispersion = glGetUniformLocation(program, "u_Dispersion");
|
||||
// *** METALLIC / ROUGHNESS UNIFORMS ****************************************************************
|
||||
uniforms.metallic_factor = glGetUniformLocation(program, "u_MetallicFactor");
|
||||
uniforms.roughness_factor = glGetUniformLocation(program, "u_RoughnessFactor");
|
||||
uniforms.metallic_roughness_sampler = glGetUniformLocation(program, "u_MetallicRoughnessSampler");
|
||||
uniforms.metallic_roughness_uv_set = glGetUniformLocation(program, "u_MetallicRoughnessUVSet");
|
||||
uniforms.metallic_roughness_uv_transform = glGetUniformLocation(program, "u_MetallicRoughnessUVTransform");
|
||||
// *** EMISSION UNIFORMS ****************************************************************************
|
||||
uniforms.emissive_factor = glGetUniformLocation(program, "u_EmissiveFactor");
|
||||
uniforms.emissive_sampler = glGetUniformLocation(program, "u_EmissiveSampler");
|
||||
uniforms.emissive_uv_set = glGetUniformLocation(program, "u_EmissiveUVSet");
|
||||
uniforms.emissive_uv_transform = glGetUniformLocation(program, "u_EmissiveUVTransform");
|
||||
uniforms.emissive_strength = glGetUniformLocation(program, "u_EmissiveStrength");
|
||||
// *** OCCLUSION UNIFORMS ***************************************************************************
|
||||
uniforms.occlusion_strength = glGetUniformLocation(program, "u_OcclusionStrength");
|
||||
uniforms.occlusion_sampler = glGetUniformLocation(program, "u_OcclusionSampler");
|
||||
uniforms.occlusion_uv_set = glGetUniformLocation(program, "u_OcclusionUVSet");
|
||||
uniforms.occlusion_uv_transform = glGetUniformLocation(program, "u_OcclusionUVTransform");
|
||||
// *** NORMAL MAP UNIFORMS **************************************************************************
|
||||
uniforms.normal_sampler = glGetUniformLocation(program, "u_NormalSampler");
|
||||
uniforms.normal_scale = glGetUniformLocation(program, "u_NormalScale");
|
||||
uniforms.normal_uv_set = glGetUniformLocation(program, "u_NormalUVSet");
|
||||
uniforms.normal_uv_transform = glGetUniformLocation(program, "u_NormalUVTransform");
|
||||
// *** VOLUME / TRANSMISSION UNIFORMS ***************************************************************
|
||||
uniforms.attenuation_distance = glGetUniformLocation(program, "u_AttenuationDistance");
|
||||
uniforms.attenuation_color = glGetUniformLocation(program, "u_AttenuationColor");
|
||||
uniforms.transmission_factor = glGetUniformLocation(program, "u_TransmissionFactor");
|
||||
uniforms.transmission_sampler = glGetUniformLocation(program, "u_TransmissionSampler");
|
||||
uniforms.transmission_uv_set = glGetUniformLocation(program, "u_TransmissionUVSet");
|
||||
uniforms.transmission_uv_transform = glGetUniformLocation(program, "u_TransmissionUVTransform");
|
||||
uniforms.transmission_framebuffer_sampler = glGetUniformLocation(program, "u_TransmissionFramebufferSampler");
|
||||
uniforms.transmission_framebuffer_size = glGetUniformLocation(program, "u_TransmissionFramebufferSize");
|
||||
uniforms.screen_size = glGetUniformLocation(program, "u_ScreenSize");
|
||||
uniforms.thickness = glGetUniformLocation(program, "u_ThicknessFactor");
|
||||
uniforms.thickness_sampler = glGetUniformLocation(program, "u_ThicknessSampler");
|
||||
uniforms.thickness_uv_set = glGetUniformLocation(program, "u_ThicknessUVSet");
|
||||
uniforms.thickness_uv_transform = glGetUniformLocation(program, "u_ThicknessUVTransform");
|
||||
// *** CLEARCOAT UNIFORMS ***************************************************************************
|
||||
uniforms.clearcoat_factor = glGetUniformLocation(program, "u_ClearcoatFactor");
|
||||
uniforms.clearcoat_roughness_factor = glGetUniformLocation(program, "u_ClearcoatRoughnessFactor");
|
||||
uniforms.clearcoat_sampler = glGetUniformLocation(program, "u_ClearcoatSampler");
|
||||
uniforms.clearcoat_uv_set = glGetUniformLocation(program, "u_ClearcoatUVSet");
|
||||
uniforms.clearcoat_uv_transform = glGetUniformLocation(program, "u_ClearcoatUVTransform");
|
||||
uniforms.clearcoat_roughness_sampler = glGetUniformLocation(program, "u_ClearcoatRoughnessSampler");
|
||||
uniforms.clearcoat_roughness_uv_set = glGetUniformLocation(program, "u_ClearcoatRoughnessUVSet");
|
||||
uniforms.clearcoat_roughness_uv_transform = glGetUniformLocation(program, "u_ClearcoatRoughnessUVTransform");
|
||||
uniforms.clearcoat_normal_scale = glGetUniformLocation(program, "u_ClearcoatNormalScale");
|
||||
uniforms.clearcoat_normal_sampler = glGetUniformLocation(program, "u_ClearcoatNormalSampler");
|
||||
uniforms.clearcoat_normal_uv_set = glGetUniformLocation(program, "u_ClearcoatNormalUVSet");
|
||||
uniforms.clearcoat_normal_uv_transform = glGetUniformLocation(program, "u_ClearcoatNormalUVTransform");
|
||||
// *** DIFFUSE TRANSMISSION UNIFORMS ****************************************************************
|
||||
uniforms.diffuse_transmission_factor = glGetUniformLocation(program, "u_DiffuseTransmissionFactor");
|
||||
uniforms.diffuse_transmission_sampler = glGetUniformLocation(program, "u_DiffuseTransmissionSampler");
|
||||
uniforms.diffuse_transmission_uv_set = glGetUniformLocation(program, "u_DiffuseTransmissionUVSet");
|
||||
uniforms.diffuse_transmission_uv_transform = glGetUniformLocation(program, "u_DiffuseTransmissionUVTransform");
|
||||
uniforms.diffuse_transmission_color_factor = glGetUniformLocation(program, "u_DiffuseTransmissionColorFactor");
|
||||
uniforms.diffuse_transmission_color_sampler = glGetUniformLocation(program, "u_DiffuseTransmissionColorSampler");
|
||||
uniforms.diffuse_transmission_color_uv_set = glGetUniformLocation(program, "u_DiffuseTransmissionColorUVSet");
|
||||
uniforms.diffuse_transmission_color_uv_transform = glGetUniformLocation(program,
|
||||
"u_DiffuseTransmissionColorUVTransform");
|
||||
// *** LEGACY SUPPORT - PBR_SPECULARGLOSS ***********************************************************
|
||||
uniforms.diffuse_factor = glGetUniformLocation(program, "u_DiffuseFactor");
|
||||
uniforms.specular_factor = glGetUniformLocation(program, "u_SpecularFactor");
|
||||
uniforms.glossiness_factor = glGetUniformLocation(program, "u_GlossinessFactor");
|
||||
uniforms.diffuse_sampler = glGetUniformLocation(program, "u_DiffuseSampler");
|
||||
uniforms.diffuse_uv_set = glGetUniformLocation(program, "u_DiffuseUVSet");
|
||||
uniforms.diffuse_uv_transform = glGetUniformLocation(program, "u_DiffuseUVTransform");
|
||||
uniforms.specular_glossiness_sampler = glGetUniformLocation(program, "u_SpecularGlossinessSampler");
|
||||
uniforms.specular_glossiness_uv_set = glGetUniformLocation(program, "u_SpecularGlossinessUVSet");
|
||||
uniforms.specular_glossiness_uv_transform = glGetUniformLocation(program, "u_SpecularGlossinessUVTransform");
|
||||
// *** [PARTIALLY SUPPORTED / IN DEVELOPMENT] UNIFORMS **********************************************
|
||||
uniforms.sheen_color_factor = glGetUniformLocation(program, "u_SheenColorFactor");
|
||||
uniforms.sheen_roughness_factor = glGetUniformLocation(program, "u_SheenRoughnessFactor");
|
||||
//
|
||||
uniforms.specular_color_factor = glGetUniformLocation(program, "u_KHR_materials_specular_specularColorFactor");
|
||||
uniforms.specular_factor = glGetUniformLocation(program, "u_KHR_materials_specular_specularFactor");
|
||||
//
|
||||
uniforms.joints_sampler = glGetUniformLocation(program, "u_jointsSampler");
|
||||
return uniforms;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file lv_gltf_view_shader.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_VIEW_SHADER_H
|
||||
#define LV_GLTF_VIEW_SHADER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../opengl_shader/lv_opengl_shader_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define GLSL_VERSION_PREFIX "#version 300 es\n"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
const lv_opengl_shader_t *shader_list;
|
||||
size_t count;
|
||||
} lv_gltf_view_shader_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
char *lv_gltf_view_shader_get_vertex(void);
|
||||
char *lv_gltf_view_shader_get_fragment(void);
|
||||
void lv_gltf_view_shader_get_src(lv_gltf_view_shader_t *shaders);
|
||||
void lv_gltf_view_shader_get_env(lv_gltf_view_shader_t *shaders);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_VIEW_SHADER_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,474 @@
|
||||
/**
|
||||
* @file lv_gltf_ibl_sampler.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_ibl_sampler.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../../misc/lv_math.h"
|
||||
#include "../../../../misc/lv_log.h"
|
||||
#include "../../../../stdlib/lv_string.h"
|
||||
#include "../../../../drivers/glfw/lv_opengles_debug.h"
|
||||
|
||||
#include "../../opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../lv_gltf_view_internal.h"
|
||||
#include "../assets/lv_gltf_view_shader.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../../stb_image/stb_image.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define INTERNAL_FORMAT GL_RGBA8
|
||||
#define TEXTURE_TARGET_TYPE GL_UNSIGNED_BYTE
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void ibl_sampler_init(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_sampler_load(lv_gltf_ibl_sampler_t * sampler, const char * path);
|
||||
static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_sampler_destroy(lv_gltf_ibl_sampler_t * sampler);
|
||||
static bool ibl_gl_has_extension(const char * extension);
|
||||
static void ibl_texture_from_image(lv_gltf_ibl_sampler_t * sampler, lv_gltf_ibl_texture_t * texture,
|
||||
const lv_gltf_ibl_image_t * image);
|
||||
static GLuint ibl_load_texture_hdr(lv_gltf_ibl_sampler_t * sampler, const lv_gltf_ibl_image_t * image);
|
||||
static GLuint ibl_create_cubemap_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps);
|
||||
static uint32_t ibl_create_lut_texture(const lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_panorama_to_cubemap(const lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_apply_filter(const lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, float roughness,
|
||||
uint32_t target_mip_level, GLuint target_texture, uint32_t sample_count, float lod_bias);
|
||||
static void ibl_cubemap_to_lambertian(const lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_cubemap_to_ggx(const lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_cubemap_to_sheen(const lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_sample_lut(const lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, uint32_t targetTexture,
|
||||
uint32_t currentTextureSize);
|
||||
static void ibl_sample_ggx_lut(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_sample_charlie_lut(lv_gltf_ibl_sampler_t * sampler);
|
||||
static int ibl_count_bits(int value);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gltf_ibl_generate_env_textures(lv_gltf_view_env_textures_t * env, const char * path, float env_rotation)
|
||||
{
|
||||
lv_gltf_ibl_sampler_t sampler;
|
||||
|
||||
ibl_sampler_init(&sampler);
|
||||
ibl_sampler_load(&sampler, path);
|
||||
ibl_sampler_filter(&sampler);
|
||||
|
||||
env->angle = env_rotation;
|
||||
env->diffuse = sampler.lambertian_texture_id;
|
||||
env->specular = sampler.ggx_texture_id;
|
||||
env->sheen = sampler.sheen_texture_id;
|
||||
env->ggxLut = sampler.ggxlut_texture_id;
|
||||
env->charlie_lut = sampler.charlielut_texture_id;
|
||||
env->mip_count = sampler.mipmap_levels;
|
||||
env->ibl_intensity_scale = sampler.scale_value;
|
||||
ibl_sampler_destroy(&sampler);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void ibl_sampler_init(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
lv_memset(sampler, 0, sizeof(*sampler));
|
||||
sampler->texture_size = 128;
|
||||
sampler->ggx_sample_count = 128;
|
||||
sampler->lambertian_sample_count = 256;
|
||||
sampler->sheen_sample_count = 32;
|
||||
sampler->lod_bias = 0.0;
|
||||
sampler->lowest_mip_level = 3;
|
||||
sampler->lut_resolution = 1024;
|
||||
sampler->lut_sample_count = 64;
|
||||
sampler->scale_value = 1.0;
|
||||
lv_gltf_view_shader_t env_shader;
|
||||
lv_gltf_view_shader_get_env(&env_shader);
|
||||
sampler->shader_manager = lv_opengl_shader_manager_create(env_shader.shader_list, env_shader.count, NULL, NULL);
|
||||
}
|
||||
|
||||
static void ibl_sampler_load(lv_gltf_ibl_sampler_t * sampler, const char * path)
|
||||
{
|
||||
// vv -- WebGL Naming
|
||||
if(ibl_gl_has_extension("GL_NV_float") && ibl_gl_has_extension("GL_ARB_color_buffer_float")) {
|
||||
LV_LOG_INFO("Device supports float format textures");
|
||||
}
|
||||
// Native naming #2
|
||||
if(ibl_gl_has_extension("GL_ARB_color_buffer_float") || ibl_gl_has_extension("GL_NV_half_float")) {
|
||||
LV_LOG_INFO("Device supports half_float format textures");
|
||||
}
|
||||
|
||||
int32_t src_width, src_height, src_nrChannels;
|
||||
|
||||
float * data;
|
||||
if(path != NULL) {
|
||||
data = stbi_loadf(path, &src_width, &src_height, &src_nrChannels, 3);
|
||||
}
|
||||
else {
|
||||
extern unsigned char pisa_jpg[];
|
||||
extern unsigned int pisa_jpg_len;
|
||||
data = stbi_loadf_from_memory(pisa_jpg, pisa_jpg_len, &src_width, &src_height, &src_nrChannels, 3);
|
||||
}
|
||||
|
||||
{
|
||||
lv_gltf_ibl_image_t panorama_image = {
|
||||
.data = (float *)lv_malloc(src_width * src_height * 3 * sizeof(float)),
|
||||
.data_len = src_width * src_height * 3,
|
||||
.width = src_width,
|
||||
.height = src_height,
|
||||
};
|
||||
LV_ASSERT_MALLOC(panorama_image.data);
|
||||
|
||||
lv_memcpy(panorama_image.data, data, panorama_image.data_len * sizeof(*panorama_image.data));
|
||||
stbi_image_free(data);
|
||||
sampler->input_texture_id = ibl_load_texture_hdr(sampler, &panorama_image);
|
||||
lv_free(panorama_image.data);
|
||||
}
|
||||
|
||||
GL_CALL(glGenFramebuffers(1, &sampler->framebuffer));
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
|
||||
|
||||
sampler->cubemap_texture_id = ibl_create_cubemap_texture(sampler, true);
|
||||
sampler->lambertian_texture_id = ibl_create_cubemap_texture(sampler, false);
|
||||
sampler->ggx_texture_id = ibl_create_cubemap_texture(sampler, true);
|
||||
sampler->sheen_texture_id = ibl_create_cubemap_texture(sampler, true);
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->ggx_texture_id));
|
||||
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->sheen_texture_id));
|
||||
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
|
||||
sampler->mipmap_levels = ibl_count_bits(sampler->texture_size) + 1 - sampler->lowest_mip_level;
|
||||
}
|
||||
|
||||
static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
GLint prev_framebuffer;
|
||||
GL_CALL(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_framebuffer));
|
||||
|
||||
ibl_panorama_to_cubemap(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
|
||||
ibl_cubemap_to_lambertian(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
|
||||
ibl_cubemap_to_ggx(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
|
||||
ibl_cubemap_to_sheen(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
|
||||
ibl_sample_ggx_lut(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
|
||||
ibl_sample_charlie_lut(sampler);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
}
|
||||
static void ibl_sampler_destroy(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
lv_opengl_shader_manager_destroy(sampler->shader_manager);
|
||||
}
|
||||
|
||||
static void ibl_texture_from_image(lv_gltf_ibl_sampler_t * sampler, lv_gltf_ibl_texture_t * texture,
|
||||
const lv_gltf_ibl_image_t * image)
|
||||
{
|
||||
const size_t src_format_bpp = 3;
|
||||
const size_t dst_format_bpp = 4;
|
||||
|
||||
texture->internal_format = INTERNAL_FORMAT;
|
||||
texture->format = GL_RGBA;
|
||||
texture->type = TEXTURE_TARGET_TYPE;
|
||||
size_t pixel_num = image->data_len / src_format_bpp;
|
||||
texture->data = (uint8_t *)lv_malloc(pixel_num * 4);
|
||||
LV_ASSERT_MALLOC(texture->data);
|
||||
|
||||
float max_value = 0.0;
|
||||
float clamped_sum = 0.0;
|
||||
float diff_sum = 0.0;
|
||||
size_t src = 0;
|
||||
size_t dst = 0;
|
||||
|
||||
for(size_t i = 0; i < pixel_num; i++) {
|
||||
const float r = image->data[src + 0];
|
||||
const float g = image->data[src + 1];
|
||||
const float b = image->data[src + 2];
|
||||
const float max_component = LV_MAX(LV_MAX(r, g), b);
|
||||
|
||||
if(max_component > 1.0) {
|
||||
diff_sum += max_component - 1.0;
|
||||
}
|
||||
clamped_sum += LV_MIN(max_component, 1.0f);
|
||||
max_value = LV_MAX(max_component, max_value);
|
||||
|
||||
texture->data[dst + 0] = LV_MIN(r * 255, 255);
|
||||
texture->data[dst + 1] = LV_MIN(g * 255, 255);
|
||||
texture->data[dst + 2] = LV_MIN(b * 255, 255);
|
||||
texture->data[dst + 3] = 0xFF;
|
||||
|
||||
src += src_format_bpp;
|
||||
dst += dst_format_bpp;
|
||||
}
|
||||
|
||||
float scale_factor = 1.0;
|
||||
if(clamped_sum > 1.0) {
|
||||
// Apply global scale factor to compensate for intensity lost when clamping
|
||||
scale_factor = (clamped_sum + diff_sum) / clamped_sum;
|
||||
LV_LOG_INFO("HDR Intensity Scale %f\n", scale_factor);
|
||||
}
|
||||
|
||||
sampler->scale_value = scale_factor;
|
||||
}
|
||||
static uint32_t ibl_load_texture_hdr(lv_gltf_ibl_sampler_t * sampler, const lv_gltf_ibl_image_t * image)
|
||||
{
|
||||
lv_gltf_ibl_texture_t texture;
|
||||
ibl_texture_from_image(sampler, &texture, image);
|
||||
GLuint texture_id;
|
||||
GL_CALL(glGenTextures(1, &texture_id));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture_id));
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, // target
|
||||
0, // level
|
||||
texture.internal_format, image->width, image->height,
|
||||
0, // border
|
||||
texture.format, // format of the pixel data
|
||||
texture.type, // type of the pixel data
|
||||
texture.data));
|
||||
|
||||
lv_free(texture.data);
|
||||
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static GLuint ibl_create_cubemap_texture(const lv_gltf_ibl_sampler_t * sampler, bool with_mipmaps)
|
||||
{
|
||||
uint32_t targetTexture;
|
||||
GL_CALL(glGenTextures(1, &targetTexture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, targetTexture));
|
||||
for(int32_t i = 0; i < 6; ++i) {
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, INTERNAL_FORMAT, sampler->texture_size,
|
||||
sampler->texture_size, 0, GL_RGBA, TEXTURE_TARGET_TYPE, NULL));
|
||||
}
|
||||
if(with_mipmaps) {
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
|
||||
}
|
||||
else {
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
}
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
return targetTexture;
|
||||
}
|
||||
static GLuint ibl_create_lut_texture(const lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
GLuint texture;
|
||||
GL_CALL(glGenTextures(1, &texture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, sampler->lut_resolution, sampler->lut_resolution, 0, GL_RGBA,
|
||||
TEXTURE_TARGET_TYPE, NULL));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
return texture;
|
||||
}
|
||||
static void ibl_panorama_to_cubemap(const lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
for(int32_t i = 0; i < 6; ++i) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
||||
sampler->cubemap_texture_id, 0));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
while(status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
LV_LOG_ERROR("Environnement render error not complete. Expected %d. Got %d", GL_FRAMEBUFFER_COMPLETE,
|
||||
status);
|
||||
}
|
||||
GL_CALL(glViewport(0, 0, sampler->texture_size, sampler->texture_size));
|
||||
GL_CALL(glClearColor(1.0, 0.0, 0.0, 0.0));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
uint32_t frag_shader =
|
||||
lv_opengl_shader_manager_select_shader(sampler->shader_manager, "panorama_to_cubemap.frag", NULL, 0);
|
||||
uint32_t vert_shader = lv_opengl_shader_manager_select_shader(sampler->shader_manager, "fullscreen.vert", NULL, 0);
|
||||
lv_opengl_shader_program_t * program =
|
||||
lv_opengl_shader_manager_get_program(sampler->shader_manager, frag_shader, vert_shader);
|
||||
GLuint program_id = lv_opengl_shader_program_get_id(program);
|
||||
|
||||
GL_CALL(glUseProgram(program_id));
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
|
||||
// Bind texture ID to active texture
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, sampler->input_texture_id));
|
||||
// map shader uniform to texture unit (TEXTURE0)
|
||||
GLuint location;
|
||||
GL_CALL(location = glGetUniformLocation(program_id, "u_panorama"));
|
||||
GL_CALL(glUniform1i(location, 0));
|
||||
program->update_uniform_1i(program, "u_currentFace", i);
|
||||
//fullscreen triangle
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
|
||||
}
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
|
||||
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
|
||||
}
|
||||
static void ibl_apply_filter(const lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, float roughness,
|
||||
uint32_t target_mip_level, GLuint target_texture, uint32_t sample_count, float lod_bias)
|
||||
{
|
||||
uint32_t current_texture_size = sampler->texture_size >> target_mip_level;
|
||||
for(uint32_t i = 0; i < 6; ++i) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
||||
target_texture, target_mip_level));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, target_texture));
|
||||
GL_CALL(glViewport(0, 0, current_texture_size, current_texture_size));
|
||||
GL_CALL(glClearColor(0.0, 1.0, 0.0, 0.0));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
uint32_t frag_shader =
|
||||
lv_opengl_shader_manager_select_shader(sampler->shader_manager, "ibl_filtering.frag", NULL, 0);
|
||||
uint32_t vert_shader = lv_opengl_shader_manager_select_shader(sampler->shader_manager, "fullscreen.vert", NULL, 0);
|
||||
lv_opengl_shader_program_t * program =
|
||||
lv_opengl_shader_manager_get_program(sampler->shader_manager, frag_shader, vert_shader);
|
||||
GLuint program_id = lv_opengl_shader_program_get_id(program);
|
||||
|
||||
GL_CALL(glUseProgram(program_id));
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0));
|
||||
// Bind texture ID to active texture
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
|
||||
// map shader uniform to texture unit (TEXTURE0)
|
||||
uint32_t location = glGetUniformLocation(program_id, "u_cubemapTexture");
|
||||
GL_CALL(glUniform1i(location, 0)); // texture unit 0
|
||||
program->update_uniform_1f(program, "u_roughness", roughness);
|
||||
program->update_uniform_1i(program, "u_sampleCount", sample_count);
|
||||
/* Software rendered mode looks better with this and horrible with below */
|
||||
/*program->update_uniform_1i(program, "u_width", current_texture_size); */
|
||||
/* Standard mode looks best with this and somewhat worse with above */
|
||||
program->update_uniform_1i(program, "u_width", sampler->texture_size);
|
||||
program->update_uniform_1f(program, "u_lodBias", lod_bias);
|
||||
program->update_uniform_1i(program, "u_distribution", distribution);
|
||||
program->update_uniform_1i(program, "u_currentFace", i);
|
||||
program->update_uniform_1i(program, "u_isGeneratingLUT", 0);
|
||||
program->update_uniform_1i(program, "u_floatTexture", 0);
|
||||
program->update_uniform_1f(program, "u_intensityScale", sampler->scale_value);
|
||||
//fullscreen triangle
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
|
||||
}
|
||||
}
|
||||
static void ibl_cubemap_to_lambertian(const lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
ibl_apply_filter(sampler, 0, 0.0, 0, sampler->lambertian_texture_id, sampler->lambertian_sample_count, 0.0);
|
||||
}
|
||||
static void ibl_cubemap_to_ggx(const lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
LV_ASSERT(sampler->mipmap_levels != 1);
|
||||
for(uint32_t current_mip_level = 0; current_mip_level <= sampler->mipmap_levels; ++current_mip_level) {
|
||||
float roughness = (current_mip_level) / (float)(sampler->mipmap_levels - 1);
|
||||
ibl_apply_filter(sampler, 1, roughness, current_mip_level, sampler->ggx_texture_id, sampler->ggx_sample_count,
|
||||
0.0);
|
||||
}
|
||||
}
|
||||
static void ibl_cubemap_to_sheen(const lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
LV_ASSERT(sampler->mipmap_levels != 1);
|
||||
for(uint32_t current_mip_level = 0; current_mip_level <= sampler->mipmap_levels; ++current_mip_level) {
|
||||
float roughness = (current_mip_level) / (float)(sampler->mipmap_levels - 1);
|
||||
ibl_apply_filter(sampler, 2, roughness, current_mip_level, sampler->sheen_texture_id,
|
||||
sampler->sheen_sample_count, 0.0);
|
||||
}
|
||||
}
|
||||
static void ibl_sample_lut(const lv_gltf_ibl_sampler_t * sampler, uint32_t distribution, uint32_t targetTexture,
|
||||
uint32_t currentTextureSize)
|
||||
{
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, targetTexture, 0));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, targetTexture));
|
||||
GL_CALL(glViewport(0, 0, currentTextureSize, currentTextureSize));
|
||||
GL_CALL(glClearColor(0.0, 1.0, 1.0, 0.0));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
uint32_t frag_shader = lv_opengl_shader_manager_select_shader(sampler->shader_manager, "ibl_filtering.frag", NULL, 0);
|
||||
uint32_t vert_shader = lv_opengl_shader_manager_select_shader(sampler->shader_manager, "fullscreen.vert", NULL, 0);
|
||||
lv_opengl_shader_program_t * program = lv_opengl_shader_manager_get_program(sampler->shader_manager, frag_shader,
|
||||
vert_shader);
|
||||
GLuint program_id = lv_opengl_shader_program_get_id(program);
|
||||
|
||||
GL_CALL(glUseProgram(program_id));
|
||||
// TEXTURE0 = active.
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
|
||||
// Bind texture ID to active texture
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cubemap_texture_id));
|
||||
// map shader uniform to texture unit (TEXTURE0)
|
||||
uint32_t location = glGetUniformLocation(program_id, "u_cubemapTexture");
|
||||
GL_CALL(glUniform1i(location, 0)); // texture unit 0
|
||||
program->update_uniform_1f(program, "u_roughness", 0.0);
|
||||
program->update_uniform_1i(program, "u_sampleCount", sampler->lut_sample_count);
|
||||
//shader->update_uniform_1i( shader, "u_sampleCount", 512);
|
||||
program->update_uniform_1i(program, "u_width", 0.0);
|
||||
program->update_uniform_1f(program, "u_lodBias", 0.0);
|
||||
program->update_uniform_1i(program, "u_distribution", distribution);
|
||||
program->update_uniform_1i(program, "u_currentFace", 0);
|
||||
program->update_uniform_1i(program, "u_isGeneratingLUT", 1);
|
||||
//fullscreen triangle
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
|
||||
}
|
||||
static void ibl_sample_ggx_lut(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
sampler->ggxlut_texture_id = ibl_create_lut_texture(sampler);
|
||||
ibl_sample_lut(sampler, 1, sampler->ggxlut_texture_id, sampler->lut_resolution);
|
||||
}
|
||||
static void ibl_sample_charlie_lut(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
sampler->charlielut_texture_id = ibl_create_lut_texture(sampler);
|
||||
ibl_sample_lut(sampler, 2, sampler->charlielut_texture_id, sampler->lut_resolution);
|
||||
}
|
||||
|
||||
static bool ibl_gl_has_extension(const char * extension)
|
||||
{
|
||||
int32_t extension_count;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &extension_count);
|
||||
for(uint32_t i = 0; i < (uint32_t)extension_count; i++) {
|
||||
const GLubyte * curr_extension = glGetStringi(GL_EXTENSIONS, i);
|
||||
if(lv_streq((const char *)curr_extension, extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ibl_count_bits(int value)
|
||||
{
|
||||
int count = 0;
|
||||
while(value > 1) {
|
||||
value >>= 1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file lv_gltf_ibl_sampler.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_IBL_SAMPLER_H
|
||||
#define LV_GLTF_IBL_SAMPLER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include "../../../../misc/lv_types.h"
|
||||
#include "../../opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../lv_gltf_view_internal.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
uint32_t texture_size;
|
||||
float lod_bias;
|
||||
uint32_t lowest_mip_level;
|
||||
uint32_t input_texture_id;
|
||||
uint32_t cubemap_texture_id;
|
||||
uint32_t framebuffer;
|
||||
uint32_t mipmap_count;
|
||||
|
||||
uint32_t lambertian_texture_id;
|
||||
uint32_t lambertian_sample_count;
|
||||
|
||||
uint32_t ggx_sample_count;
|
||||
uint32_t ggx_texture_id;
|
||||
|
||||
uint32_t sheen_texture_id;
|
||||
uint32_t sheen_sample_count;
|
||||
|
||||
uint32_t ggxlut_texture_id;
|
||||
|
||||
uint32_t lut_sample_count;
|
||||
uint32_t lut_resolution;
|
||||
|
||||
uint32_t charlielut_texture_id;
|
||||
|
||||
float scale_value;
|
||||
uint32_t mipmap_levels;
|
||||
|
||||
lv_opengl_shader_manager_t * shader_manager;
|
||||
} lv_gltf_ibl_sampler_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t * data;
|
||||
uint32_t internal_format;
|
||||
uint32_t format;
|
||||
uint32_t type;
|
||||
} lv_gltf_ibl_texture_t;
|
||||
|
||||
typedef struct {
|
||||
float * data;
|
||||
size_t data_len;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} lv_gltf_ibl_image_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_gltf_ibl_generate_env_textures(lv_gltf_view_env_textures_t * env, const char * env_file_path,
|
||||
float env_rotation);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_IBL_SAMPLER_H*/
|
||||
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* @file lv_gltf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_H
|
||||
#define LV_GLTF_H
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_color.h"
|
||||
#include "../gltf_data/lv_gltf_model.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_GLTF_AA_MODE_OFF = 0, /** Anti aliasing off*/
|
||||
LV_GLTF_AA_MODE_ON = 1, /** Anti aliasing on*/
|
||||
LV_GLTF_AA_MODE_DYNAMIC = 2, /** Anti aliasing on only when frame has no movement*/
|
||||
} lv_gltf_aa_mode_t;
|
||||
|
||||
typedef enum {
|
||||
LV_GLTF_BG_MODE_SOLID = 0, /** Solid background. Use `lv_obj_set_style_bg_color` to set the background color*/
|
||||
LV_GLTF_BG_MODE_ENVIRONMENT = 1, /** Environnement background*/
|
||||
} lv_gltf_bg_mode_t;
|
||||
|
||||
#define LV_GLTF_ANIM_SPEED_TENTH 100
|
||||
#define LV_GLTF_ANIM_SPEED_QUARTER 250
|
||||
#define LV_GLTF_ANIM_SPEED_HALF 500
|
||||
#define LV_GLTF_ANIM_SPEED_NORMAL 1000
|
||||
#define LV_GLTF_ANIM_SPEED_2X 2000
|
||||
#define LV_GLTF_ANIM_SPEED_3X 3000
|
||||
#define LV_GLTF_ANIM_SPEED_4X 4000
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a GLTF viewer object
|
||||
* @param parent pointer to the parent object
|
||||
* @return pointer to the created GLTF viewer object
|
||||
*/
|
||||
lv_obj_t * lv_gltf_create(lv_obj_t * parent);
|
||||
|
||||
/**
|
||||
* Load a GLTF model from a file into the viewer
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param path file path to the GLTF model to load
|
||||
* @return pointer to the loaded GLTF model, or NULL on failure
|
||||
*/
|
||||
lv_gltf_model_t * lv_gltf_load_model_from_file(lv_obj_t * obj, const char * path);
|
||||
|
||||
/**
|
||||
* Get the number of models loaded in the GLTF viewer
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return the total number of models in the viewer
|
||||
*/
|
||||
size_t lv_gltf_get_model_count(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get a specific model by its index
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param id index of the model to retrieve (0-based)
|
||||
* @return pointer to the model at the specified index, or NULL if index is invalid
|
||||
*/
|
||||
lv_gltf_model_t * lv_gltf_get_model_by_index(lv_obj_t * obj, size_t id);
|
||||
|
||||
/**
|
||||
* Get the primary model from the GLTF viewer
|
||||
* The primary model is the first model added to the viewer and can be used
|
||||
* for camera selection and other primary operations
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return pointer to the primary model, or NULL if no models are loaded
|
||||
*/
|
||||
lv_gltf_model_t * lv_gltf_get_primary_model(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the yaw (horizontal rotation) of the camera
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param yaw yaw angle in degrees
|
||||
*/
|
||||
void lv_gltf_set_yaw(lv_obj_t * obj, float yaw);
|
||||
|
||||
/**
|
||||
* Get the yaw (horizontal rotation) of the camera
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return yaw angle in degrees
|
||||
*/
|
||||
float lv_gltf_get_yaw(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the pitch (vertical rotation) of the camera
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param pitch pitch angle in degrees
|
||||
*/
|
||||
void lv_gltf_set_pitch(lv_obj_t * obj, float pitch);
|
||||
|
||||
/**
|
||||
* Get the pitch (vertical rotation) of the camera
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return pitch angle in degrees
|
||||
*/
|
||||
float lv_gltf_get_pitch(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the camera distance from the focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value distance value
|
||||
*/
|
||||
void lv_gltf_set_distance(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the camera distance from the focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return distance value
|
||||
*/
|
||||
float lv_gltf_get_distance(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* Viewport Functions
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the field of view
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value vertical FOV in degrees. If zero, the view will be orthographic (non-perspective)
|
||||
*/
|
||||
void lv_gltf_set_fov(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the field of view
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return vertical FOV in degrees
|
||||
*/
|
||||
float lv_gltf_get_fov(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* Focal Point Functions
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the X coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value X coordinate
|
||||
*/
|
||||
void lv_gltf_set_focal_x(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the X coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return X coordinate
|
||||
*/
|
||||
float lv_gltf_get_focal_x(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the Y coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value Y coordinate
|
||||
*/
|
||||
void lv_gltf_set_focal_y(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the Y coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return Y coordinate
|
||||
*/
|
||||
float lv_gltf_get_focal_y(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the Z coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value Z coordinate
|
||||
*/
|
||||
void lv_gltf_set_focal_z(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the Z coordinate of the camera focal point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return Z coordinate
|
||||
*/
|
||||
float lv_gltf_get_focal_z(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the focal coordinates to the center point of the model object
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param model a model attached to this viewer or NULL for the first model
|
||||
*/
|
||||
void lv_gltf_recenter(lv_obj_t * obj, lv_gltf_model_t * model);
|
||||
|
||||
/**********************
|
||||
* Scene Control Functions
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the active camera index
|
||||
* The camera is selected from the first GLTF model added to the viewer
|
||||
*
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value camera index (0 for default camera, 1+ for scene camera index)
|
||||
* @note Values higher than the scene's camera count will be clamped to the maximum available camera index
|
||||
*/
|
||||
void lv_gltf_set_camera(lv_obj_t * obj, uint32_t value);
|
||||
|
||||
/**
|
||||
* Get the active camera index
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return active camera index
|
||||
*/
|
||||
uint32_t lv_gltf_get_camera(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the number of cameras in the first GLTF model added to the viewer
|
||||
* This count represents the valid range for the camera index parameter
|
||||
* used with lv_gltf_set_camera()
|
||||
*
|
||||
* To get the camera count of other models, call
|
||||
* lv_gltf_model_get_camera_count(model) directly with the specific model
|
||||
*
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return number of available cameras
|
||||
*/
|
||||
uint32_t lv_gltf_get_camera_count(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the animation speed ratio
|
||||
*
|
||||
* The actual ratio is the value parameter / LV_GLTF_ANIM_SPEED_NORMAL
|
||||
* Values greater than LV_GLTF_ANIM_SPEED_NORMAL will speed-up the animation
|
||||
* Values less than LV_GLTF_ANIM_SPEED_NORMAL will slow down the animation
|
||||
*
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value speed-up ratio of the animation
|
||||
*/
|
||||
void lv_gltf_set_animation_speed(lv_obj_t * obj, uint32_t value);
|
||||
|
||||
/**
|
||||
* Get the animation speed ratio
|
||||
*
|
||||
* The actual ratio is the return value / LV_GLTF_ANIM_SPEED_NORMAL
|
||||
*
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
*/
|
||||
uint32_t lv_gltf_get_animation_speed(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* Visual Settings Functions
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the background mode
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value background mode
|
||||
*/
|
||||
void lv_gltf_set_background_mode(lv_obj_t * obj, lv_gltf_bg_mode_t value);
|
||||
|
||||
/**
|
||||
* Get the background mode
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return background mode
|
||||
*/
|
||||
lv_gltf_bg_mode_t lv_gltf_get_background_mode(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the background blur amount
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value blur amount between 0 and 100
|
||||
*/
|
||||
void lv_gltf_set_background_blur(lv_obj_t * obj, uint32_t value);
|
||||
|
||||
/**
|
||||
* Get the background blur amount
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return blur amount between 0 and 100
|
||||
*/
|
||||
uint32_t lv_gltf_get_background_blur(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the environmental brightness/power
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value brightness multiplier
|
||||
*/
|
||||
void lv_gltf_set_env_brightness(lv_obj_t * obj, uint32_t value);
|
||||
|
||||
/**
|
||||
* Get the environmental brightness/power
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return brightness multiplier
|
||||
*/
|
||||
uint32_t lv_gltf_get_env_brightness(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the image exposure level
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value exposure level (1.0 is default)
|
||||
*/
|
||||
void lv_gltf_set_image_exposure(lv_obj_t * obj, float value);
|
||||
|
||||
/**
|
||||
* Get the image exposure level
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return exposure level
|
||||
*/
|
||||
float lv_gltf_get_image_exposure(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* Rendering Functions
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the anti-aliasing mode
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param value anti-aliasing mode
|
||||
*/
|
||||
void lv_gltf_set_antialiasing_mode(lv_obj_t * obj, lv_gltf_aa_mode_t value);
|
||||
|
||||
/**
|
||||
* Get the anti-aliasing mode
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return anti-aliasing mode
|
||||
*/
|
||||
lv_gltf_aa_mode_t lv_gltf_get_antialiasing_mode(const lv_obj_t * obj);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#endif /*LV_GLTF_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @file lv_gltf_view_internal.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_VIEW_INTERNAL_H
|
||||
#define LV_GLTF_VIEW_INTERNAL_H
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "lv_gltf.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../../../widgets/3dtexture/lv_3dtexture_private.h"
|
||||
#include "../gltf_data/lv_gltf_data_internal.h"
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif/* __cplusplus*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t texture;
|
||||
uint32_t renderbuffer;
|
||||
unsigned framebuffer;
|
||||
} lv_gltf_renwin_state_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gltf_renwin_state_t render_state;
|
||||
lv_gltf_renwin_state_t opaque_render_state;
|
||||
|
||||
uint64_t opaque_frame_buffer_width;
|
||||
uint64_t opaque_frame_buffer_height;
|
||||
uint32_t material_variant;
|
||||
bool render_state_ready;
|
||||
bool render_opaque_buffer;
|
||||
} lv_gltf_view_state_t;
|
||||
|
||||
typedef struct {
|
||||
float pitch;
|
||||
float yaw;
|
||||
float distance;
|
||||
float fov; // The vertical FOV, in degrees. If this is zero, the view will be orthographic (non-perspective)
|
||||
int32_t render_width; // If anti-aliasing is not applied this frame, these are the same as width/height, if antialiasing
|
||||
int32_t render_height; // is enabled, these are width/height * antialias upscale power (currently 2.0)
|
||||
float focal_x;
|
||||
float focal_y;
|
||||
float focal_z;
|
||||
bool frame_was_antialiased;
|
||||
int32_t animation_speed_ratio;
|
||||
lv_gltf_aa_mode_t aa_mode;
|
||||
lv_gltf_bg_mode_t bg_mode;
|
||||
float blur_bg; /** How much to blur the environment background, between 0.0 and 1.0 */
|
||||
float env_pow; /** Environmental brightness, 1.8 by default */
|
||||
float exposure; /** Image exposure level, 1.0 default */
|
||||
} lv_gltf_view_desc_t;
|
||||
|
||||
typedef struct {
|
||||
GLboolean blend_enabled;
|
||||
GLint blend_src;
|
||||
GLint blend_dst;
|
||||
GLint blend_equation;
|
||||
GLfloat clear_depth;
|
||||
GLfloat clear_color[4];
|
||||
} lv_opengl_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t diffuse;
|
||||
uint32_t specular;
|
||||
uint32_t sheen;
|
||||
uint32_t ggxLut;
|
||||
uint32_t charlie_lut;
|
||||
uint32_t mip_count;
|
||||
float ibl_intensity_scale;
|
||||
float angle;
|
||||
} lv_gltf_view_env_textures_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
#include <fastgltf/types.hpp>
|
||||
#include <map>
|
||||
|
||||
struct _lv_gltf_t {
|
||||
lv_3dtexture_t texture;
|
||||
lv_array_t models;
|
||||
lv_gltf_view_state_t state;
|
||||
lv_gltf_view_desc_t desc;
|
||||
lv_gltf_view_desc_t last_desc;
|
||||
lv_opengl_shader_manager_t * shader_manager;
|
||||
lv_gltf_view_env_textures_t env_textures;
|
||||
fastgltf::math::fmat4x4 view_matrix;
|
||||
fastgltf::math::fmat4x4 projection_matrix;
|
||||
fastgltf::math::fmat4x4 view_projection_matrix;
|
||||
fastgltf::math::fvec3 camera_pos;
|
||||
|
||||
std::map<int32_t, std::map<fastgltf::Node *, fastgltf::math::fmat4x4>> ibm_by_skin_then_node;
|
||||
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
GLuint lv_gltf_view_render(lv_gltf_t * viewer);
|
||||
lv_result_t lv_gltf_view_shader_injest_discover_defines(lv_array_t * result, lv_gltf_model_t * data,
|
||||
fastgltf::Node * node,
|
||||
fastgltf::Primitive * prim);
|
||||
|
||||
lv_gltf_shaderset_t lv_gltf_view_shader_compile_program(lv_gltf_t * view, const lv_opengl_shader_define_t * defines,
|
||||
size_t n);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif/* __cplusplus*/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#endif /*LV_GLTF_VIEW_INTERNAL_H*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* @file lv_gltf_view_shader.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_gltf_view_internal.h"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "fastgltf/types.hpp"
|
||||
#include "../gltf_data/lv_gltf_data_internal.hpp"
|
||||
#include "../gltf_data/lv_gltf_data_internal.h"
|
||||
#include "../opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../stdlib/lv_sprintf.h"
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static lv_result_t add_define(lv_array_t * array, const char * defsymbol, const char * value, bool value_allocated);
|
||||
static lv_result_t add_define_if_primitive_attribute_exists(lv_array_t * array, const fastgltf::Asset & asset,
|
||||
const fastgltf::Primitive * primitive, const char * attribute,
|
||||
const char * define);
|
||||
|
||||
static lv_result_t add_texture_defines_impl(lv_array_t * array, const fastgltf::TextureInfo & material_prop,
|
||||
const char * define,
|
||||
const char * uv_define);
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::TextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define);
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::NormalTextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define);
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::OcclusionTextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_result_t lv_gltf_view_shader_injest_discover_defines(lv_array_t * result, lv_gltf_model_t * data,
|
||||
fastgltf::Node * node,
|
||||
fastgltf::Primitive * prim)
|
||||
{
|
||||
const auto & asset = data->asset;
|
||||
|
||||
if(add_define(result, "_OPAQUE", "0", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "_MASK", "1", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "_BLEND", "2", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
LV_ASSERT_MSG(prim->findAttribute("POSITION") != prim->attributes.end(),
|
||||
"A mesh primitive is required to hold the POSITION attribute");
|
||||
LV_ASSERT_MSG(prim->indicesAccessor.has_value(),
|
||||
"We specify fastgltf::Options::GenerateMeshIndices, so we should always have indices");
|
||||
|
||||
if(!prim->materialIndex.has_value()) {
|
||||
if(add_define(result, "ALPHAMODE", "_OPAQUE", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const auto & material = asset.materials[prim->materialIndex.value()];
|
||||
if(add_define(result, "TONEMAP_KHR_PBR_NEUTRAL", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.unlit) {
|
||||
if(add_define(result, "MATERIAL_UNLIT", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "LINEAR_OUTPUT", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(add_define(result, "MATERIAL_METALLICROUGHNESS", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "LINEAR_OUTPUT", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
const size_t light_count = data->node_by_light_index.size();
|
||||
if(add_define(result, "USE_IBL", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(light_count > 10) {
|
||||
LV_LOG_ERROR("Too many scene lights, max is 10");
|
||||
}
|
||||
else if(light_count > 0) {
|
||||
if(add_define(result, "USE_PUNCTUAL", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
char * count = (char *) lv_zalloc(5);
|
||||
lv_snprintf(count, 5, "%zu", light_count);
|
||||
if(add_define(result, "LIGHT_COUNT", count, true) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(add_define(result, "LIGHT_COUNT", "0", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// only set cutoff value for mask material
|
||||
if(material.alphaMode == fastgltf::AlphaMode::Mask) {
|
||||
if(add_define(result, "ALPHAMODE", "_MASK", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
else if(material.alphaMode == fastgltf::AlphaMode::Opaque) {
|
||||
if(add_define(result, "ALPHAMODE", "_OPAQUE", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(add_define(result, "ALPHAMODE", "_BLEND", false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
if(add_texture_defines(result, material.pbrData.baseColorTexture, "HAS_BASE_COLOR_MAP",
|
||||
"HAS_BASECOLOR_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.pbrData.metallicRoughnessTexture, "HAS_METALLIC_ROUGHNESS_MAP",
|
||||
"HAS_METALLICROUGHNESS_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.occlusionTexture, "HAS_OCCLUSION_MAP", "HAS_OCCLUSION_UV_TRANSFORM") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.normalTexture, "HAS_NORMAL_MAP", "HAS_NORMAL_UV_TRANSFORM") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.emissiveTexture, "HAS_EMISSIVE_MAP", "HAS_EMISSIVE_UV_TRANSFORM") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
if(add_define(result, "MATERIAL_EMISSIVE_STRENGTH", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.sheen)
|
||||
if(add_define(result, "MATERIAL_SHEEN", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.specular)
|
||||
if(add_define(result, "MATERIAL_SPECULAR", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.specularGlossiness) {
|
||||
if(add_define(result, "MATERIAL_SPECULARGLOSSINESS", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.specularGlossiness->diffuseTexture, "HAS_DIFFUSE_MAP",
|
||||
"HAS_DIFFUSE_UV_TRANSFORM")) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.specularGlossiness->specularGlossinessTexture,
|
||||
"HAS_SPECULARGLOSSINESS_MAP", "HAS_SPECULARGLOSSINESS_UV_TRANSFORM")) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
if(material.transmission) {
|
||||
if(add_define(result, "MATERIAL_TRANSMISSION", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "MATERIAL_DISPERSION", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define(result, "MATERIAL_VOLUME", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.transmission->transmissionTexture.has_value())
|
||||
if(add_define(result, "HAS_TRANSMISSION_MAP", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.volume) {
|
||||
add_texture_defines(result, material.volume->thicknessTexture, "HAS_THICKNESS_MAP",
|
||||
"HAS_THICKNESS_UV_TRANSFORM");
|
||||
}
|
||||
}
|
||||
if(material.clearcoat) {
|
||||
if(add_define(result, "MATERIAL_CLEARCOAT", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.clearcoat->clearcoatTexture, "HAS_CLEARCOAT_MAP",
|
||||
"HAS_CLEARCOAT_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.clearcoat->clearcoatRoughnessTexture,
|
||||
"HAS_CLEARCOAT_ROUGHNESS_MAP",
|
||||
"HAS_CLEARCOATROUGHNESS_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.clearcoat->clearcoatNormalTexture, "HAS_CLEARCOAT_NORMAL_MAP",
|
||||
"HAS_CLEARCOATNORMAL_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
if(material.diffuseTransmission) {
|
||||
if(add_define(result, "MATERIAL_DIFFUSE_TRANSMISSION", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(material.diffuseTransmission->diffuseTransmissionTexture.has_value()) {
|
||||
if(add_define(result, "HAS_DIFFUSE_TRANSMISSION_MAP", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
if(material.diffuseTransmission->diffuseTransmissionColorTexture.has_value()) {
|
||||
if(add_define(result, "HAS_DIFFUSE_TRANSMISSION_COLOR_MAP", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "NORMAL", "HAS_NORMAL_VEC3") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "TANGENT", "HAS_TANGENT_VEC4") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "TEXCOORD_0", "HAS_TEXCOORD_0_VEC2") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "TEXCOORD_1", "HAS_TEXCOORD_1_VEC2") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "JOINTS_0",
|
||||
"HAS_JOINTS_0_VEC4") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "JOINTS_1",
|
||||
"HAS_JOINTS_1_VEC4") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "WEIGHTS_0", "HAS_WEIGHTS_0_VEC4") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_define_if_primitive_attribute_exists(result, asset, prim, "WEIGHTS_1", "HAS_WEIGHTS_1_VEC4") ==
|
||||
LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
const auto * joints0it = prim->findAttribute("JOINTS_0");
|
||||
const auto * weights0it = prim->findAttribute("WEIGHTS_0");
|
||||
if((node->skinIndex.has_value()) && (joints0it != prim->attributes.end()) && (weights0it != prim->attributes.end())) {
|
||||
if(add_define(result, "USE_SKINNING", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile and load shaders.
|
||||
*
|
||||
* This function compiles and loads the shaders from the specified shader cache, preparing them
|
||||
* for use in rendering operations. It returns a structure containing the shader set information.
|
||||
*
|
||||
* @param shaders Pointer to the lv_opengl_shader_cache_t structure containing the shader cache.
|
||||
* @return A gl_renwin_shaderset_t structure representing the compiled and loaded shaders.
|
||||
*/
|
||||
|
||||
lv_gltf_shaderset_t lv_gltf_view_shader_compile_program(lv_gltf_t * view, const lv_opengl_shader_define_t * defines,
|
||||
size_t n)
|
||||
{
|
||||
uint32_t frag_shader_hash = lv_opengl_shader_manager_select_shader(view->shader_manager, "__MAIN__.frag",
|
||||
defines, n);
|
||||
|
||||
uint32_t vert_shader_hash = lv_opengl_shader_manager_select_shader(view->shader_manager, "__MAIN__.vert",
|
||||
defines, n);
|
||||
lv_opengl_shader_program_t * program =
|
||||
lv_opengl_shader_manager_get_program(view->shader_manager, frag_shader_hash, vert_shader_hash);
|
||||
|
||||
LV_ASSERT_NULL(program);
|
||||
|
||||
GLuint program_id = lv_opengl_shader_program_get_id(program);
|
||||
|
||||
GL_CALL(glUseProgram(program_id));
|
||||
lv_gltf_shaderset_t shader_prog;
|
||||
shader_prog.program = program_id;
|
||||
|
||||
return shader_prog;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_result_t add_define(lv_array_t * array, const char * name, const char * value, bool value_allocated)
|
||||
{
|
||||
const size_t n = lv_array_size(array);
|
||||
for(size_t i = 0; i < n; ++i) {
|
||||
lv_opengl_shader_define_t * define = (lv_opengl_shader_define_t *)lv_array_at(array, i);
|
||||
if(lv_streq(define->name, name)) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
lv_opengl_shader_define_t entry = { name, value, value_allocated };
|
||||
return lv_array_push_back(array, &entry);
|
||||
}
|
||||
|
||||
static lv_result_t add_define_if_primitive_attribute_exists(lv_array_t * array, const fastgltf::Asset & asset,
|
||||
const fastgltf::Primitive * primitive, const char * attribute,
|
||||
const char * define)
|
||||
{
|
||||
const auto & it = primitive->findAttribute(attribute);
|
||||
if(it == primitive->attributes.end() || !asset.accessors[it->accessorIndex].bufferViewIndex.has_value()) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
return add_define(array, define, NULL, false);
|
||||
}
|
||||
|
||||
static lv_result_t add_texture_defines_impl(lv_array_t * array, const fastgltf::TextureInfo & material_prop,
|
||||
const char * define,
|
||||
const char * uv_define)
|
||||
{
|
||||
if(add_define(array, define, NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!material_prop.transform) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
return add_define(array, uv_define, NULL, false);
|
||||
}
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::TextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define)
|
||||
{
|
||||
if(!material_prop.has_value()) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
return add_texture_defines_impl(array, material_prop.value(), define, uv_define);
|
||||
}
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::NormalTextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define)
|
||||
{
|
||||
if(!material_prop.has_value()) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
return add_texture_defines_impl(array, material_prop.value(), define, uv_define);
|
||||
}
|
||||
|
||||
static lv_result_t add_texture_defines(lv_array_t * array,
|
||||
const fastgltf::Optional<fastgltf::OcclusionTextureInfo> & material_prop,
|
||||
const char * define, const char * uv_define)
|
||||
{
|
||||
if(!material_prop.has_value()) {
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
return add_texture_defines_impl(array, material_prop.value(), define, uv_define);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file lv_gltf_math.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_math.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/** Creates a right-handed view matrix */
|
||||
fastgltf::math::fmat4x4 lv_gltf_math_look_at_rh(const fastgltf::math::fvec3 & eye, const fastgltf::math::fvec3 & center,
|
||||
const fastgltf::math::fvec3 & up) noexcept
|
||||
{
|
||||
auto dir = normalize(center - eye);
|
||||
auto lft = normalize(cross(dir, up));
|
||||
auto rup = cross(lft, dir);
|
||||
|
||||
fastgltf::math::fmat4x4 ret(1.f);
|
||||
ret.col(0) = { lft.x(), rup.x(), -dir.x(), 0.f };
|
||||
ret.col(1) = { lft.y(), rup.y(), -dir.y(), 0.f };
|
||||
ret.col(2) = { lft.z(), rup.z(), -dir.z(), 0.f };
|
||||
ret.col(3) = { -dot(lft, eye), -dot(rup, eye), dot(dir, eye), 1.f };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a right-handed perspective matrix, with the near and far clips at -1 and +1, respectively.
|
||||
* @param fov The FOV in radians
|
||||
*/
|
||||
[[nodiscard]] fastgltf::math::fmat4x4 lv_gltf_math_perspective_rh(float fov, float ratio, float z_near,
|
||||
float z_far) noexcept
|
||||
{
|
||||
fastgltf::math::fmat4x4 ret(0.f);
|
||||
auto tanHalfFov = std::tan(fov / 2.f);
|
||||
ret.col(0).x() = 1.f / (ratio * tanHalfFov);
|
||||
ret.col(1).y() = 1.f / tanHalfFov;
|
||||
ret.col(2).z() = -(z_far + z_near) / (z_far - z_near);
|
||||
ret.col(2).w() = -1.f;
|
||||
ret.col(3).z() = -(2.f * z_far * z_near) / (z_far - z_near);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user