Init
This commit is contained in:
189
inc/lvgl/src/libs/gltf/fastgltf/lv_fastgltf.hpp
Normal file
189
inc/lvgl/src/libs/gltf/fastgltf/lv_fastgltf.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file lv_fastgltf.hpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
#include <fastgltf/util.hpp>
|
||||
#include <fastgltf/types.hpp>
|
||||
#include <fastgltf/tools.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "../gltf_data/lv_gltf_data_internal.hpp"
|
||||
|
||||
namespace fastgltf
|
||||
{
|
||||
|
||||
/**
|
||||
* Computes the transform matrix for a given node a different way with less total operations
|
||||
*/
|
||||
FASTGLTF_EXPORT inline auto getFastLocalTransformMatrix(const Node & node)
|
||||
{
|
||||
return visit_exhaustive(visitor {
|
||||
[&](const math::fmat4x4 & matrix)
|
||||
{
|
||||
return matrix;
|
||||
},
|
||||
[&](const TRS & trs)
|
||||
{
|
||||
math::fmat4x4 matrix = math::fmat4x4();
|
||||
float sx = trs.scale[0], sy = trs.scale[1], sz = trs.scale[2];
|
||||
float qx = trs.rotation[0], qy = trs.rotation[1], qz = trs.rotation[2], qw = trs.rotation[3];
|
||||
float x2 = qx + qx, y2 = qy + qy, z2 = qz + qz;
|
||||
float xx = qx * x2, xy = qx * y2, xz = qx * z2;
|
||||
float yy = qy * y2, yz = qy * z2, zz = qz * z2;
|
||||
float wx = qw * x2, wy = qw * y2, wz = qw * z2;
|
||||
matrix[0][0] = (1 - (yy + zz)) * sx;
|
||||
matrix[0][1] = (xy + wz) * sx;
|
||||
matrix[0][2] = (xz - wy) * sx;
|
||||
matrix[1][0] = (xy - wz) * sy;
|
||||
matrix[1][1] = (1 - (xx + zz)) * sy;
|
||||
matrix[1][2] = (yz + wx) * sy;
|
||||
matrix[2][0] = (xz + wy) * sz;
|
||||
matrix[2][1] = (yz - wx) * sz;
|
||||
matrix[2][2] = (1 - (xx + yy)) * sz;
|
||||
matrix[3][0] = trs.translation[0];
|
||||
matrix[3][1] = trs.translation[1];
|
||||
matrix[3][2] = trs.translation[2];
|
||||
matrix[0][3] = 0.f;
|
||||
matrix[1][3] = 0.f;
|
||||
matrix[2][3] = 0.f;
|
||||
matrix[3][3] = 1.f;
|
||||
return matrix;
|
||||
}
|
||||
}, node.transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to remove the scale component of a 4x4 matrix transform. Will silently fail if
|
||||
* any of the component scales is 0 or near zero (which they should never be).
|
||||
*/
|
||||
FASTGLTF_EXPORT inline void removeScale(fastgltf::math::fmat4x4 & matrix)
|
||||
{
|
||||
auto scale = math::fvec3(length(matrix.col(0)), length(matrix.col(1)), length(matrix.col(2)));
|
||||
if((fabs(scale.x()) > 0.00001f) && (fabs(scale.y()) > 0.00001f) && (fabs(scale.z()) > 0.00001f)) {
|
||||
matrix.col(0) /= scale.x();
|
||||
matrix.col(1) /= scale.y();
|
||||
matrix.col(2) /= scale.z();
|
||||
}
|
||||
}
|
||||
|
||||
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 = getFastLocalTransformMatrix(node);
|
||||
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 Callback>
|
||||
inline void custom_iterate_scene_nodes(lv_gltf_model_t * model, std::size_t sceneIndex, math::fmat4x4 * initial,
|
||||
Callback callback)
|
||||
{
|
||||
auto & scene = model->asset.scenes[sceneIndex];
|
||||
|
||||
auto invoke_cb = [&](std::size_t node_index, math::fmat4x4 & parent_world_matrix,
|
||||
auto & self) -> void {
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *)lv_array_at(&model->nodes, node_index);
|
||||
fastgltf::Node & fastgltf_node = *node->fastgltf_node;
|
||||
LV_ASSERT(node->fastgltf_node == &fastgltf_node);
|
||||
|
||||
auto local_matrix = getFastLocalTransformMatrix(fastgltf_node);
|
||||
std::invoke(callback, node, parent_world_matrix, local_matrix);
|
||||
|
||||
uint32_t num_children = fastgltf_node.children.size();
|
||||
if(num_children == 0) {
|
||||
return;
|
||||
}
|
||||
math::fmat4x4 new_parent_world_matrix = parent_world_matrix * local_matrix;
|
||||
if(num_children == 1)
|
||||
{
|
||||
self(fastgltf_node.children[0], new_parent_world_matrix, self);
|
||||
return;
|
||||
}
|
||||
math::fmat4x4 parent_world_matrix_tmp_copy = math::fmat4x4(new_parent_world_matrix);
|
||||
for(auto & child : fastgltf_node.children)
|
||||
{
|
||||
self(child, parent_world_matrix_tmp_copy, self);
|
||||
}
|
||||
};
|
||||
|
||||
for(size_t i = 0 ; i < scene.nodeIndices.size(); ++i) {
|
||||
invoke_cb(scene.nodeIndices[i], *initial, invoke_cb);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
289
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data.cpp
Normal file
289
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @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_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->compiled_shaders, 1, sizeof(lv_gltf_compiled_shader_t));
|
||||
return data;
|
||||
}
|
||||
|
||||
void lv_gltf_data_delete(lv_gltf_model_t * data)
|
||||
{
|
||||
LV_ASSERT_NULL(data);
|
||||
lv_timer_delete(data->animation_update_timer);
|
||||
data->animation_update_timer = NULL;
|
||||
|
||||
lv_gltf_data_delete_textures(data);
|
||||
uint32_t node_count = lv_array_size(&data->nodes);
|
||||
for(uint32_t i = 0; i < node_count; ++i) {
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *) lv_array_at(&data->nodes, i);
|
||||
lv_gltf_model_node_deinit(node);
|
||||
}
|
||||
lv_array_deinit(&data->nodes);
|
||||
lv_array_deinit(&data->compiled_shaders);
|
||||
|
||||
/* Explicitly call destructors for C++ objects initialized with placement new */
|
||||
data->textures.~vector();
|
||||
data->meshes.~vector();
|
||||
data->node_by_light_index.~vector();
|
||||
data->local_mesh_to_center_points_by_primitive.~map();
|
||||
data->skin_tex.~vector();
|
||||
data->validated_skins.~vector();
|
||||
data->blended_nodes_by_material_index.~map();
|
||||
data->opaque_nodes_by_material_index.~map();
|
||||
data->node_transform_cache.~map();
|
||||
data->channel_set_cache.~map();
|
||||
data->asset.~Asset();
|
||||
|
||||
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(const 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*/
|
||||
278
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_animations.cpp
Normal file
278
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_animations.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* @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];
|
||||
bool need_rot_recalc = false;
|
||||
int32_t translation_comp_index = -1;
|
||||
int32_t rotation_comp_index = -1;
|
||||
int32_t scale_comp_index = -1;
|
||||
|
||||
for(const auto & c : (*_channel_set)) {
|
||||
switch(anim.channels[c].path) {
|
||||
case fastgltf::AnimationPath::Translation:
|
||||
translation_comp_index = c;
|
||||
break;
|
||||
case fastgltf::AnimationPath::Rotation:
|
||||
rotation_comp_index = c;
|
||||
need_rot_recalc = true;
|
||||
break;
|
||||
case fastgltf::AnimationPath::Scale:
|
||||
scale_comp_index = c;
|
||||
need_rot_recalc = true;
|
||||
break;
|
||||
case fastgltf::AnimationPath::Weights:
|
||||
LV_LOG_WARN("Unhandled weights animation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_rot_recalc) {
|
||||
fastgltf::math::fvec3 new_scale;
|
||||
fastgltf::math::fquat new_quat;
|
||||
if(!((scale_comp_index > -1) && (rotation_comp_index > -1))) {
|
||||
fastgltf::math::fvec3 unused;
|
||||
fastgltf::math::decomposeTransformMatrix(matrix, new_scale, new_quat, unused);
|
||||
}
|
||||
if(scale_comp_index > -1) new_scale = animation_get_vec3_at_timestamp(gltf_data, &anim.samplers[scale_comp_index],
|
||||
timestamp);
|
||||
if(rotation_comp_index > -1) new_quat = animation_get_quat_at_timestamp(gltf_data, &anim.samplers[rotation_comp_index],
|
||||
timestamp);
|
||||
|
||||
float sx = new_scale[0], sy = new_scale[1], sz = new_scale[2];
|
||||
float qx = new_quat[0], qy = new_quat[1], qz = new_quat[2], qw = new_quat[3];
|
||||
|
||||
float x2 = qx + qx, y2 = qy + qy, z2 = qz + qz;
|
||||
float xx = qx * x2, xy = qx * y2, xz = qx * z2;
|
||||
float yy = qy * y2, yz = qy * z2, zz = qz * z2;
|
||||
float wx = qw * x2, wy = qw * y2, wz = qw * z2;
|
||||
|
||||
matrix[0][0] = (1 - (yy + zz)) * sx;
|
||||
matrix[0][1] = (xy + wz) * sx;
|
||||
matrix[0][2] = (xz - wy) * sx;
|
||||
|
||||
matrix[1][0] = (xy - wz) * sy;
|
||||
matrix[1][1] = (1 - (xx + zz)) * sy;
|
||||
matrix[1][2] = (yz + wx) * sy;
|
||||
|
||||
matrix[2][0] = (xz + wy) * sz;
|
||||
matrix[2][1] = (yz - wx) * sz;
|
||||
matrix[2][2] = (1 - (xx + yy)) * sz;
|
||||
|
||||
/* These entries should not be necessary */
|
||||
//matrix[0][3] = 0.f;
|
||||
//matrix[1][3] = 0.f;
|
||||
//matrix[2][3] = 0.f;
|
||||
}
|
||||
|
||||
if(translation_comp_index > -1) {
|
||||
fastgltf::math::fvec3 new_translation = animation_get_vec3_at_timestamp(gltf_data,
|
||||
&anim.samplers[translation_comp_index], timestamp);
|
||||
matrix[3][0] = new_translation[0];
|
||||
matrix[3][1] = new_translation[1];
|
||||
matrix[3][2] = new_translation[2];
|
||||
}
|
||||
matrix[3][3] = 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* 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*/
|
||||
103
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_cache.cpp
Normal file
103
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_cache.cpp
Normal file
@@ -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*/
|
||||
875
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_injest.cpp
Normal file
875
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_injest.cpp
Normal file
@@ -0,0 +1,875 @@
|
||||
/**
|
||||
* @file lv_gltf_data_injest.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/core.hpp>
|
||||
#include <fastgltf/math.hpp>
|
||||
#include <fastgltf/tools.hpp>
|
||||
#include <fastgltf/types.hpp>
|
||||
#include "../fastgltf/lv_fastgltf.hpp"
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../misc/lv_log.h"
|
||||
#include "../../../misc/lv_math.h"
|
||||
#include "../../../stdlib/lv_sprintf.h"
|
||||
#include "../../../misc/lv_fs.h"
|
||||
|
||||
#include "../stb_image/stb_image.h"
|
||||
#include <webp/decode.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
constexpr auto SUPPORTED_EXTENSIONS =
|
||||
//fastgltf::Extensions::KHR_draco_mesh_compression |
|
||||
//fastgltf::Extensions::EXT_meshopt_compression |
|
||||
fastgltf::Extensions::KHR_mesh_quantization | fastgltf::Extensions::KHR_texture_transform |
|
||||
fastgltf::Extensions::KHR_lights_punctual | fastgltf::Extensions::KHR_materials_anisotropy |
|
||||
fastgltf::Extensions::KHR_materials_clearcoat | fastgltf::Extensions::KHR_materials_dispersion |
|
||||
fastgltf::Extensions::KHR_materials_emissive_strength | fastgltf::Extensions::KHR_materials_ior |
|
||||
fastgltf::Extensions::KHR_materials_iridescence | fastgltf::Extensions::KHR_materials_sheen |
|
||||
fastgltf::Extensions::KHR_materials_specular |
|
||||
fastgltf::Extensions::
|
||||
KHR_materials_pbrSpecularGlossiness
|
||||
| // Depreciated, to enable support make sure to define FASTGLTF_ENABLE_DEPRECATED_EXT
|
||||
fastgltf::Extensions::KHR_materials_transmission |
|
||||
fastgltf::Extensions::KHR_materials_volume | fastgltf::Extensions::KHR_materials_unlit |
|
||||
fastgltf::Extensions::EXT_texture_webp |
|
||||
//fastgltf::Extensions::KHR_materials_diffuse_transmission |
|
||||
fastgltf::Extensions::KHR_materials_variants;
|
||||
|
||||
constexpr auto GLTF_OPTIONS = fastgltf::Options::DontRequireValidAssetMember | fastgltf::Options::AllowDouble |
|
||||
fastgltf::Options::LoadExternalBuffers | fastgltf::Options::LoadExternalImages |
|
||||
fastgltf::Options::GenerateMeshIndices;
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
fastgltf::math::fvec3 position;
|
||||
fastgltf::math::fvec3 normal;
|
||||
fastgltf::math::fvec4 tangent;
|
||||
fastgltf::math::fvec2 uv;
|
||||
fastgltf::math::fvec2 uv2;
|
||||
fastgltf::math::fvec4 joints;
|
||||
fastgltf::math::fvec4 joints2;
|
||||
fastgltf::math::fvec4 weights;
|
||||
fastgltf::math::fvec4 weights2;
|
||||
} vertex_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void set_bounds_info(lv_gltf_model_t * data, fastgltf::math::fvec3 v_min, fastgltf::math::fvec3 v_max,
|
||||
fastgltf::math::fvec3 v_cen, float radius);
|
||||
static lv_gltf_model_t * create_data_from_bytes(const uint8_t * bytes, size_t data_size);
|
||||
|
||||
static lv_gltf_model_t * create_data_from_file(const char * path);
|
||||
|
||||
static void injest_grow_bounds_to_include(lv_gltf_model_t * data, const fastgltf::math::fmat4x4 & matrix,
|
||||
const fastgltf::Mesh & mesh);
|
||||
|
||||
static void injest_set_initial_bounds(lv_gltf_model_t * data, const fastgltf::math::fmat4x4 & matrix,
|
||||
const fastgltf::Mesh & mesh);
|
||||
|
||||
static bool injest_image(lv_opengl_shader_manager_t * shader_manager, lv_gltf_model_t * data, fastgltf::Image & image,
|
||||
uint32_t index);
|
||||
|
||||
static bool injest_image_from_buffer_view(lv_gltf_model_t * data, fastgltf::sources::BufferView & view,
|
||||
GLuint texture_id);
|
||||
static void injest_light(lv_gltf_model_t * data, size_t light_index, fastgltf::Light & light, size_t scene_index);
|
||||
static bool injest_mesh(lv_gltf_model_t * data, fastgltf::Mesh & mesh);
|
||||
|
||||
static void make_small_magenta_texture(uint32_t new_magenta_tex);
|
||||
|
||||
template <typename T, typename Func>
|
||||
static size_t injest_vec_attribute(uint8_t vec_size, int32_t current_attrib_index, lv_gltf_model_t * data,
|
||||
const fastgltf::Primitive * prim, const char * attrib_id, GLuint primitive_vertex_buffer,
|
||||
size_t offset, Func &&functor);
|
||||
|
||||
static int32_t injest_get_any_image_index(fastgltf::Optional<fastgltf::Texture> tex);
|
||||
static bool injest_check_any_image_index_valid(fastgltf::Optional<fastgltf::Texture> tex);
|
||||
|
||||
static inline GLsizei get_level_count(int32_t width, int32_t height)
|
||||
{
|
||||
return static_cast<GLsizei>(1 + floor(log2(width > height ? width : height)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate immutable texture storage with fallback for GLES2
|
||||
*
|
||||
* glTexStorage2D (GL_EXT_texture_storage) may not be available on all GLES2 drivers.
|
||||
* This function falls back to glTexImage2D when the extension is not available.
|
||||
*/
|
||||
static inline void tex_storage_2d_compat(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
#ifdef glTexStorage2D
|
||||
if(glad_glTexStorage2DEXT) {
|
||||
glTexStorage2D(target, levels, internalformat, width, height);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Fallback: use glTexImage2D for each mipmap level */
|
||||
GLenum format = GL_RGBA;
|
||||
if(internalformat == GL_RGB8) {
|
||||
format = GL_RGB;
|
||||
}
|
||||
for(GLsizei level = 0; level < levels; level++) {
|
||||
glTexImage2D(target, level, internalformat, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
|
||||
width = (width > 1) ? (width / 2) : 1;
|
||||
height = (height > 1) ? (height / 2) : 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_mesh_texture_impl(lv_gltf_model_t * data, const fastgltf::TextureInfo & material_prop,
|
||||
GLuint * primitive_tex_prop,
|
||||
GLint * primitive_tex_uv_id);
|
||||
static void load_mesh_texture(lv_gltf_model_t * data, const fastgltf::Optional<fastgltf::TextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id);
|
||||
|
||||
static void load_mesh_texture(lv_gltf_model_t * data,
|
||||
const fastgltf::Optional<fastgltf::NormalTextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id);
|
||||
|
||||
static void load_mesh_texture(lv_gltf_model_t * data,
|
||||
const fastgltf::Optional<fastgltf::OcclusionTextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_gltf_model_t * lv_gltf_data_load_internal(const void * data_source, size_t data_size,
|
||||
lv_opengl_shader_manager_t * shaders)
|
||||
{
|
||||
lv_gltf_model_t * model = NULL;
|
||||
if(data_size > 0) {
|
||||
model = create_data_from_bytes((const uint8_t *)data_source, data_size);
|
||||
}
|
||||
else {
|
||||
model = create_data_from_file((const char *)data_source);
|
||||
}
|
||||
|
||||
LV_ASSERT_MSG(model, "Failed to create gltf data");
|
||||
if(!model) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse the visible node structure to get a world transform matrix for each mesh component
|
||||
// instance per node, and apply that matrix to the min/max of the untransformed mesh, then
|
||||
// grow a bounding volume to include those transformed points
|
||||
|
||||
int32_t scene_index = 0;
|
||||
bool first_visible_mesh = true;
|
||||
fastgltf::iterateSceneNodes(
|
||||
model->asset, scene_index, fastgltf::math::fmat4x4(), [&](fastgltf::Node & node, fastgltf::math::fmat4x4 matrix) {
|
||||
if(!node.meshIndex.has_value()) {
|
||||
return;
|
||||
}
|
||||
if(first_visible_mesh) {
|
||||
injest_set_initial_bounds(model, matrix, model->asset.meshes[node.meshIndex.value()]);
|
||||
}
|
||||
else {
|
||||
injest_grow_bounds_to_include(model, matrix, model->asset.meshes[node.meshIndex.value()]);
|
||||
}
|
||||
first_visible_mesh = false;
|
||||
});
|
||||
|
||||
/* Reserve enough space for model nodes */
|
||||
lv_array_init(&model->nodes, model->asset.nodes.size(), sizeof(lv_gltf_model_node_t));
|
||||
/*Virtually set size so that lv_array_assign will work*/
|
||||
model->nodes.size = model->asset.nodes.size();
|
||||
|
||||
fastgltf::namegen_iterate_scene_nodes(model->asset, scene_index,
|
||||
[&](fastgltf::Node & node, const std::string & node_path, const std::string & node_num_path,
|
||||
size_t node_index, std::size_t child_index) {
|
||||
LV_UNUSED(child_index);
|
||||
lv_gltf_model_node_t model_node;
|
||||
lv_gltf_model_node_init(model, &model_node, &node, node_path.c_str(), node_num_path.c_str());
|
||||
|
||||
/* Store the nodes in the same order as fastgltf
|
||||
* This is a workaround as we can't assign any type of user data to fastgltf's types*/
|
||||
lv_array_assign(&model->nodes, node_index, & model_node);
|
||||
});
|
||||
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(auto & image : model->asset.images) {
|
||||
injest_image(shaders, model, image, i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
uint16_t lightnum = 0;
|
||||
for(auto & light : model->asset.lights) {
|
||||
injest_light(model, lightnum, light, 0);
|
||||
lightnum += 1;
|
||||
}
|
||||
for(auto & mesh : model->asset.meshes) {
|
||||
injest_mesh(model, mesh);
|
||||
}
|
||||
|
||||
if(model->asset.defaultScene.has_value()) {
|
||||
LV_LOG_INFO("Default scene = #%d", data->asset.defaultScene.value());
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_gltf_model_t * create_data_from_file(const char * path)
|
||||
{
|
||||
lv_fs_file_t file;
|
||||
lv_fs_res_t res = lv_fs_open(&file, path, LV_FS_MODE_RD);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("Failed to open file '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
res = lv_fs_seek(&file, 0, LV_FS_SEEK_END);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("Failed to seek end of file '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
uint32_t file_size;
|
||||
res = lv_fs_tell(&file, &file_size);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("Failed to get file count size '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = lv_fs_seek(&file, 0, LV_FS_SEEK_SET);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("Failed to seek start of file '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t * bytes = (uint8_t *) lv_malloc(file_size);
|
||||
|
||||
uint32_t bytes_read;
|
||||
res = lv_fs_read(&file, bytes, file_size, &bytes_read);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("Failed to seek start of file '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
if(bytes_read != file_size) {
|
||||
LV_LOG_ERROR("Failed to read the entire gltf file '%s': %d", path, res);
|
||||
return NULL;
|
||||
}
|
||||
lv_fs_close(&file);
|
||||
|
||||
lv_gltf_model_t * model = create_data_from_bytes(bytes, file_size);
|
||||
lv_free(bytes);
|
||||
|
||||
model->filename = path;
|
||||
return model;
|
||||
}
|
||||
|
||||
static lv_gltf_model_t * create_data_from_bytes(const uint8_t * bytes, size_t data_size)
|
||||
{
|
||||
fastgltf::Parser parser(SUPPORTED_EXTENSIONS);
|
||||
auto gltf_buffer = fastgltf::GltfDataBuffer::FromBytes(reinterpret_cast<const std::byte *>(bytes), data_size);
|
||||
if(!gltf_buffer) {
|
||||
LV_LOG_ERROR("Failed to create glTF buffer from bytes: %s",
|
||||
std::string(fastgltf::getErrorMessage(gltf_buffer.error())).c_str());
|
||||
return NULL;
|
||||
}
|
||||
auto asset = parser.loadGltf(gltf_buffer.get(), ".", GLTF_OPTIONS);
|
||||
if(!asset) {
|
||||
LV_LOG_ERROR("Failed to decode glTF bytes: %s", std::string(fastgltf::getErrorMessage(asset.error())).c_str());
|
||||
return NULL;
|
||||
}
|
||||
return lv_gltf_data_create_internal("from_bytes", std::move(asset.get()));
|
||||
}
|
||||
|
||||
static void make_small_magenta_texture(uint32_t new_magenta_tex)
|
||||
{
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, new_magenta_tex));
|
||||
unsigned char clearBytes[4] = { 255, 0, 255, 255 }; // RGBA format
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, clearBytes));
|
||||
// Set texture parameters (optional but recommended)
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
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));
|
||||
GL_CALL(glGenerateMipmap(GL_TEXTURE_2D));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
static void load_mesh_texture_impl(lv_gltf_model_t * data, const fastgltf::TextureInfo & material_prop,
|
||||
GLuint * primitive_tex_prop,
|
||||
GLint * primitive_tex_uv_id)
|
||||
{
|
||||
const auto & texture = data->asset.textures[material_prop.textureIndex];
|
||||
if(!injest_check_any_image_index_valid(texture)) {
|
||||
return;
|
||||
}
|
||||
*primitive_tex_prop = data->textures[injest_get_any_image_index(texture)];
|
||||
if(material_prop.transform && material_prop.transform->texCoordIndex.has_value()) {
|
||||
*primitive_tex_uv_id = material_prop.transform->texCoordIndex.value();
|
||||
}
|
||||
else {
|
||||
*primitive_tex_uv_id = material_prop.texCoordIndex;
|
||||
}
|
||||
LV_LOG_TRACE("Prim tex prop: %d Prim tex uv id %d", *primitive_tex_prop, *primitive_tex_uv_id);
|
||||
}
|
||||
|
||||
static void load_mesh_texture(lv_gltf_model_t * data,
|
||||
const fastgltf::Optional<fastgltf::NormalTextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id)
|
||||
{
|
||||
if(!material_prop) {
|
||||
return;
|
||||
}
|
||||
load_mesh_texture_impl(data, material_prop.value(), primitive_tex_prop, primitive_tex_uv_id);
|
||||
}
|
||||
|
||||
static void load_mesh_texture(lv_gltf_model_t * data, const fastgltf::Optional<fastgltf::TextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id)
|
||||
{
|
||||
if(!material_prop) {
|
||||
return;
|
||||
}
|
||||
load_mesh_texture_impl(data, material_prop.value(), primitive_tex_prop, primitive_tex_uv_id);
|
||||
}
|
||||
|
||||
static void load_mesh_texture(lv_gltf_model_t * data,
|
||||
const fastgltf::Optional<fastgltf::OcclusionTextureInfo> & material_prop,
|
||||
GLuint * primitive_tex_prop, GLint * primitive_tex_uv_id)
|
||||
{
|
||||
if(!material_prop) {
|
||||
return;
|
||||
}
|
||||
load_mesh_texture_impl(data, material_prop.value(), primitive_tex_prop, primitive_tex_uv_id);
|
||||
}
|
||||
|
||||
static int32_t injest_get_any_image_index(fastgltf::Optional<fastgltf::Texture> tex)
|
||||
{
|
||||
if(tex->imageIndex.has_value()) {
|
||||
return tex->imageIndex.value();
|
||||
}
|
||||
|
||||
if(tex->webpImageIndex.has_value()) {
|
||||
return tex->webpImageIndex.value();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static bool injest_check_any_image_index_valid(fastgltf::Optional<fastgltf::Texture> tex)
|
||||
{
|
||||
if(tex->imageIndex.has_value())
|
||||
return true;
|
||||
if(tex->webpImageIndex.has_value())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void injest_grow_bounds_to_include(lv_gltf_model_t * data, const fastgltf::math::fmat4x4 & matrix,
|
||||
const fastgltf::Mesh & mesh)
|
||||
{
|
||||
/* Grow the bounds to include the specified mesh. */
|
||||
fastgltf::math::fvec3 v_min{ data->vertex_min[0], data->vertex_min[1], data->vertex_min[2] };
|
||||
|
||||
fastgltf::math::fvec3 v_max{
|
||||
data->vertex_max[0],
|
||||
data->vertex_max[1],
|
||||
data->vertex_max[2],
|
||||
};
|
||||
fastgltf::math::fvec3 v_cen{ data->vertex_cen[0], data->vertex_cen[1], data->vertex_cen[2] };
|
||||
|
||||
float new_bound_radius = data->bound_radius;
|
||||
if(mesh.primitives.size() > 0) {
|
||||
set_bounds_info(data, v_min, v_max, v_cen, new_bound_radius);
|
||||
return;
|
||||
}
|
||||
size_t accessor_index = mesh.primitives[0].findAttribute("POSITION")->accessorIndex;
|
||||
const auto & accessor = data->asset.accessors[accessor_index];
|
||||
|
||||
if(!accessor.bufferViewIndex.has_value() || !(accessor.min.has_value() && accessor.max.has_value())) {
|
||||
set_bounds_info(data, v_min, v_max, v_cen, new_bound_radius);
|
||||
return;
|
||||
}
|
||||
|
||||
fastgltf::math::fvec4 t_min{ (float)(accessor.min.value().get<double>(0)), (float)(accessor.min.value().get<double>(1)),
|
||||
(float)(accessor.min.value().get<double>(2)), 1.f };
|
||||
fastgltf::math::fvec4 t_max{ (float)(accessor.max.value().get<double>(0)), (float)(accessor.max.value().get<double>(1)),
|
||||
(float)(accessor.max.value().get<double>(2)), 1.f };
|
||||
|
||||
t_min = matrix * t_min;
|
||||
t_max = matrix * t_max;
|
||||
v_max[0] = LV_MAX(LV_MAX(v_max[0], t_min.x()), t_max.x());
|
||||
v_max[1] = LV_MAX(LV_MAX(v_max[1], t_min.y()), t_max.y());
|
||||
v_max[2] = LV_MAX(LV_MAX(v_max[2], t_min.z()), t_max.z());
|
||||
v_min[0] = LV_MIN(LV_MIN(v_min[0], t_min.x()), t_max.x());
|
||||
v_min[1] = LV_MIN(LV_MIN(v_min[1], t_min.y()), t_max.y());
|
||||
v_min[2] = LV_MIN(LV_MIN(v_min[2], 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];
|
||||
new_bound_radius = std::sqrt((size_x * size_x) + (size_y * size_y) + (size_z * size_z)) / 2.0f;
|
||||
|
||||
set_bounds_info(data, v_min, v_max, v_cen, new_bound_radius);
|
||||
}
|
||||
static void injest_set_initial_bounds(lv_gltf_model_t * data, const fastgltf::math::fmat4x4 & matrix,
|
||||
const fastgltf::Mesh & mesh)
|
||||
{
|
||||
fastgltf::math::fvec3 v_min, v_max, v_cen;
|
||||
float radius = 0.f;
|
||||
if(mesh.primitives.size() == 0) {
|
||||
set_bounds_info(data, v_min, v_max, v_cen, radius);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t accessor_index = mesh.primitives[0].findAttribute("POSITION")->accessorIndex;
|
||||
const auto & accessor = data->asset.accessors[accessor_index];
|
||||
|
||||
if(!accessor.bufferViewIndex.has_value() || !(accessor.min.has_value() && accessor.max.has_value())) {
|
||||
set_bounds_info(data, v_min, v_max, v_cen, radius);
|
||||
return;
|
||||
}
|
||||
|
||||
fastgltf::math::fvec4 t_min{ (float)(accessor.min.value().get<double>(0)), (float)(accessor.min.value().get<double>(1)),
|
||||
(float)(accessor.min.value().get<double>(2)), 1.f };
|
||||
|
||||
fastgltf::math::fvec4 t_max{ (float)(accessor.max.value().get<double>(0)), (float)(accessor.max.value().get<double>(1)),
|
||||
(float)(accessor.max.value().get<double>(2)), 1.f };
|
||||
|
||||
t_min = matrix * t_min;
|
||||
t_max = matrix * t_max;
|
||||
|
||||
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;
|
||||
const float size_x = v_max[0] - v_min[0];
|
||||
const float size_y = v_max[1] - v_min[1];
|
||||
const 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;
|
||||
|
||||
set_bounds_info(data, v_min, v_max, v_cen, radius);
|
||||
}
|
||||
|
||||
bool injest_image(lv_opengl_shader_manager_t * shader_manager, lv_gltf_model_t * data, fastgltf::Image & image,
|
||||
uint32_t index)
|
||||
{
|
||||
std::string _tex_id = std::string(lv_gltf_get_filename(data)) + "_IMG" + std::to_string(index);
|
||||
|
||||
char tmp[512];
|
||||
lv_snprintf(tmp, sizeof(tmp), "%s_img_%u", data->filename, index);
|
||||
const uint32_t hash = lv_opengl_shader_hash(tmp);
|
||||
GLuint texture_id = lv_opengl_shader_manager_get_texture(shader_manager, hash);
|
||||
|
||||
if(texture_id != GL_NONE) {
|
||||
LV_LOG_TRACE("Emplacing back already cached texture from previous injest iteration %u", texture_id);
|
||||
data->textures.emplace_back(texture_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
LV_LOG_TRACE("Image (%s) [%d] [%u]", image.name.c_str(), texture_id, hash);
|
||||
glGenTextures(1, &texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 20));
|
||||
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
bool image_invalidated = false;
|
||||
std::visit(fastgltf::visitor{
|
||||
[](auto & arg)
|
||||
{
|
||||
LV_UNUSED(arg);
|
||||
LV_LOG_ERROR("Unexpected image source");
|
||||
},
|
||||
[&](fastgltf::sources::URI & file_path)
|
||||
{
|
||||
LV_ASSERT_MSG(file_path.fileByteOffset == 0, "Offsets aren't supported with stbi");
|
||||
LV_ASSERT_MSG(file_path.uri.isLocalPath(), "We're only capable of loading local files.");
|
||||
|
||||
int32_t width, height, nrChannels;
|
||||
LV_LOG_TRACE("Loading image: %s", image.name.c_str());
|
||||
const std::string path(file_path.uri.path().begin(), file_path.uri.path().end());
|
||||
unsigned char * data = stbi_load(path.c_str(), &width, &height, &nrChannels, 4);
|
||||
tex_storage_2d_compat(GL_TEXTURE_2D, get_level_count(width, height), GL_RGBA8, width, height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
stbi_image_free(data);
|
||||
},
|
||||
[&](fastgltf::sources::Array & vector)
|
||||
{
|
||||
int32_t width, height, nrChannels;
|
||||
LV_LOG_TRACE("Unpacking image data: %s", image.name.c_str());
|
||||
|
||||
unsigned char * data = stbi_load_from_memory(
|
||||
reinterpret_cast<const stbi_uc *>(vector.bytes.data()),
|
||||
static_cast<int32_t>(vector.bytes.size()), &width, &height, &nrChannels, 4);
|
||||
tex_storage_2d_compat(GL_TEXTURE_2D, get_level_count(width, height), GL_RGBA8, width, height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
stbi_image_free(data);
|
||||
},
|
||||
[&](fastgltf::sources::BufferView & view)
|
||||
{
|
||||
LV_LOG_TRACE("Injesting image from bufferview: %s", image.name.c_str());
|
||||
image_invalidated |= injest_image_from_buffer_view(data, view, texture_id);
|
||||
},
|
||||
}, image.data);
|
||||
|
||||
if(!image_invalidated) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
else {
|
||||
LV_LOG_ERROR("Failed to load image %s", image.name.c_str());
|
||||
}
|
||||
LV_LOG_TRACE("Storing texture with hash: %u %u", hash, texture_id);
|
||||
lv_opengl_shader_manager_store_texture(shader_manager, hash, texture_id);
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
data->textures.emplace_back(texture_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool injest_image_from_buffer_view(lv_gltf_model_t * data, fastgltf::sources::BufferView & view,
|
||||
GLuint texture_id)
|
||||
{
|
||||
/* Yes, we've already loaded every buffer into some GL buffer. However, with GL it's simpler
|
||||
to just copy the buffer data again for the texture. Besides, this is just an example. */
|
||||
auto & buffer_view = data->asset.bufferViews[view.bufferViewIndex];
|
||||
auto & buffer = data->asset.buffers[buffer_view.bufferIndex];
|
||||
LV_LOG_INFO("Unpacking image bufferView: %s from %d bytes", image.name, bufferView.byteLenght);
|
||||
return std::visit(
|
||||
fastgltf::visitor{
|
||||
// We only care about VectorWithMime here, because we specify LoadExternalBuffers, meaning
|
||||
// all buffers are already loaded into a vector.
|
||||
[](auto & arg)
|
||||
{
|
||||
LV_UNUSED(arg);
|
||||
LV_LOG_ERROR("Unexpected image source");
|
||||
return false;
|
||||
},
|
||||
[&](fastgltf::sources::Array & vector)
|
||||
{
|
||||
LV_LOG_TRACE("[WEBP] width: %d height: %d", width, height);
|
||||
int32_t width, height, nrChannels;
|
||||
int32_t webpRes = WebPGetInfo(
|
||||
reinterpret_cast<const uint8_t *>(vector.bytes.data() + buffer_view.byteOffset),
|
||||
static_cast<std::size_t>(buffer_view.byteLength), &width, &height);
|
||||
|
||||
if(!webpRes) {
|
||||
unsigned char * data = stbi_load_from_memory(
|
||||
reinterpret_cast<const stbi_uc *>(vector.bytes.data() + buffer_view.byteOffset),
|
||||
static_cast<int32_t>(buffer_view.byteLength), &width, &height, &nrChannels, 4);
|
||||
if((width <= 0) || (height <= 0)) {
|
||||
LV_LOG_ERROR("Failed to load image from memory");
|
||||
make_small_magenta_texture(texture_id);
|
||||
return true;
|
||||
}
|
||||
LV_LOG_TRACE("[WEBP] width: %d height: %d", width, height);
|
||||
tex_storage_2d_compat(GL_TEXTURE_2D, get_level_count(width, height), GL_RGBA8, width, height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
stbi_image_free(data);
|
||||
return false;
|
||||
}
|
||||
WebPBitstreamFeatures features = WebPBitstreamFeatures();
|
||||
auto status_code = WebPGetFeatures(
|
||||
reinterpret_cast<const uint8_t *>(vector.bytes.data() + buffer_view.byteOffset),
|
||||
static_cast<std::size_t>(buffer_view.byteLength), &features);
|
||||
if(status_code != VP8_STATUS_OK) {
|
||||
LV_LOG_ERROR("Failed to load webp image %d", status_code);
|
||||
make_small_magenta_texture(texture_id);
|
||||
return true;
|
||||
}
|
||||
if(features.has_alpha) {
|
||||
uint8_t * unpacked = WebPDecodeRGBA(
|
||||
reinterpret_cast<const uint8_t *>(vector.bytes.data() + buffer_view.byteOffset),
|
||||
static_cast<std::size_t>(buffer_view.byteLength), &width, &height);
|
||||
tex_storage_2d_compat(GL_TEXTURE_2D, get_level_count(width, height), GL_RGBA8, width, height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
unpacked);
|
||||
WebPFree(unpacked);
|
||||
}
|
||||
else {
|
||||
uint8_t * unpacked = WebPDecodeRGB(
|
||||
reinterpret_cast<const uint8_t *>(vector.bytes.data() + buffer_view.byteOffset),
|
||||
static_cast<std::size_t>(buffer_view.byteLength), &width, &height);
|
||||
tex_storage_2d_compat(GL_TEXTURE_2D, get_level_count(width, height), GL_RGB8, width, height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
unpacked);
|
||||
WebPFree(unpacked);
|
||||
}
|
||||
return false;
|
||||
} },
|
||||
buffer.data);
|
||||
}
|
||||
static void injest_light(lv_gltf_model_t * data, size_t light_index, fastgltf::Light & light, size_t scene_index)
|
||||
{
|
||||
fastgltf::math::fmat4x4 tmat;
|
||||
// It would seem like we'd need this info but not really, just the index will do at the loading phase, the rest is pulled during frame updates.
|
||||
LV_UNUSED(light);
|
||||
|
||||
fastgltf::findlight_iterate_scene_nodes(data->asset, scene_index, &tmat,
|
||||
[&](fastgltf::Node & node, const fastgltf::math::fmat4x4 & parentworldmatrix,
|
||||
const fastgltf::math::fmat4x4 & localmatrix) {
|
||||
LV_UNUSED(parentworldmatrix);
|
||||
LV_UNUSED(localmatrix);
|
||||
if(!node.lightIndex.has_value() ||
|
||||
node.lightIndex.value() != light_index) {
|
||||
return;
|
||||
}
|
||||
LV_LOG_INFO("SCENE LIGHT BEING ADDED #%d\n", light_index);
|
||||
data->node_by_light_index.push_back(&node);
|
||||
});
|
||||
}
|
||||
|
||||
static bool injest_mesh(lv_gltf_model_t * data, fastgltf::Mesh & mesh)
|
||||
{
|
||||
/*const auto &asset = GET_ASSET(data);*/
|
||||
const auto & outMesh = lv_gltf_get_new_meshdata(data);
|
||||
outMesh->primitives.resize(mesh.primitives.size());
|
||||
|
||||
for(auto it = mesh.primitives.begin(); it != mesh.primitives.end(); ++it) {
|
||||
if(it->dracoCompression) {
|
||||
LV_LOG_WARN("Unhandled draco compression");
|
||||
}
|
||||
auto * positionIt = it->findAttribute("POSITION");
|
||||
// A mesh primitive is required to hold the POSITION attribute.
|
||||
//
|
||||
assert(positionIt != it->attributes.end());
|
||||
assert(it->indicesAccessor.has_value()); // We specify GenerateMeshIndices, so we should always have indices
|
||||
|
||||
auto index = std::distance(mesh.primitives.begin(), it);
|
||||
auto & primitive = outMesh->primitives[index];
|
||||
|
||||
// Generate the VAO
|
||||
GLuint vao;
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
primitive.primitiveType = fastgltf::to_underlying(it->type);
|
||||
primitive.vertexArray = vao;
|
||||
|
||||
if(it->materialIndex.has_value()) {
|
||||
// Adjust for default material
|
||||
primitive.materialUniformsIndex = it->materialIndex.value() + 1;
|
||||
auto & material = data->asset.materials[it->materialIndex.value()];
|
||||
load_mesh_texture(data, material.pbrData.baseColorTexture, &primitive.albedoTexture,
|
||||
&primitive.baseColorTexcoordIndex);
|
||||
|
||||
load_mesh_texture(data, material.pbrData.metallicRoughnessTexture, &primitive.metalRoughTexture,
|
||||
&primitive.metallicRoughnessTexcoordIndex);
|
||||
load_mesh_texture(data, material.normalTexture, &primitive.normalTexture, &primitive.normalTexcoordIndex);
|
||||
load_mesh_texture(data, material.occlusionTexture, &primitive.occlusionTexture,
|
||||
&primitive.occlusionTexcoordIndex);
|
||||
load_mesh_texture(data, material.emissiveTexture, &primitive.emissiveTexture,
|
||||
&primitive.emissiveTexcoordIndex);
|
||||
if(material.volume)
|
||||
load_mesh_texture(data, material.volume->thicknessTexture, &primitive.thicknessTexture,
|
||||
&primitive.thicknessTexcoordIndex);
|
||||
if(material.transmission)
|
||||
load_mesh_texture(data, material.transmission->transmissionTexture,
|
||||
&primitive.transmissionTexture, (GLint *)&primitive.transmissionTexcoordIndex);
|
||||
if(material.clearcoat && material.clearcoat->clearcoatFactor > 0.0f) {
|
||||
load_mesh_texture(data, material.clearcoat->clearcoatTexture,
|
||||
(GLuint *)&primitive.clearcoatTexture, &primitive.clearcoatTexcoordIndex);
|
||||
load_mesh_texture(data, material.clearcoat->clearcoatRoughnessTexture,
|
||||
(GLuint *)&primitive.clearcoatRoughnessTexture,
|
||||
&primitive.clearcoatRoughnessTexcoordIndex);
|
||||
load_mesh_texture(data, material.clearcoat->clearcoatNormalTexture,
|
||||
(GLuint *)&primitive.clearcoatNormalTexture,
|
||||
&primitive.clearcoatNormalTexcoordIndex);
|
||||
}
|
||||
if(material.diffuseTransmission && material.diffuseTransmission->diffuseTransmissionFactor > 0.0f) {
|
||||
load_mesh_texture(data, material.diffuseTransmission->diffuseTransmissionTexture,
|
||||
&primitive.diffuseTransmissionTexture,
|
||||
&primitive.diffuseTransmissionTexcoordIndex);
|
||||
load_mesh_texture(data, material.diffuseTransmission->diffuseTransmissionColorTexture,
|
||||
&primitive.diffuseTransmissionColorTexture,
|
||||
&primitive.diffuseTransmissionColorTexcoordIndex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
primitive.materialUniformsIndex = 0;
|
||||
}
|
||||
|
||||
auto & positionAccessor = data->asset.accessors[positionIt->accessorIndex];
|
||||
if(!positionAccessor.bufferViewIndex.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the vertex buffer for this primitive, and use the accessor tools to copy directly into the mapped buffer.
|
||||
GL_CALL(glGenBuffers(1, &primitive.vertexBuffer));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, primitive.vertexBuffer));
|
||||
|
||||
std::vector<vertex_t> vertices_vec(positionAccessor.count);
|
||||
vertex_t * vertices = vertices_vec.data();
|
||||
glBufferData(GL_ARRAY_BUFFER, positionAccessor.count * sizeof(*vertices), nullptr, GL_STATIC_DRAW);
|
||||
{
|
||||
int32_t attr_index = 0;
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec3>(
|
||||
3, attr_index, data, &(*it), "POSITION", primitive.vertexBuffer, offsetof(vertex_t, position),
|
||||
[&](fastgltf::math::fvec3 vec, size_t idx) {
|
||||
vertices[idx].position = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec4>(
|
||||
4, attr_index, data, &(*it), "JOINTS_0", primitive.vertexBuffer, offsetof(vertex_t, joints),
|
||||
[&](fastgltf::math::fvec4 vec, size_t idx) {
|
||||
vertices[idx].joints = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec4>(
|
||||
4, attr_index, data, &(*it), "JOINTS_1", primitive.vertexBuffer, offsetof(vertex_t, joints2),
|
||||
[&](fastgltf::math::fvec4 vec, std::size_t idx) {
|
||||
vertices[idx].joints2 = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec4>(
|
||||
4, attr_index, data, &(*it), "WEIGHTS_0", primitive.vertexBuffer, offsetof(vertex_t, weights),
|
||||
[&](fastgltf::math::fvec4 vec, std::size_t idx) {
|
||||
vertices[idx].weights = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec4>(
|
||||
4, attr_index, data, &(*it), "WEIGHTS_1", primitive.vertexBuffer, offsetof(vertex_t, weights2),
|
||||
[&](fastgltf::math::fvec4 vec, size_t idx) {
|
||||
vertices[idx].weights2 = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec3>(
|
||||
3, attr_index, data, &(*it), "NORMAL", primitive.vertexBuffer, offsetof(vertex_t, normal),
|
||||
[&](fastgltf::math::fvec3 vec, std::size_t idx) {
|
||||
vertices[idx].normal = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec4>(
|
||||
4, attr_index, data, &(*it), "TANGENT", primitive.vertexBuffer, offsetof(vertex_t, tangent),
|
||||
[&](fastgltf::math::fvec4 vec, size_t idx) {
|
||||
vertices[idx].tangent = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec2>(
|
||||
2, attr_index, data, &(*it), "TEXCOORD_0", primitive.vertexBuffer, offsetof(vertex_t, uv),
|
||||
[&](fastgltf::math::fvec2 vec, size_t idx) {
|
||||
vertices[idx].uv = vec;
|
||||
});
|
||||
attr_index = injest_vec_attribute<fastgltf::math::fvec2>(
|
||||
2, attr_index, data, &(*it), "TEXCOORD_1", primitive.vertexBuffer, offsetof(vertex_t, uv2),
|
||||
[&](fastgltf::math::fvec2 vec, size_t idx) {
|
||||
vertices[idx].uv2 = vec;
|
||||
});
|
||||
}
|
||||
glBindVertexArray(vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, primitive.vertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, positionAccessor.count * sizeof(vertex_t), vertices_vec.data(), GL_STATIC_DRAW);
|
||||
|
||||
// Generate the indirect draw command
|
||||
auto & draw = primitive.draw;
|
||||
draw.instanceCount = 1;
|
||||
draw.baseInstance = 0;
|
||||
draw.baseVertex = 0;
|
||||
draw.firstIndex = 0;
|
||||
|
||||
auto & indexAccessor = data->asset.accessors[it->indicesAccessor.value()];
|
||||
if(!indexAccessor.bufferViewIndex.has_value())
|
||||
return false;
|
||||
draw.count = static_cast<std::uint32_t>(indexAccessor.count);
|
||||
|
||||
// Create the index buffer and copy the indices into it.
|
||||
glGenBuffers(1, &primitive.indexBuffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, primitive.indexBuffer);
|
||||
if(indexAccessor.componentType == fastgltf::ComponentType::UnsignedByte ||
|
||||
indexAccessor.componentType == fastgltf::ComponentType::UnsignedShort) {
|
||||
primitive.indexType = GL_UNSIGNED_SHORT;
|
||||
std::uint16_t * tempIndices = new std::uint16_t[indexAccessor.count];
|
||||
fastgltf::copyFromAccessor<std::uint16_t>(data->asset, indexAccessor, tempIndices);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast<GLsizeiptr>(indexAccessor.count * sizeof(std::uint16_t)), tempIndices,
|
||||
GL_STATIC_DRAW);
|
||||
delete[] tempIndices;
|
||||
}
|
||||
else {
|
||||
primitive.indexType = GL_UNSIGNED_INT;
|
||||
//std::uint32_t tempIndices[indexAccessor.count];
|
||||
std::uint32_t * tempIndices = new std::uint32_t[indexAccessor.count];
|
||||
fastgltf::copyFromAccessor<std::uint32_t>(data->asset, indexAccessor, tempIndices);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
static_cast<GLsizeiptr>(indexAccessor.count * sizeof(std::uint32_t)), tempIndices,
|
||||
GL_STATIC_DRAW);
|
||||
delete[] tempIndices;
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
return true;
|
||||
}
|
||||
template <typename T, typename Func>
|
||||
static size_t injest_vec_attribute(uint8_t vec_size, int32_t current_attrib_index, lv_gltf_model_t * data,
|
||||
const fastgltf::Primitive * prim, const char * attrib_id, GLuint primitive_vertex_buffer,
|
||||
size_t offset, Func &&functor
|
||||
|
||||
)
|
||||
{
|
||||
const auto & asset = data->asset;
|
||||
if(const auto * _attrib = prim->findAttribute(std::string(attrib_id)); _attrib != prim->attributes.end()) {
|
||||
auto & accessor = asset.accessors[_attrib->accessorIndex];
|
||||
if(accessor.bufferViewIndex.has_value()) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, primitive_vertex_buffer);
|
||||
fastgltf::iterateAccessorWithIndex<T>(asset, accessor, functor);
|
||||
// Specify the layout of the vertex data
|
||||
glVertexAttribPointer(current_attrib_index, // Attribute index
|
||||
vec_size, // Number of components per vertex
|
||||
GL_FLOAT, // Data type
|
||||
GL_FALSE, // Normalized
|
||||
sizeof(vertex_t), // Stride (size of one vertex)
|
||||
(void *)offset); // Offset in the buffer
|
||||
glEnableVertexAttribArray(current_attrib_index);
|
||||
}
|
||||
else {
|
||||
glDisableVertexAttribArray(current_attrib_index);
|
||||
}
|
||||
current_attrib_index++;
|
||||
}
|
||||
return current_attrib_index;
|
||||
}
|
||||
|
||||
static void set_bounds_info(lv_gltf_model_t * data, fastgltf::math::fvec3 v_min, fastgltf::math::fvec3 v_max,
|
||||
fastgltf::math::fvec3 v_cen, float radius)
|
||||
{
|
||||
{
|
||||
auto _d = v_min.data();
|
||||
data->vertex_min[0] = _d[0];
|
||||
data->vertex_min[1] = _d[1];
|
||||
data->vertex_min[2] = _d[2];
|
||||
}
|
||||
{
|
||||
auto _d = v_max.data();
|
||||
data->vertex_max[0] = _d[0];
|
||||
data->vertex_max[1] = _d[1];
|
||||
data->vertex_max[2] = _d[2];
|
||||
}
|
||||
{
|
||||
auto _d = v_cen.data();
|
||||
data->vertex_cen[0] = _d[0];
|
||||
data->vertex_cen[1] = _d[1];
|
||||
data->vertex_cen[2] = _d[2];
|
||||
}
|
||||
data->bound_radius = radius;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
256
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_internal.h
Normal file
256
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_internal.h
Normal file
@@ -0,0 +1,256 @@
|
||||
#ifndef LV_GLTFDATA_PRIVATE_H
|
||||
#define LV_GLTFDATA_PRIVATE_H
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if LV_USE_GLTF
|
||||
#include "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../../../draw/lv_image_dsc.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_array.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 {
|
||||
lv_gltf_uniform_locations_t uniforms;
|
||||
GLuint program;
|
||||
} 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(const lv_gltf_model_t * model);
|
||||
|
||||
|
||||
/**
|
||||
* @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_delete(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 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);
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LV_GLTFDATA_PRIVATE_H */
|
||||
412
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_internal.hpp
Normal file
412
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_internal.hpp
Normal file
@@ -0,0 +1,412 @@
|
||||
#ifndef LV_GLTFDATA_HPP
|
||||
#define LV_GLTFDATA_HPP
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../gltf_view/lv_gltf.h"
|
||||
#include "lv_gltf_data_internal.h"
|
||||
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include "../../../drivers/opengles/lv_opengles_private.h"
|
||||
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_ll.h"
|
||||
#include "../../../misc/lv_event.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
#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> >;
|
||||
|
||||
#define LV_GLTF_NODE_CHANNEL_X 0
|
||||
#define LV_GLTF_NODE_CHANNEL_Y 1
|
||||
#define LV_GLTF_NODE_CHANNEL_Z 2
|
||||
#define LV_GLTF_NODE_CHANNEL_W 4
|
||||
|
||||
typedef enum {
|
||||
LV_GLTF_NODE_PROP_POSITION,
|
||||
LV_GLTF_NODE_PROP_ROTATION,
|
||||
LV_GLTF_NODE_PROP_SCALE,
|
||||
} lv_gltf_node_prop_t;
|
||||
|
||||
typedef struct {
|
||||
lv_3dpoint_t local_position;
|
||||
lv_3dpoint_t world_position;
|
||||
lv_3dpoint_t scale;
|
||||
lv_3dpoint_t rotation;
|
||||
} lv_gltf_model_node_data_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gltf_node_prop_t prop;
|
||||
uint8_t channel;
|
||||
float value;
|
||||
} lv_gltf_write_op_t;
|
||||
|
||||
typedef struct {
|
||||
GLuint drawsBuffer;
|
||||
std::vector<lv_gltf_primitive_t> primitives;
|
||||
} lv_gltf_mesh_data_t;
|
||||
|
||||
typedef struct {
|
||||
lv_event_list_t event_list;
|
||||
lv_gltf_model_node_data_t node_data;
|
||||
bool read_world_position;
|
||||
bool value_changed;
|
||||
} lv_gltf_model_node_attr_t;
|
||||
|
||||
|
||||
struct _lv_gltf_model_node_t {
|
||||
lv_gltf_model_t * model;
|
||||
const char * numeric_path;
|
||||
const char * path;
|
||||
fastgltf::Node * fastgltf_node;
|
||||
lv_gltf_model_node_attr_t * read_attrs;
|
||||
lv_array_t write_ops;
|
||||
};
|
||||
|
||||
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;
|
||||
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;
|
||||
bool write_ops_pending;
|
||||
bool write_ops_flushed;
|
||||
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);
|
||||
|
||||
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_delete_textures(lv_gltf_model_t * data);
|
||||
GLuint lv_gltf_data_create_texture(lv_gltf_model_t * data);
|
||||
void lv_gltf_model_node_init(lv_gltf_model_t * model, lv_gltf_model_node_t * node, fastgltf::Node * fastgltf_node,
|
||||
const char * path,
|
||||
const char * num_path);
|
||||
|
||||
void lv_gltf_model_node_deinit(lv_gltf_model_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);
|
||||
|
||||
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);
|
||||
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_internal_node(lv_gltf_model_t * model,
|
||||
const fastgltf::Node * fastgltf_node);
|
||||
|
||||
void lv_gltf_model_send_new_values(lv_gltf_model_t * model);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /*LV_GLTFVIEW_H*/
|
||||
52
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_mesh.cpp
Normal file
52
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_mesh.cpp
Normal file
@@ -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*/
|
||||
126
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_primitive.cpp
Normal file
126
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_primitive.cpp
Normal file
@@ -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, size_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*/
|
||||
60
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_shader.cpp
Normal file
60
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_shader.cpp
Normal file
@@ -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*/
|
||||
68
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_skin.cpp
Normal file
68
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_skin.cpp
Normal file
@@ -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*/
|
||||
87
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_texture.cpp
Normal file
87
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_data_texture.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @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_delete_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;
|
||||
}
|
||||
|
||||
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*/
|
||||
127
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model.h
Normal file
127
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef LV_GLTF_MODEL_H
|
||||
#define LV_GLTF_MODEL_H
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "lv_gltf_model_node.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_event.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 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*/
|
||||
375
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model_node.cpp
Normal file
375
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model_node.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @file lv_gltf_model_node.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_data_internal.hpp"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <float.h>
|
||||
#include "fastgltf/types.hpp"
|
||||
#include "lv_gltf_model.h"
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include "../../../misc/lv_assert.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_event_private.h"
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#include "../../../stdlib/lv_sprintf.h"
|
||||
#include "../../../core/lv_obj_pos.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
static lv_result_t add_write_op(lv_gltf_model_node_t * node, lv_gltf_node_prop_t prop, uint8_t channel, float value);
|
||||
static void invalidate_model(lv_gltf_model_t * model);
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gltf_model_node_init(lv_gltf_model_t * model, lv_gltf_model_node_t * node, fastgltf::Node * fastgltf_node,
|
||||
const char * path,
|
||||
const char * numeric_path)
|
||||
{
|
||||
LV_ASSERT_NULL(node);
|
||||
lv_memset(node, 0, sizeof(*node));
|
||||
node->model = model;
|
||||
node->fastgltf_node = fastgltf_node;
|
||||
node->path = lv_strdup(path);
|
||||
node->numeric_path = lv_strdup(numeric_path);
|
||||
LV_ASSERT_MALLOC(node->path);
|
||||
LV_ASSERT_MALLOC(node->numeric_path);
|
||||
|
||||
lv_array_init(&node->write_ops, 0, sizeof(lv_gltf_write_op_t));
|
||||
}
|
||||
|
||||
void lv_gltf_model_node_deinit(lv_gltf_model_node_t * node)
|
||||
{
|
||||
LV_ASSERT_NULL(node);
|
||||
lv_free((void *)node->path);
|
||||
lv_free((void *)node->numeric_path);
|
||||
lv_array_deinit(&node->write_ops);
|
||||
|
||||
if(node->read_attrs) {
|
||||
lv_event_remove_all(&node->read_attrs->event_list);
|
||||
lv_free((void *)node->read_attrs);
|
||||
}
|
||||
}
|
||||
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_index(lv_gltf_model_t * model, size_t index)
|
||||
{
|
||||
if(!model) {
|
||||
LV_LOG_WARN("Failed to get node from NULL model");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t count = lv_array_size(&model->nodes);
|
||||
if(index >= count) {
|
||||
LV_LOG_WARN("Invalid index %zu. Max should be %" LV_PRIu32, index, count - 1);
|
||||
return nullptr;
|
||||
}
|
||||
return (lv_gltf_model_node_t *)lv_array_at(&model->nodes, index);
|
||||
}
|
||||
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_numeric_path(lv_gltf_model_t * model, const char * num_path)
|
||||
{
|
||||
|
||||
const uint32_t node_count = lv_array_size(&model->nodes);
|
||||
for(uint32_t i = 0; i < node_count; ++i) {
|
||||
lv_gltf_model_node_t * entry = (lv_gltf_model_node_t *) lv_array_at(&model->nodes, i);
|
||||
if(lv_streq(entry->numeric_path, num_path)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_path(lv_gltf_model_t * model, const char * path)
|
||||
{
|
||||
|
||||
if(!model) {
|
||||
LV_LOG_WARN("Can't get node from NULL model");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint32_t node_count = lv_array_size(&model->nodes);
|
||||
for(uint32_t i = 0; i < node_count; ++i) {
|
||||
lv_gltf_model_node_t * entry = (lv_gltf_model_node_t *) lv_array_at(&model->nodes, i);
|
||||
if(lv_streq(entry->path, path)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_internal_node(lv_gltf_model_t * model,
|
||||
const fastgltf::Node * fastgltf_node)
|
||||
{
|
||||
LV_ASSERT_NULL(model);
|
||||
const uint32_t node_count = lv_array_size(&model->nodes);
|
||||
for(uint32_t i = 0; i < node_count; ++i) {
|
||||
lv_gltf_model_node_t * entry = (lv_gltf_model_node_t *) lv_array_at(&model->nodes, i);
|
||||
if(entry->fastgltf_node == fastgltf_node) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * lv_gltf_model_node_get_path(lv_gltf_model_node_t * node)
|
||||
{
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Can't get the path of a null node");
|
||||
return nullptr;
|
||||
}
|
||||
return node->path;
|
||||
}
|
||||
|
||||
const char * lv_gltf_model_node_get_ip(lv_gltf_model_node_t * node)
|
||||
{
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Can't get the ip of a null node");
|
||||
return nullptr;
|
||||
}
|
||||
return node->numeric_path;
|
||||
}
|
||||
void lv_gltf_model_send_new_values(lv_gltf_model_t * model)
|
||||
{
|
||||
LV_ASSERT_NULL(model);
|
||||
if(!model->write_ops_flushed) {
|
||||
return;
|
||||
}
|
||||
const uint32_t node_count = lv_array_size(&model->nodes);
|
||||
for(uint32_t i = 0; i < node_count; ++i) {
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *) lv_array_at(&model->nodes, i);
|
||||
if(!node->read_attrs || !node->read_attrs->value_changed) {
|
||||
continue;
|
||||
}
|
||||
lv_event_push_and_send(&node->read_attrs->event_list, LV_EVENT_VALUE_CHANGED, node, &node->read_attrs->node_data);
|
||||
node->read_attrs->value_changed = false;
|
||||
}
|
||||
model->write_ops_flushed = false;
|
||||
}
|
||||
|
||||
lv_event_dsc_t * lv_gltf_model_node_add_event_cb(lv_gltf_model_node_t * node, lv_event_cb_t cb,
|
||||
lv_event_code_t filter_list,
|
||||
void * user_data)
|
||||
{
|
||||
if(!node->read_attrs) {
|
||||
node->read_attrs = (lv_gltf_model_node_attr_t *) lv_zalloc(sizeof(*node->read_attrs));
|
||||
LV_ASSERT_MALLOC(node->read_attrs);
|
||||
if(!node->read_attrs) {
|
||||
LV_LOG_WARN("Failed to allocate memory for read attributes");
|
||||
return nullptr;
|
||||
}
|
||||
lv_array_init(&node->read_attrs->event_list.array, 1, sizeof(lv_event_dsc_t *));
|
||||
}
|
||||
return lv_event_add(&node->read_attrs->event_list, cb, filter_list, user_data);
|
||||
}
|
||||
|
||||
lv_event_dsc_t * lv_gltf_model_node_add_event_cb_with_world_position(lv_gltf_model_node_t * node, lv_event_cb_t cb,
|
||||
lv_event_code_t filter_list,
|
||||
void * user_data)
|
||||
{
|
||||
lv_event_dsc_t * dsc = lv_gltf_model_node_add_event_cb(node, cb, filter_list, user_data);
|
||||
if(!dsc) {
|
||||
return nullptr;
|
||||
}
|
||||
LV_ASSERT_NULL(node->read_attrs);
|
||||
node->read_attrs->read_world_position = true;
|
||||
return dsc;
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_position_x(lv_gltf_model_node_t * node, float x)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_POSITION, LV_GLTF_NODE_CHANNEL_X, x);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_position_y(lv_gltf_model_node_t * node, float y)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_POSITION, LV_GLTF_NODE_CHANNEL_Y, y);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_position_z(lv_gltf_model_node_t * node, float z)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_POSITION, LV_GLTF_NODE_CHANNEL_Z, z);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_rotation_x(lv_gltf_model_node_t * node, float x)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_ROTATION, LV_GLTF_NODE_CHANNEL_X, x);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_rotation_y(lv_gltf_model_node_t * node, float y)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_ROTATION, LV_GLTF_NODE_CHANNEL_Y, y);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_rotation_z(lv_gltf_model_node_t * node, float z)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_ROTATION, LV_GLTF_NODE_CHANNEL_Z, z);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_scale_x(lv_gltf_model_node_t * node, float x)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_SCALE, LV_GLTF_NODE_CHANNEL_X, x);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_scale_y(lv_gltf_model_node_t * node, float y)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_SCALE, LV_GLTF_NODE_CHANNEL_Y, y);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_set_scale_z(lv_gltf_model_node_t * node, float z)
|
||||
{
|
||||
return add_write_op(node, LV_GLTF_NODE_PROP_SCALE, LV_GLTF_NODE_CHANNEL_Z, z);
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_get_local_position(lv_event_t * e, lv_3dpoint_t * result)
|
||||
{
|
||||
if(!e || e->code != LV_EVENT_VALUE_CHANGED) {
|
||||
LV_LOG_WARN("Invalid event");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *)lv_event_get_target(e);
|
||||
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Cannot get property from a NULL node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!node->read_attrs) {
|
||||
LV_LOG_WARN("No read event set for this node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
*result = node->read_attrs->node_data.local_position;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_get_world_position(lv_event_t * e, lv_3dpoint_t * result)
|
||||
{
|
||||
if(!e || e->code != LV_EVENT_VALUE_CHANGED) {
|
||||
LV_LOG_WARN("Invalid event");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *)lv_event_get_target(e);
|
||||
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Cannot get property from a NULL node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!node->read_attrs) {
|
||||
LV_LOG_WARN("No read event set for this node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!node->read_attrs->read_world_position) {
|
||||
LV_LOG_WARN("World position is not read by this node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
*result = node->read_attrs->node_data.world_position;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_get_scale(lv_event_t * e, lv_3dpoint_t * result)
|
||||
{
|
||||
if(!e || e->code != LV_EVENT_VALUE_CHANGED) {
|
||||
LV_LOG_WARN("Invalid event");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *)lv_event_get_target(e);
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Cannot get property from a NULL node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!node->read_attrs) {
|
||||
LV_LOG_WARN("No read event set for this node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
*result = node->read_attrs->node_data.scale;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_model_node_get_euler_rotation(lv_event_t * e, lv_3dpoint_t * result)
|
||||
{
|
||||
if(!e || e->code != LV_EVENT_VALUE_CHANGED) {
|
||||
LV_LOG_WARN("Invalid event");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
lv_gltf_model_node_t * node = (lv_gltf_model_node_t *)lv_event_get_target(e);
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Cannot get property from a NULL node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(!node->read_attrs) {
|
||||
LV_LOG_WARN("No read event set for this node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
*result = node->read_attrs->node_data.rotation;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void invalidate_model(lv_gltf_model_t * model)
|
||||
{
|
||||
lv_obj_invalidate((lv_obj_t *)model->viewer);
|
||||
model->write_ops_pending = true;
|
||||
}
|
||||
|
||||
static lv_result_t add_write_op(lv_gltf_model_node_t * node, lv_gltf_node_prop_t prop, uint8_t channel, float value)
|
||||
{
|
||||
if(!node) {
|
||||
LV_LOG_WARN("Can't queue queue write operation for NULL node");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/* Try to find if a write operation for this property + channel combination exists*/
|
||||
/* Doing this is ok for now because the array will be of max size 9 (3 properties x 3 channels)
|
||||
* In case we start adding more properties we need to look into other approaches*/
|
||||
const uint32_t write_ops_count = lv_array_size(&node->write_ops);
|
||||
for(uint32_t i = 0; i < write_ops_count; ++i) {
|
||||
lv_gltf_write_op_t * write_op = (lv_gltf_write_op_t *)lv_array_at(&node->write_ops, i);
|
||||
if(write_op->prop != prop || write_op->channel != channel) {
|
||||
continue;
|
||||
}
|
||||
if(LV_ABS(write_op->value - value) > FLT_EPSILON) {
|
||||
write_op->value = value;
|
||||
invalidate_model(node->model);
|
||||
}
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
/* Else create a new one */
|
||||
lv_gltf_write_op_t write_op {prop, channel, value};
|
||||
lv_result_t res = lv_array_push_back(&node->write_ops, &write_op);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return res;
|
||||
}
|
||||
invalidate_model(node->model);
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
264
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model_node.h
Normal file
264
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_model_node.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @file lv_gltf_model_node.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_MODEL_NODE_H
|
||||
#define LV_GLTF_MODEL_NODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../math/lv_3dmath.h"
|
||||
#include "../../../misc/lv_event.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @brief Get a glTF model node by its index
|
||||
*
|
||||
* @param data Pointer to the glTF model structure
|
||||
* @param index The index of the node to retrieve
|
||||
* @return Pointer to the glTF model node, or NULL if not found
|
||||
*/
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_index(lv_gltf_model_t * data, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Get a glTF model node by its numeric path
|
||||
*
|
||||
* @param data Pointer to the glTF model structure
|
||||
* @param num_path The numeric path string of the node to retrieve (eg. ".0")
|
||||
* @return Pointer to the glTF model node, or NULL if not found
|
||||
*/
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_numeric_path(lv_gltf_model_t * data, const char * num_path);
|
||||
|
||||
/**
|
||||
* @brief Get a glTF model node by its path
|
||||
*
|
||||
* @param data Pointer to the glTF model structure
|
||||
* @param path The path string of the node to retrieve
|
||||
* @return Pointer to the glTF model node, or NULL if not found
|
||||
*/
|
||||
lv_gltf_model_node_t * lv_gltf_model_node_get_by_path(lv_gltf_model_t * data, const char * path);
|
||||
|
||||
/**
|
||||
* @brief Get the path of a glTF model node
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @return The path string of the node, or NULL if node is invalid
|
||||
*/
|
||||
const char * lv_gltf_model_node_get_path(lv_gltf_model_node_t * node);
|
||||
|
||||
/**
|
||||
* @brief Get the IP (internal pointer/identifier) of a glTF model node
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @return The IP string of the node, or NULL if node is invalid
|
||||
*/
|
||||
const char * lv_gltf_model_node_get_ip(lv_gltf_model_node_t * node);
|
||||
|
||||
/**
|
||||
* @brief Add an event callback to a glTF model node
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param cb The event callback function to add. Use lv_event_get_param() to retrieve lv_gltf_node_data_t with the node's data.
|
||||
* @param filter_list Event code filter for the callback
|
||||
* @param user_data User data to pass to the callback
|
||||
* @return Pointer to the event descriptor, or NULL if allocation failed
|
||||
*/
|
||||
lv_event_dsc_t * lv_gltf_model_node_add_event_cb(lv_gltf_model_node_t * node, lv_event_cb_t cb,
|
||||
lv_event_code_t filter_list,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* @brief Add an event callback to a glTF model node with world position computation enabled. Use this only when world position is needed, as computing it is an expensive operation.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param cb The event callback function to add. Use lv_event_get_param() to retrieve lv_gltf_node_data_t with the node's data.
|
||||
* @param filter_list Event code filter for the callback
|
||||
* @param user_data User data to pass to the callback
|
||||
* @return Pointer to the event descriptor, or NULL if allocation failed
|
||||
*/
|
||||
lv_event_dsc_t * lv_gltf_model_node_add_event_cb_with_world_position(lv_gltf_model_node_t * node, lv_event_cb_t cb,
|
||||
lv_event_code_t filter_list,
|
||||
void * user_data);
|
||||
/**
|
||||
* @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 Set the X position of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param x The X position value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_position_x(lv_gltf_model_node_t * node, float x);
|
||||
|
||||
/**
|
||||
* @brief Set the Y position of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param y The Y position value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_position_y(lv_gltf_model_node_t * node, float y);
|
||||
|
||||
/**
|
||||
* @brief Set the Z position of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param z The Z position value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_position_z(lv_gltf_model_node_t * node, float z);
|
||||
|
||||
/**
|
||||
* @brief Set the X component of a glTF model node's rotation quaternion. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param x The X rotation component value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_rotation_x(lv_gltf_model_node_t * node, float x);
|
||||
|
||||
/**
|
||||
* @brief Set the Y component of a glTF model node's rotation quaternion. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param y The Y rotation component value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_rotation_y(lv_gltf_model_node_t * node, float y);
|
||||
|
||||
/**
|
||||
* @brief Set the Z component of a glTF model node's rotation quaternion. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param z The Z rotation component value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_rotation_z(lv_gltf_model_node_t * node, float z);
|
||||
|
||||
/**
|
||||
* @brief Set the X scale of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param x The X scale value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_scale_x(lv_gltf_model_node_t * node, float x);
|
||||
|
||||
/**
|
||||
* @brief Set the Y scale of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param y The Y scale value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_scale_y(lv_gltf_model_node_t * node, float y);
|
||||
|
||||
/**
|
||||
* @brief Set the Z scale of a glTF model node. The operation is queued and applied on the next rendering phase.
|
||||
*
|
||||
* @param node Pointer to the glTF model node structure
|
||||
* @param z The Z scale value
|
||||
* @return LV_RESULT_OK if the operation is queued successfully, LV_RESULT_INVALID if node is null or no more memory to queue the operation
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_set_scale_z(lv_gltf_model_node_t * node, float z);
|
||||
|
||||
/**
|
||||
* @brief Get the local position of a glTF model node. Must be called from within an LV_EVENT_VALUE_CHANGED callback.
|
||||
*
|
||||
* Local position is relative to the node's parent.
|
||||
*
|
||||
* This function is only valid when called from an event callback registered.
|
||||
* See `lv_gltf_model_node_add_event_cb()` and `lv_gltf_model_node_add_event_cb_with_world_position()`
|
||||
*
|
||||
* @param e Pointer to the event structure from the callback
|
||||
* @param result Pointer to lv_3dpoint_t structure to store the position (x, y, z)
|
||||
* @return LV_RESULT_OK if successful, LV_RESULT_INVALID if called outside event callback or if parameters are null
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_get_local_position(lv_event_t * e, lv_3dpoint_t * result);
|
||||
|
||||
/**
|
||||
* @brief Get the world position of a glTF model node. Must be called from within an LV_EVENT_VALUE_CHANGED callback
|
||||
* registered with world position enabled.
|
||||
*
|
||||
* World position is the absolute position in global scene coordinates.
|
||||
*
|
||||
* This function requires the event callback to be registered with lv_gltf_model_node_add_event_cb_with_world_position()
|
||||
* as it involves complex matrix calculations that are computed on-demand.
|
||||
*
|
||||
* @param e Pointer to the event structure from the callback
|
||||
* @param result Pointer to lv_3dpoint_t structure to store the position (x, y, z)
|
||||
* @return LV_RESULT_OK if successful, LV_RESULT_INVALID if called outside event callback, world position not enabled, or if parameters are null
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_get_world_position(lv_event_t * e, lv_3dpoint_t * result);
|
||||
|
||||
/**
|
||||
* @brief Get the scale of a glTF model node. Must be called from within an LV_EVENT_VALUE_CHANGED callback.
|
||||
*
|
||||
* Returns the scale factors for each axis.
|
||||
*
|
||||
* This function is only valid when called from an event callback registered.
|
||||
* See `lv_gltf_model_node_add_event_cb()` and `lv_gltf_model_node_add_event_cb_with_world_position()`
|
||||
*
|
||||
* @param e Pointer to the event structure from the callback
|
||||
* @param result Pointer to lv_3dpoint_t structure to store the scale (x, y, z)
|
||||
* @return LV_RESULT_OK if successful, LV_RESULT_INVALID if called outside event callback or if parameters are null
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_get_scale(lv_event_t * e, lv_3dpoint_t * result);
|
||||
|
||||
/**
|
||||
* @brief Get the Euler rotation of a glTF model node. Must be called from within an LV_EVENT_VALUE_CHANGED callback.
|
||||
*
|
||||
* Returns rotation as Euler angles in radians (x, y, z).
|
||||
*
|
||||
* This function is only valid when called from an event callback registered.
|
||||
* See `lv_gltf_model_node_add_event_cb()` and `lv_gltf_model_node_add_event_cb_with_world_position()`
|
||||
*
|
||||
* @param e Pointer to the event structure from the callback
|
||||
* @param result Pointer to lv_3dpoint_t structure to store the rotation in radians (x, y, z)
|
||||
* @return LV_RESULT_OK if successful, LV_RESULT_INVALID if called outside event callback or if parameters are null
|
||||
*/
|
||||
lv_result_t lv_gltf_model_node_get_euler_rotation(lv_event_t * e, lv_3dpoint_t * result);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_MODEL_NODE_H*/
|
||||
115
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_uniform_locations.cpp
Normal file
115
inc/lvgl/src/libs/gltf/gltf_data/lv_gltf_uniform_locations.cpp
Normal file
@@ -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*/
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file lv_gltf_environment.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_ENVIRONMENT_H
|
||||
#define LV_GLTF_ENVIRONMENT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../misc/lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_GLTF_DEFAULT_CUBE_MAP_RESOLUTION 128
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create an IBL sampler for processing environment images
|
||||
* @return pointer to the created sampler, or NULL on failure
|
||||
* @note Can be safely deleted after environments are created
|
||||
*/
|
||||
lv_gltf_ibl_sampler_t * lv_gltf_ibl_sampler_create(void);
|
||||
|
||||
/**
|
||||
* Set the resolution for each cubemap face
|
||||
* @param pointer to a sampler
|
||||
* @param resolution of each cube map face in pixels (recommended: 64-512 for embedded)
|
||||
*/
|
||||
void lv_gltf_ibl_sampler_set_cube_map_pixel_resolution(lv_gltf_ibl_sampler_t * sampler, uint32_t resolution);
|
||||
|
||||
/**
|
||||
* Delete an IBL sampler
|
||||
* @param sampler pointer to the sampler to delete
|
||||
*/
|
||||
void lv_gltf_ibl_sampler_delete(lv_gltf_ibl_sampler_t * sampler);
|
||||
|
||||
/**
|
||||
* Create an environment from an HDR or JPEG panoramic image for IBL rendering
|
||||
* @param sampler IBL sampler defining output resolution (can be deleted after this call)
|
||||
* @param file_path path to equirectangular environment image, or NULL to use default embedded image
|
||||
* @return pointer to the created environment, or NULL on failure
|
||||
*
|
||||
* @note The source image will be downsampled to the sampler's texture_size
|
||||
* @note The environment can be shared across multiple glTF objects
|
||||
*/
|
||||
lv_gltf_environment_t * lv_gltf_environment_create(lv_gltf_ibl_sampler_t * sampler, const char * file_path);
|
||||
|
||||
/**
|
||||
* Set the rotation angle of the environment map
|
||||
* @param env pointer to the environment
|
||||
* @param angle rotation angle in degrees
|
||||
*/
|
||||
void lv_gltf_environment_set_angle(lv_gltf_environment_t * env, float angle);
|
||||
|
||||
/**
|
||||
* Delete an environment
|
||||
* @param environment pointer to the environment to delete
|
||||
*/
|
||||
void lv_gltf_environment_delete(lv_gltf_environment_t * environment);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_ENVIRONMENT_H*/
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file lv_gltf_environment_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_ENVIRONMENT_PRIVATE_H
|
||||
#define LV_GLTF_ENVIRONMENT_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "lv_gltf_environment.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_gltf_ibl_sampler {
|
||||
uint32_t cube_map_resolution;
|
||||
float lod_bias;
|
||||
uint32_t lowest_mip_level;
|
||||
uint32_t input_texture_id;
|
||||
uint32_t cube_map_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;
|
||||
|
||||
uint32_t fullscreen_vertex_buffer;
|
||||
uint32_t fullscreen_tex_coord_buffer;
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
struct _lv_gltf_environment {
|
||||
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;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_ENVIRONMENT_PRIVATE_H*/
|
||||
|
||||
655
inc/lvgl/src/libs/gltf/gltf_environment/lv_gltf_ibl_sampler.c
Normal file
655
inc/lvgl/src/libs/gltf/gltf_environment/lv_gltf_ibl_sampler.c
Normal file
@@ -0,0 +1,655 @@
|
||||
/**
|
||||
* @file lv_gltf_ibl_sampler.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_environment_private.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../../../misc/lv_math.h"
|
||||
#include "../../../misc/lv_log.h"
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#include "../../../drivers/opengles/lv_opengles_private.h"
|
||||
#include "../../../drivers/opengles/lv_opengles_debug.h"
|
||||
|
||||
#include "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../gltf_view/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 lv_result_t 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_cube_map_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(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_apply_filter(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_cube_map_to_lambertian(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_cube_map_to_ggx(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_cube_map_to_sheen(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void ibl_sample_lut(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 void init_fullscreen_quad(lv_gltf_ibl_sampler_t * sampler);
|
||||
static void draw_fullscreen_quad(lv_gltf_ibl_sampler_t * sampler, GLuint program_id);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static const lv_opengl_glsl_version_t GLSL_VERSIONS[] = {
|
||||
LV_OPENGL_GLSL_VERSION_300ES,
|
||||
LV_OPENGL_GLSL_VERSION_330,
|
||||
};
|
||||
static const size_t GLSL_VERSION_COUNT = sizeof(GLSL_VERSIONS) / sizeof(GLSL_VERSIONS[0]);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_gltf_ibl_sampler_t * lv_gltf_ibl_sampler_create(void)
|
||||
{
|
||||
lv_gltf_ibl_sampler_t * sampler = lv_zalloc(sizeof(*sampler));
|
||||
LV_ASSERT_MALLOC(sampler)
|
||||
if(!sampler) {
|
||||
LV_LOG_WARN("Failed to create sampler");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sampler->cube_map_resolution = LV_GLTF_DEFAULT_CUBE_MAP_RESOLUTION;
|
||||
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_opengl_shader_portions_t env_shader_portions;
|
||||
lv_gltf_view_shader_get_env(&env_shader_portions);
|
||||
lv_opengl_shader_manager_init(&sampler->shader_manager, env_shader_portions.all, env_shader_portions.count, NULL,
|
||||
NULL);
|
||||
init_fullscreen_quad(sampler);
|
||||
return sampler;
|
||||
}
|
||||
|
||||
void lv_gltf_ibl_sampler_set_cube_map_pixel_resolution(lv_gltf_ibl_sampler_t * sampler, uint32_t resolution)
|
||||
{
|
||||
if(!sampler) {
|
||||
LV_LOG_WARN("Can't set cube map resolution on a NULL sampler");
|
||||
return;
|
||||
}
|
||||
if(resolution == 0) {
|
||||
LV_LOG_WARN("Cube map resolution should be > 0");
|
||||
return;
|
||||
}
|
||||
sampler->cube_map_resolution = resolution;
|
||||
}
|
||||
|
||||
void lv_gltf_ibl_sampler_delete(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
if(!sampler) {
|
||||
LV_LOG_WARN("Can't delete a NULL sampler");
|
||||
return;
|
||||
}
|
||||
|
||||
ibl_sampler_destroy(sampler);
|
||||
lv_free(sampler);
|
||||
}
|
||||
|
||||
void lv_gltf_environment_set_angle(lv_gltf_environment_t * env, float angle)
|
||||
{
|
||||
if(!env) {
|
||||
LV_LOG_WARN("Can't set angle on a NULL environment");
|
||||
return;
|
||||
}
|
||||
env->angle = angle;
|
||||
}
|
||||
|
||||
lv_gltf_environment_t * lv_gltf_environment_create(lv_gltf_ibl_sampler_t * sampler, const char * file_path)
|
||||
{
|
||||
if(!sampler) {
|
||||
LV_LOG_WARN("Can't create an environment with a NULL sampler");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_gltf_environment_t * env = lv_zalloc(sizeof(*env));
|
||||
LV_ASSERT_MALLOC(env);
|
||||
if(!env) {
|
||||
LV_LOG_WARN("Failed to create environment");
|
||||
return NULL;
|
||||
}
|
||||
if(ibl_sampler_load(sampler, file_path) != LV_RESULT_OK) {
|
||||
LV_LOG_WARN("Failed to initialize ibl sampler");
|
||||
lv_free(env);
|
||||
return NULL;
|
||||
}
|
||||
ibl_sampler_filter(sampler);
|
||||
|
||||
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;
|
||||
return env;
|
||||
}
|
||||
|
||||
void lv_gltf_environment_delete(lv_gltf_environment_t * env)
|
||||
{
|
||||
const unsigned int d[3] = { env->diffuse, env->specular, env->sheen };
|
||||
GL_CALL(glDeleteTextures(3, d));
|
||||
lv_free(env);
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_result_t 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 = NULL;
|
||||
if(path) {
|
||||
data = stbi_loadf(path, &src_width, &src_height, &src_nrChannels, 3);
|
||||
}
|
||||
|
||||
if(!data) {
|
||||
if(path) {
|
||||
LV_LOG_WARN("Failed to load environment image. Falling back to default");
|
||||
}
|
||||
extern unsigned char chromatic_jpg[];
|
||||
extern unsigned int chromatic_jpg_len;
|
||||
data = stbi_loadf_from_memory(chromatic_jpg, chromatic_jpg_len, &src_width, &src_height, &src_nrChannels, 3);
|
||||
if(!data) {
|
||||
LV_LOG_ERROR("Failed to load fallback env image");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
lv_gltf_ibl_image_t panorama_image = {
|
||||
.data = data,
|
||||
.data_len = src_width * src_height * 3,
|
||||
.width = src_width,
|
||||
.height = src_height,
|
||||
};
|
||||
|
||||
sampler->input_texture_id = ibl_load_texture_hdr(sampler, &panorama_image);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
GL_CALL(glGenFramebuffers(1, &sampler->framebuffer));
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, sampler->framebuffer));
|
||||
|
||||
sampler->cube_map_texture_id = ibl_create_cube_map_texture(sampler, true);
|
||||
sampler->lambertian_texture_id = ibl_create_cube_map_texture(sampler, false);
|
||||
sampler->ggx_texture_id = ibl_create_cube_map_texture(sampler, true);
|
||||
sampler->sheen_texture_id = ibl_create_cube_map_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->cube_map_resolution) + 1 - sampler->lowest_mip_level;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
static void ibl_sampler_filter(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
GLint prev_framebuffer;
|
||||
GLint prev_viewport[4];
|
||||
GLint prev_program;
|
||||
GLint prev_texture_2d;
|
||||
GLint prev_texture_cube;
|
||||
GLint prev_active_texture;
|
||||
|
||||
GL_CALL(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_framebuffer));
|
||||
GL_CALL(glGetIntegerv(GL_VIEWPORT, prev_viewport));
|
||||
GL_CALL(glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program));
|
||||
GL_CALL(glGetIntegerv(GL_ACTIVE_TEXTURE, &prev_active_texture));
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_texture_2d));
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &prev_texture_cube));
|
||||
|
||||
ibl_panorama_to_cubemap(sampler);
|
||||
ibl_cube_map_to_lambertian(sampler);
|
||||
ibl_cube_map_to_ggx(sampler);
|
||||
ibl_cube_map_to_sheen(sampler);
|
||||
ibl_sample_ggx_lut(sampler);
|
||||
ibl_sample_charlie_lut(sampler);
|
||||
|
||||
// Restore all GL state
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, prev_framebuffer));
|
||||
GL_CALL(glViewport(prev_viewport[0], prev_viewport[1], prev_viewport[2], prev_viewport[3]));
|
||||
GL_CALL(glUseProgram(prev_program));
|
||||
GL_CALL(glActiveTexture(prev_active_texture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, prev_texture_2d));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, prev_texture_cube));
|
||||
}
|
||||
static void ibl_sampler_destroy(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
if(sampler->framebuffer != 0) {
|
||||
GL_CALL(glDeleteFramebuffers(1, &sampler->framebuffer));
|
||||
sampler->framebuffer = 0;
|
||||
}
|
||||
|
||||
if(sampler->input_texture_id != 0) {
|
||||
GL_CALL(glDeleteTextures(1, &sampler->input_texture_id));
|
||||
sampler->input_texture_id = 0;
|
||||
}
|
||||
|
||||
if(sampler->cube_map_texture_id != 0) {
|
||||
GL_CALL(glDeleteTextures(1, &sampler->cube_map_texture_id));
|
||||
sampler->cube_map_texture_id = 0;
|
||||
}
|
||||
|
||||
GL_CALL(glDeleteBuffers(1, &sampler->fullscreen_vertex_buffer));
|
||||
GL_CALL(glDeleteBuffers(1, &sampler->fullscreen_tex_coord_buffer));
|
||||
lv_opengl_shader_manager_deinit(&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_cube_map_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->cube_map_resolution,
|
||||
sampler->cube_map_resolution, 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(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->cube_map_texture_id, 0));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_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->cube_map_resolution, sampler->cube_map_resolution));
|
||||
GL_CALL(glClearColor(1.0, 0.0, 0.0, 0.0));
|
||||
GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
lv_opengl_shader_params_t frag_shader = {.name = "panorama_to_cubemap.frag"};
|
||||
lv_opengl_shader_params_t vert_shader = {.name = "fullscreen.vert"};
|
||||
lv_opengl_shader_program_t * program = lv_opengl_shader_manager_compile_program_best_version(&sampler->shader_manager,
|
||||
&frag_shader, &vert_shader,
|
||||
GLSL_VERSIONS,
|
||||
GLSL_VERSION_COUNT);
|
||||
|
||||
LV_ASSERT_MSG(program != NULL,
|
||||
"Failed to link program. This probably means your platform doesn't support a required GLSL version");
|
||||
|
||||
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
|
||||
draw_fullscreen_quad(sampler, program_id);
|
||||
}
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, sampler->cube_map_texture_id));
|
||||
GL_CALL(glGenerateMipmap(GL_TEXTURE_CUBE_MAP));
|
||||
}
|
||||
static void ibl_apply_filter(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->cube_map_resolution >> 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));
|
||||
|
||||
lv_opengl_shader_params_t frag_shader = {.name = "ibl_filtering.frag"};
|
||||
lv_opengl_shader_params_t vert_shader = {.name = "fullscreen.vert"};
|
||||
lv_opengl_shader_program_t * program =
|
||||
lv_opengl_shader_manager_compile_program_best_version(&sampler->shader_manager, &frag_shader, &vert_shader,
|
||||
GLSL_VERSIONS,
|
||||
GLSL_VERSION_COUNT);
|
||||
LV_ASSERT_MSG(program != NULL,
|
||||
"Failed to link program. This probably means your platform doesn't support a required GLSL version");
|
||||
|
||||
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->cube_map_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->cube_map_resolution);
|
||||
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
|
||||
draw_fullscreen_quad(sampler, program_id);
|
||||
}
|
||||
}
|
||||
static void ibl_cube_map_to_lambertian(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_cube_map_to_ggx(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_cube_map_to_sheen(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(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));
|
||||
|
||||
lv_opengl_shader_params_t frag_shader = {.name = "ibl_filtering.frag"};
|
||||
lv_opengl_shader_params_t vert_shader = {.name = "fullscreen.vert"};
|
||||
lv_opengl_shader_program_t * program =
|
||||
lv_opengl_shader_manager_compile_program_best_version(&sampler->shader_manager, &frag_shader, &vert_shader,
|
||||
GLSL_VERSIONS,
|
||||
GLSL_VERSION_COUNT);
|
||||
LV_ASSERT_MSG(program != NULL,
|
||||
"Failed to link program. This probably means your platform doesn't support a required GLSL version");
|
||||
|
||||
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->cube_map_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
|
||||
draw_fullscreen_quad(sampler, program_id);
|
||||
}
|
||||
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)
|
||||
{
|
||||
const GLubyte * extensions = glGetString(GL_EXTENSIONS);
|
||||
if(!extensions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * ext_str = (const char *)extensions;
|
||||
const char * current = ext_str;
|
||||
const char * next;
|
||||
|
||||
while(*current) {
|
||||
/* Find the next space or end of string */
|
||||
next = strchr(current, ' ');
|
||||
if(next) {
|
||||
size_t length = next - current;
|
||||
if(length == strlen(extension) && strncmp(current, extension, length) == 0) {
|
||||
return true;
|
||||
}
|
||||
current = next + 1;
|
||||
}
|
||||
else {
|
||||
/* Last extension (no space found) */
|
||||
if(strcmp(current, extension) == 0) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ibl_count_bits(int value)
|
||||
{
|
||||
int count = 0;
|
||||
while(value > 1) {
|
||||
value >>= 1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void init_fullscreen_quad(lv_gltf_ibl_sampler_t * sampler)
|
||||
{
|
||||
/* Vertices go from -1 -1 (left bottom) to 1 1 (right top)*/
|
||||
GLfloat vertices[] = {
|
||||
-1.0f, -1.0f,
|
||||
1.0f, -1.0f,
|
||||
-1.0f, 1.0f,
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
/* Texture coords go from 0 0 (left botton) to 1 1 (right top)*/
|
||||
GLfloat texCoords[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
GL_CALL(glGenBuffers(1, &sampler->fullscreen_vertex_buffer));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, sampler->fullscreen_vertex_buffer));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
|
||||
|
||||
GL_CALL(glGenBuffers(1, &sampler->fullscreen_tex_coord_buffer));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, sampler->fullscreen_tex_coord_buffer));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
static void draw_fullscreen_quad(lv_gltf_ibl_sampler_t * sampler, GLuint program_id)
|
||||
{
|
||||
GLuint positionAttrib = glGetAttribLocation(program_id, "aPosition");
|
||||
GL_CALL(glEnableVertexAttribArray(positionAttrib));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, sampler->fullscreen_vertex_buffer));
|
||||
GL_CALL(glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void *)0));
|
||||
|
||||
GLuint texCoordAttrib = glGetAttribLocation(program_id, "aTexCoord");
|
||||
GL_CALL(glEnableVertexAttribArray(texCoordAttrib));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, sampler->fullscreen_tex_coord_buffer));
|
||||
GL_CALL(glVertexAttribPointer(texCoordAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void *)0));
|
||||
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||
|
||||
GL_CALL(glDisableVertexAttribArray(positionAttrib));
|
||||
GL_CALL(glDisableVertexAttribArray(texCoordAttrib));
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
7545
inc/lvgl/src/libs/gltf/gltf_view/assets/chromatic.c
Normal file
7545
inc/lvgl/src/libs/gltf/gltf_view/assets/chromatic.c
Normal file
File diff suppressed because it is too large
Load Diff
3522
inc/lvgl/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c
Normal file
3522
inc/lvgl/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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 "../../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
/**********************
|
||||
* 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_opengl_shader_portions_t *shaders);
|
||||
void lv_gltf_view_shader_get_env(lv_opengl_shader_portions_t *shaders);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GLTF_VIEW_SHADER_H*/
|
||||
421
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf.h
Normal file
421
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf.h
Normal file
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* @file lv_gltf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_H
|
||||
#define LV_GLTF_H
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../math/lv_3dmath.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../misc/lv_area.h"
|
||||
#include "../gltf_data/lv_gltf_model.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#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
|
||||
#define LV_GLTF_DEFAULT_CAMERA 0
|
||||
|
||||
/**********************
|
||||
* 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;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create a glTF object
|
||||
* @param parent pointer to the parent object
|
||||
* @return pointer to the created glTF object
|
||||
*/
|
||||
lv_obj_t * lv_gltf_create(lv_obj_t * parent);
|
||||
|
||||
/**
|
||||
* Assign an environment to a glTF object for IBL rendering
|
||||
* @param obj pointer to a glTF viewer object
|
||||
* @param environment pointer to the environment to use
|
||||
* @note The environment can be shared across multiple glTF objects
|
||||
* @note If no environment is set before attempting to load a file,
|
||||
* a default one will be created for you
|
||||
*/
|
||||
void lv_gltf_set_environment(lv_obj_t * obj, lv_gltf_environment_t * environment);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Load a glTF model from a byte array into the viewer
|
||||
* @param obj pointer to a glTF viewer object
|
||||
* @param bytes glTF raw data
|
||||
* @param len glTF raw data length in bytes
|
||||
* @return pointer to the loaded glTF model, or NULL on failure
|
||||
*/
|
||||
lv_gltf_model_t * lv_gltf_load_model_from_bytes(lv_obj_t * obj, const uint8_t * bytes, size_t len);
|
||||
|
||||
/**
|
||||
* 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 scale factor from the focal point
|
||||
* @param obj pointer to a glTF viewer object
|
||||
* @return distance scaling factor value
|
||||
*/
|
||||
float lv_gltf_get_distance(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the camera distance from the focal point in world units
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @return world unit distance value
|
||||
*/
|
||||
float lv_gltf_get_world_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);
|
||||
|
||||
/***********************
|
||||
* Raycasting Functions
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* Get the point that a given ray intersects with a specified plane at, if any
|
||||
* @param ray the intersection test ray
|
||||
* @param screen_y the plane to test ray intersection with
|
||||
* @param collision_point output lv_3dpoint_t holder, values are only valid if true is the return value
|
||||
* @return LV_RESULT_OK if intersection, LV_RESULT_INVALID if no intersection
|
||||
*/
|
||||
lv_result_t lv_intersect_ray_with_plane(const lv_3dray_t * ray, const lv_3dplane_t * plane,
|
||||
lv_3dpoint_t * collision_point);
|
||||
|
||||
/**
|
||||
* Get a plane that faces the current view camera, centered some units in front of it
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param distance distance in front of the camera to set the plane, in world units. see lv_gltf_get_world_distance to get the auto-distance
|
||||
* @return camera facing plane
|
||||
*/
|
||||
lv_3dplane_t lv_gltf_get_current_view_plane(lv_obj_t * obj, float distance);
|
||||
|
||||
/**
|
||||
* Calculates a ray originating from the camera and passing through the specified mouse position on the screen.
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param screen_pos screen co-ordinate, in pixels
|
||||
* @return mouse point ray
|
||||
*/
|
||||
lv_3dray_t lv_gltf_get_ray_from_2d_coordinate(lv_obj_t * obj, const lv_point_t * screen_pos);
|
||||
|
||||
|
||||
/**
|
||||
* Get the screen position of a 3d point
|
||||
* @param obj pointer to a GLTF viewer object
|
||||
* @param world_pos world position to convert
|
||||
* @param lv_point_t the resulting point, in pixels. only valid if return value is true
|
||||
* @return LV_RESULT_OK if conversion valid, LV_RESULT_INVALID if no valid conversion
|
||||
*/
|
||||
lv_result_t lv_gltf_world_to_screen(lv_obj_t * obj, const lv_3dpoint_t world_pos, lv_point_t * screen_pos);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#endif /*LV_GLTF_H*/
|
||||
863
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view.cpp
Normal file
863
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view.cpp
Normal file
@@ -0,0 +1,863 @@
|
||||
/**
|
||||
* @file lv_gltf_view.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_gltf_view_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include "../gltf_data/lv_gltf_model.h"
|
||||
#include "../gltf_data/lv_gltf_data_internal.hpp"
|
||||
#include "../../../draw/lv_draw_3d.h"
|
||||
#include "../fastgltf/lv_fastgltf.hpp"
|
||||
#include "../../../core/lv_obj_class_private.h"
|
||||
#include "../../../misc/lv_types.h"
|
||||
#include "../../../widgets/3dtexture/lv_3dtexture.h"
|
||||
#include "../gltf_environment/lv_gltf_environment.h"
|
||||
#include "assets/lv_gltf_view_shader.h"
|
||||
#include <fastgltf/math.hpp>
|
||||
#include <fastgltf/tools.hpp>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
|
||||
#define MY_CLASS (&lv_gltf_class)
|
||||
|
||||
#ifndef LV_GLTF_INITIAL_MODEL_CAPACITY
|
||||
#define LV_GLTF_INITIAL_MODEL_CAPACITY 1
|
||||
#endif /*LV_GLTF_INITIAL_MODEL_CAPACITY*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static lv_gltf_model_t * lv_gltf_add_model(lv_gltf_t * viewer, lv_gltf_model_t * model);
|
||||
static void lv_gltf_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
static void lv_gltf_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
||||
static void lv_gltf_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||
static void lv_gltf_view_state_init(lv_gltf_t * state);
|
||||
static void lv_gltf_view_desc_init(lv_gltf_view_desc_t * state);
|
||||
static void lv_gltf_parse_model(lv_gltf_t * viewer, lv_gltf_model_t * model);
|
||||
static void setup_compile_and_load_bg_shader(lv_opengl_shader_manager_t * manager);
|
||||
static void setup_background_environment(GLuint program, GLuint * vao, GLuint * indexBuffer, GLuint * vertexBuffer);
|
||||
|
||||
static lv_result_t create_default_environment(lv_gltf_t * gltf);
|
||||
|
||||
static void display_refr_end_event_cb(lv_event_t * e);
|
||||
|
||||
const lv_obj_class_t lv_gltf_class {
|
||||
&lv_3dtexture_class,
|
||||
lv_gltf_constructor,
|
||||
lv_gltf_destructor,
|
||||
lv_gltf_event,
|
||||
#if LV_USE_OBJ_PROPERTY
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
#endif
|
||||
NULL,
|
||||
"lv_gltf",
|
||||
LV_DPI_DEF * 2,
|
||||
LV_DPI_DEF / 10,
|
||||
LV_OBJ_CLASS_EDITABLE_INHERIT,
|
||||
LV_OBJ_CLASS_GROUP_DEF_INHERIT,
|
||||
sizeof(lv_gltf_t),
|
||||
LV_OBJ_CLASS_THEME_INHERITABLE_FALSE
|
||||
};
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static const lv_opengl_glsl_version_t GLSL_VERSIONS[] {
|
||||
LV_OPENGL_GLSL_VERSION_300ES,
|
||||
LV_OPENGL_GLSL_VERSION_330,
|
||||
};
|
||||
static const size_t GLSL_VERSION_COUNT = sizeof(GLSL_VERSIONS) / sizeof(GLSL_VERSIONS[0]);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_obj_t * lv_gltf_create(lv_obj_t * parent)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
lv_display_t * disp = lv_obj_get_display(obj);
|
||||
LV_ASSERT_NULL(disp);
|
||||
lv_display_add_event_cb(disp, display_refr_end_event_cb, LV_EVENT_REFR_READY, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
lv_gltf_model_t * lv_gltf_load_model_from_file(lv_obj_t * obj, const char * path)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(!viewer->environment) {
|
||||
lv_result_t res = create_default_environment(viewer);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lv_gltf_model_t * model = lv_gltf_data_load_from_file(path, &viewer->shader_manager);
|
||||
return lv_gltf_add_model(viewer, model);
|
||||
}
|
||||
|
||||
lv_gltf_model_t * lv_gltf_load_model_from_bytes(lv_obj_t * obj, const uint8_t * bytes, size_t len)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(!viewer->environment) {
|
||||
lv_result_t res = create_default_environment(viewer);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lv_gltf_model_t * model = lv_gltf_data_load_from_bytes(bytes, len, &viewer->shader_manager);
|
||||
return lv_gltf_add_model(viewer, model);
|
||||
}
|
||||
void lv_gltf_set_environment(lv_obj_t * obj, lv_gltf_environment_t * env)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * gltf = (lv_gltf_t *)obj;
|
||||
if(env == NULL) {
|
||||
LV_LOG_WARN("Refusing to assign a NULL environment to the glTF object");
|
||||
return;
|
||||
}
|
||||
|
||||
if(gltf->environment && gltf->owns_environment) {
|
||||
lv_gltf_environment_delete(gltf->environment);
|
||||
gltf->environment = NULL;
|
||||
}
|
||||
gltf->environment = env;
|
||||
gltf->owns_environment = false;
|
||||
}
|
||||
|
||||
size_t lv_gltf_get_model_count(lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
return lv_array_size(&((lv_gltf_t *)obj)->models);
|
||||
}
|
||||
|
||||
lv_gltf_model_t * lv_gltf_get_model_by_index(lv_obj_t * obj, size_t id)
|
||||
{
|
||||
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *) obj;
|
||||
|
||||
if(id >= lv_array_size(&viewer->models)) {
|
||||
return NULL;
|
||||
}
|
||||
return *(lv_gltf_model_t **)lv_array_at(&((lv_gltf_t *)obj)->models, id);
|
||||
|
||||
}
|
||||
lv_gltf_model_t * lv_gltf_get_primary_model(lv_obj_t * obj)
|
||||
{
|
||||
|
||||
return lv_gltf_get_model_by_index(obj, 0);
|
||||
}
|
||||
|
||||
void lv_gltf_set_yaw(lv_obj_t * obj, float yaw)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.yaw = yaw;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_yaw(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.yaw;
|
||||
}
|
||||
|
||||
void lv_gltf_set_pitch(lv_obj_t * obj, float pitch)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.pitch = pitch;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_pitch(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.pitch;
|
||||
}
|
||||
|
||||
void lv_gltf_set_fov(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.fov = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_fov(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.fov;
|
||||
}
|
||||
|
||||
void lv_gltf_set_distance(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.distance = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_distance(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.distance;
|
||||
}
|
||||
|
||||
float lv_gltf_get_world_distance(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
lv_gltf_view_desc_t * view_desc = &viewer->desc;
|
||||
if(viewer->models.size == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
lv_gltf_model_t * model = *(lv_gltf_model_t **)lv_array_at(&viewer->models, 0);
|
||||
return (lv_gltf_data_get_radius(model) * LV_GLTF_DISTANCE_SCALE_FACTOR) * view_desc->distance;
|
||||
}
|
||||
|
||||
void lv_gltf_set_animation_speed(lv_obj_t * obj, uint32_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.animation_speed_ratio = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
uint32_t lv_gltf_get_animation_speed(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.animation_speed_ratio;
|
||||
}
|
||||
|
||||
void lv_gltf_set_focal_x(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.focal_x = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_focal_x(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.focal_x;
|
||||
}
|
||||
|
||||
void lv_gltf_set_focal_y(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.focal_y = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_focal_y(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.focal_y;
|
||||
}
|
||||
|
||||
void lv_gltf_set_focal_z(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.focal_z = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_focal_z(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.focal_z;
|
||||
}
|
||||
|
||||
void lv_gltf_set_camera(lv_obj_t * obj, uint32_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(lv_array_is_empty(&viewer->models)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_gltf_model_t * model = *(lv_gltf_model_t **) lv_array_at(&viewer->models, 0);
|
||||
|
||||
if(value > model->asset.cameras.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
model->camera = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
uint32_t lv_gltf_get_camera(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(lv_array_is_empty(&viewer->models)) {
|
||||
return 0;
|
||||
}
|
||||
const lv_gltf_model_t * model = *(const lv_gltf_model_t **)lv_array_at(&viewer->models, 0);
|
||||
return model->camera;
|
||||
}
|
||||
|
||||
uint32_t lv_gltf_get_camera_count(const lv_obj_t * obj)
|
||||
{
|
||||
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(lv_array_is_empty(&viewer->models)) {
|
||||
return 0;
|
||||
}
|
||||
const lv_gltf_model_t * model = *(const lv_gltf_model_t **) lv_array_at(&viewer->models, 0);
|
||||
return lv_gltf_model_get_camera_count(model);
|
||||
}
|
||||
|
||||
void lv_gltf_set_antialiasing_mode(lv_obj_t * obj, lv_gltf_aa_mode_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.aa_mode = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
lv_gltf_aa_mode_t lv_gltf_get_antialiasing_mode(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.aa_mode;
|
||||
}
|
||||
|
||||
void lv_gltf_set_background_mode(lv_obj_t * obj, lv_gltf_bg_mode_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.bg_mode = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
lv_gltf_bg_mode_t lv_gltf_get_background_mode(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.bg_mode;
|
||||
}
|
||||
|
||||
void lv_gltf_set_background_blur(lv_obj_t * obj, uint32_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
if(value > 100) {
|
||||
value = 100;
|
||||
}
|
||||
viewer->desc.blur_bg = value / 100.f;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
uint32_t lv_gltf_get_background_blur(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.blur_bg * 100;
|
||||
}
|
||||
|
||||
void lv_gltf_set_env_brightness(lv_obj_t * obj, uint32_t value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.env_pow = value / 100.;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
uint32_t lv_gltf_get_env_brightness(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.env_pow * 100;
|
||||
}
|
||||
|
||||
void lv_gltf_set_image_exposure(lv_obj_t * obj, float value)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
viewer->desc.exposure = value;
|
||||
lv_obj_invalidate(obj);
|
||||
}
|
||||
|
||||
float lv_gltf_get_image_exposure(const lv_obj_t * obj)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
return viewer->desc.exposure;
|
||||
}
|
||||
void lv_gltf_recenter(lv_obj_t * obj, lv_gltf_model_t * model)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
if(model == NULL) {
|
||||
LV_ASSERT(lv_array_size(&viewer->models) > 0);
|
||||
model = *(lv_gltf_model_t **)lv_array_at(&viewer->models, 0);
|
||||
}
|
||||
|
||||
const auto & center_position = lv_gltf_data_get_center(model);
|
||||
viewer->desc.focal_x = center_position[0];
|
||||
viewer->desc.focal_y = center_position[1];
|
||||
viewer->desc.focal_z = center_position[2];
|
||||
}
|
||||
|
||||
lv_3dray_t lv_gltf_get_ray_from_2d_coordinate(lv_obj_t * obj, const lv_point_t * screen_pos)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
float norm_mouse_x = (float)screen_pos->x / (float)(lv_obj_get_width(obj));
|
||||
float norm_mouse_y = (float)screen_pos->y / (float)(lv_obj_get_height(obj));
|
||||
|
||||
lv_3dray_t outray {{0, 0, 0}, {0, 0, 0}};
|
||||
|
||||
fastgltf::math::fmat4x4 proj_mat = fastgltf::math::inverse(fastgltf::math::fmat4x4(viewer->projection_matrix));
|
||||
|
||||
/* Convert mouse coordinates to NDC */
|
||||
float x = norm_mouse_x * 2.0f - 1.0f;
|
||||
float y = 1.0f - (norm_mouse_y * 2.0f);
|
||||
float z = -1.0f; /* Clip space z */
|
||||
|
||||
fastgltf::math::fvec4 clip_space_pos = fastgltf::math::fvec4(x, y, z, 1.f);
|
||||
auto ray_eye = (proj_mat) * clip_space_pos;
|
||||
ray_eye[2] = -1.0f;
|
||||
ray_eye[3] = 0.0f;
|
||||
|
||||
/* Calculate ray world direction */
|
||||
fastgltf::math::fvec4 ray_world = fastgltf::math::inverse(viewer->view_matrix) * ray_eye;
|
||||
auto ray_direction = fastgltf::math::normalize(fastgltf::math::fvec3(ray_world[0], ray_world[1], ray_world[2]));
|
||||
|
||||
outray.direction = {ray_direction[0], ray_direction[1], ray_direction[2]};
|
||||
outray.origin = {viewer->camera_pos[0], viewer->camera_pos[1], viewer->camera_pos[2]};
|
||||
|
||||
return outray;
|
||||
}
|
||||
|
||||
lv_result_t lv_intersect_ray_with_plane(const lv_3dray_t * ray, const lv_3dplane_t * plane,
|
||||
lv_3dpoint_t * collision_point)
|
||||
{
|
||||
fastgltf::math::fvec3 plane_center = fastgltf::math::fvec3(plane->origin.x, plane->origin.y, plane->origin.z);
|
||||
fastgltf::math::fvec3 plane_normal = fastgltf::math::fvec3(plane->direction.x, plane->direction.y, plane->direction.z);
|
||||
fastgltf::math::fvec3 ray_start = fastgltf::math::fvec3(ray->origin.x, ray->origin.y, ray->origin.z);
|
||||
fastgltf::math::fvec3 ray_direction = fastgltf::math::fvec3(ray->direction.x, ray->direction.y, ray->direction.z);
|
||||
|
||||
float denom = fastgltf::math::dot(plane_normal, ray_direction);
|
||||
if(fabs(denom) > 1e-6) { /* Check if the ray is not parallel to the plane */
|
||||
fastgltf::math::fvec3 diff = plane_center - ray_start;
|
||||
float t = fastgltf::math::dot(diff, plane_normal) / denom;
|
||||
|
||||
if(t >= 0) { /* Intersection occurs ahead of the ray origin */
|
||||
/* Calculate the collision point */
|
||||
(*collision_point).x = ray_start[0] + t * ray_direction[0];
|
||||
(*collision_point).y = ray_start[1] + t * ray_direction[1];
|
||||
(*collision_point).z = ray_start[2] + t * ray_direction[2];
|
||||
return LV_RESULT_OK; /* Collision point found */
|
||||
}
|
||||
}
|
||||
return LV_RESULT_INVALID; /* No intersection */
|
||||
}
|
||||
|
||||
lv_3dplane_t lv_gltf_get_current_view_plane(lv_obj_t * obj, float distance)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
lv_3dplane_t outplane = {{0, 0, 0}, {0, 0, 0}};
|
||||
|
||||
/* Forward vector is the third column of the matrix */
|
||||
auto forward = fastgltf::math::fvec3(viewer->view_matrix[0][2], viewer->view_matrix[1][2], viewer->view_matrix[2][2]);
|
||||
forward = fastgltf::math::normalize(forward);
|
||||
|
||||
/* Calculate the plane center */
|
||||
const auto & camera_pos = viewer->camera_pos;
|
||||
auto plane_pos = fastgltf::math::fvec3(camera_pos[0], camera_pos[1], camera_pos[2]) - forward * distance;
|
||||
outplane.origin = {plane_pos[0], plane_pos[1], plane_pos[2]};
|
||||
outplane.direction = {-forward[0], -forward[1], -forward[2]};
|
||||
return outplane;
|
||||
}
|
||||
|
||||
lv_result_t lv_gltf_world_to_screen(lv_obj_t * obj, const lv_3dpoint_t world_pos, lv_point_t * screen_pos)
|
||||
{
|
||||
LV_ASSERT_NULL(obj);
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
fastgltf::math::fvec4 world_position_h = fastgltf::math::fvec4(world_pos.x, world_pos.y, world_pos.z, 1.0f);
|
||||
fastgltf::math::fvec4 clip_space_pos = viewer->projection_matrix * viewer->view_matrix * world_position_h;
|
||||
|
||||
/* Check for perspective division (w must not be zero) */
|
||||
if(clip_space_pos[3] == 0.0f) {
|
||||
screen_pos->x = -1;
|
||||
screen_pos->y = -1;
|
||||
return LV_RESULT_INVALID; /* Position is not valid for screen mapping */
|
||||
}
|
||||
|
||||
clip_space_pos /= clip_space_pos[3];
|
||||
float norm_screen_x = clip_space_pos[0] * 0.5f + 0.5f;
|
||||
float norm_screen_y = 0.5f - (clip_space_pos[1] * 0.5f);
|
||||
int32_t win_width = lv_obj_get_width(obj);
|
||||
int32_t win_height = lv_obj_get_height(obj);
|
||||
screen_pos->x = norm_screen_x * win_width;
|
||||
screen_pos->y = norm_screen_y * win_height;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_gltf_model_t * lv_gltf_add_model(lv_gltf_t * viewer, lv_gltf_model_t * model)
|
||||
{
|
||||
if(!model) {
|
||||
return NULL;
|
||||
}
|
||||
if(lv_array_push_back(&viewer->models, &model) == LV_RESULT_INVALID) {
|
||||
lv_gltf_data_delete(model);
|
||||
return NULL;
|
||||
}
|
||||
model->viewer = viewer;
|
||||
lv_gltf_parse_model(viewer, model);
|
||||
|
||||
|
||||
if(lv_array_size(&viewer->models) == 1) {
|
||||
lv_gltf_recenter((lv_obj_t *)viewer, model);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
static lv_result_t create_default_environment(lv_gltf_t * gltf)
|
||||
{
|
||||
lv_gltf_ibl_sampler_t * sampler = lv_gltf_ibl_sampler_create();
|
||||
gltf->environment = lv_gltf_environment_create(sampler, NULL);
|
||||
lv_gltf_ibl_sampler_delete(sampler);
|
||||
if(!gltf->environment) {
|
||||
LV_LOG_WARN("Failed to create default gltf environment");
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
gltf->owns_environment = true;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
static void lv_gltf_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
LV_UNUSED(class_p);
|
||||
LV_TRACE_OBJ_CREATE("begin");
|
||||
lv_gltf_t * view = (lv_gltf_t *)obj;
|
||||
lv_gltf_view_state_init(view);
|
||||
lv_gltf_view_desc_init(&view->desc);
|
||||
view->view_matrix = fastgltf::math::fmat4x4(1.0f);
|
||||
view->projection_matrix = fastgltf::math::fmat4x4(1.0f);
|
||||
view->view_projection_matrix = fastgltf::math::fmat4x4(1.0f);
|
||||
view->camera_pos = fastgltf::math::fvec3(0.0f);
|
||||
view->texture.h_flip = false;
|
||||
view->texture.v_flip = true;
|
||||
new(&view->ibm_by_skin_then_node) std::map<int32_t, std::map<fastgltf::Node *, fastgltf::math::fmat4x4>>;
|
||||
|
||||
lv_opengl_shader_portions_t portions;
|
||||
lv_gltf_view_shader_get_src(&portions);
|
||||
char * vertex_shader = lv_gltf_view_shader_get_vertex();
|
||||
char * frag_shader = lv_gltf_view_shader_get_fragment();
|
||||
lv_opengl_shader_manager_init(&view->shader_manager, portions.all, portions.count, vertex_shader, frag_shader);
|
||||
lv_free(vertex_shader);
|
||||
lv_free(frag_shader);
|
||||
|
||||
lv_array_init(&view->models, LV_GLTF_INITIAL_MODEL_CAPACITY, sizeof(lv_gltf_model_t *));
|
||||
|
||||
LV_TRACE_OBJ_CREATE("end");
|
||||
}
|
||||
|
||||
static void lv_gltf_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
{
|
||||
LV_UNUSED(class_p);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * obj = (lv_obj_t *)lv_event_get_current_target(e);
|
||||
lv_gltf_t * viewer = (lv_gltf_t *)obj;
|
||||
|
||||
if(code == LV_EVENT_DRAW_MAIN) {
|
||||
GLuint texture_id = lv_gltf_view_render(viewer);
|
||||
lv_3dtexture_set_src((lv_obj_t *)&viewer->texture, (lv_3dtexture_id_t)texture_id);
|
||||
}
|
||||
|
||||
lv_result_t res;
|
||||
|
||||
/*Call the ancestor's event handler*/
|
||||
res = lv_obj_event_base(MY_CLASS, e);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
static void lv_gltf_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
{
|
||||
LV_UNUSED(class_p);
|
||||
lv_gltf_t * view = (lv_gltf_t *)obj;
|
||||
lv_opengl_shader_manager_deinit(&view->shader_manager);
|
||||
using IbmBySkinThenNodeMap = std::map<int32_t, std::map<fastgltf::Node *, fastgltf::math::fmat4x4>>;
|
||||
|
||||
view->ibm_by_skin_then_node.~IbmBySkinThenNodeMap();
|
||||
const size_t n = lv_array_size(&view->models);
|
||||
for(size_t i = 0; i < n; ++i) {
|
||||
lv_gltf_data_delete(*(lv_gltf_model_t **)lv_array_at(&view->models, i));
|
||||
}
|
||||
lv_array_deinit(&view->models);
|
||||
if(view->environment && view->owns_environment) {
|
||||
lv_gltf_environment_delete(view->environment);
|
||||
}
|
||||
lv_display_t * disp = lv_obj_get_display(obj);
|
||||
LV_ASSERT_NULL(disp);
|
||||
lv_display_remove_event_cb_with_user_data(disp, display_refr_end_event_cb, obj);
|
||||
}
|
||||
|
||||
static void lv_gltf_view_state_init(lv_gltf_t * view)
|
||||
{
|
||||
lv_memset(&view->state, 0, sizeof(view->state));
|
||||
view->state.opaque_frame_buffer_width = LV_GLTF_TRANSMISSION_PASS_SIZE;
|
||||
view->state.opaque_frame_buffer_height = LV_GLTF_TRANSMISSION_PASS_SIZE;
|
||||
view->state.material_variant = 0;
|
||||
view->state.render_state_ready = false;
|
||||
view->state.render_opaque_buffer = false;
|
||||
}
|
||||
static void lv_gltf_view_desc_init(lv_gltf_view_desc_t * desc)
|
||||
{
|
||||
lv_memset(desc, 0, sizeof(*desc));
|
||||
desc->distance = 2.f;
|
||||
desc->exposure = 1.0f;
|
||||
desc->env_pow = 1.8f;
|
||||
desc->blur_bg = 0.5f;
|
||||
desc->bg_mode = LV_GLTF_BG_MODE_ENVIRONMENT;
|
||||
desc->aa_mode = LV_GLTF_AA_MODE_OFF;
|
||||
desc->fov = 45.f;
|
||||
desc->animation_speed_ratio = LV_GLTF_ANIM_SPEED_NORMAL;
|
||||
desc->frame_was_antialiased = false;
|
||||
}
|
||||
static void lv_gltf_parse_model(lv_gltf_t * viewer, lv_gltf_model_t * model)
|
||||
{
|
||||
const auto & iterate_callback = [&](fastgltf::Node & node, const fastgltf::math::fmat4x4 & matrix) {
|
||||
LV_UNUSED(matrix);
|
||||
if(!node.meshIndex) {
|
||||
return;
|
||||
}
|
||||
auto & mesh_index = node.meshIndex.value();
|
||||
if(node.skinIndex) {
|
||||
auto skin_index = node.skinIndex.value();
|
||||
if(!lv_gltf_data_validated_skins_contains(model, skin_index)) {
|
||||
lv_gltf_data_validate_skin(model, skin_index);
|
||||
auto skin = model->asset.skins[skin_index];
|
||||
if(skin.inverseBindMatrices) {
|
||||
auto & ibm_value = skin.inverseBindMatrices.value();
|
||||
auto & ibm_accessor = model->asset.accessors[ibm_value];
|
||||
if(ibm_accessor.bufferViewIndex) {
|
||||
fastgltf::iterateAccessorWithIndex<fastgltf::math::fmat4x4>(
|
||||
model->asset, ibm_accessor,
|
||||
[&](fastgltf::math::fmat4x4 _matrix, std::size_t idx) {
|
||||
auto & joint_node = model->asset.nodes[skin.joints[idx]];
|
||||
viewer->ibm_by_skin_then_node[skin_index][&joint_node] = _matrix;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t mp = 0; mp < model->asset.meshes[mesh_index].primitives.size(); mp++) {
|
||||
auto & model_primitive = model->asset.meshes[mesh_index].primitives[mp];
|
||||
const auto & mappings = model_primitive.mappings;
|
||||
ssize_t material_index =
|
||||
(!mappings.empty() && mappings[viewer->state.material_variant]) ?
|
||||
mappings[viewer->state.material_variant].value() + 1 :
|
||||
((model_primitive.materialIndex) ? (model_primitive.materialIndex.value() + 1) : 0);
|
||||
if(material_index < 0) {
|
||||
lv_gltf_data_add_opaque_node_primitive(model, 0, &node, mp);
|
||||
continue;
|
||||
}
|
||||
const fastgltf::Material & material = model->asset.materials[material_index - 1];
|
||||
|
||||
viewer->state.render_opaque_buffer |= material.transmission != NULL;
|
||||
|
||||
if(material.alphaMode == fastgltf::AlphaMode::Blend || material.transmission != NULL) {
|
||||
lv_gltf_data_add_blended_node_primitive(model, material_index + 1, &node, mp);
|
||||
}
|
||||
else {
|
||||
lv_gltf_data_add_opaque_node_primitive(model, material_index + 1, &node, mp);
|
||||
}
|
||||
|
||||
lv_array_t defines;
|
||||
lv_array_init(&defines, 64, sizeof(lv_opengl_shader_define_t));
|
||||
lv_result_t result =
|
||||
lv_gltf_view_shader_injest_discover_defines(&defines, model, &node, &model_primitive);
|
||||
|
||||
LV_ASSERT_MSG(result == LV_RESULT_OK, "Couldn't injest shader defines");
|
||||
|
||||
lv_opengl_shader_params_t frag_shader {"__MAIN__.frag", (lv_opengl_shader_define_t *) defines.data, lv_array_size(&defines) };
|
||||
lv_opengl_shader_params_t vert_shader {"__MAIN__.vert", (lv_opengl_shader_define_t *) defines.data, lv_array_size(&defines) };
|
||||
|
||||
lv_opengl_shader_program_t * program = lv_opengl_shader_manager_compile_program_best_version(&viewer->shader_manager,
|
||||
&frag_shader,
|
||||
&vert_shader, GLSL_VERSIONS, GLSL_VERSION_COUNT);
|
||||
LV_ASSERT_MSG(program != NULL,
|
||||
"Failed to link program. This probably means your platform doesn't support a required GLSL version");
|
||||
GLuint program_id = lv_opengl_shader_program_get_id(program);
|
||||
GL_CALL(glUseProgram(program_id));
|
||||
|
||||
lv_gltf_compiled_shader_t compiled_shader { lv_gltf_uniform_locations_create(program_id), program_id, };
|
||||
|
||||
lv_gltf_store_compiled_shader(model, material_index, &compiled_shader);
|
||||
const size_t n = lv_array_size(&defines);
|
||||
for(size_t i = 0; i < n; ++i) {
|
||||
lv_opengl_shader_define_t * define = (lv_opengl_shader_define_t *) lv_array_at(&defines, i);
|
||||
if(define->value_allocated) {
|
||||
lv_free((void *)define->value);
|
||||
}
|
||||
}
|
||||
lv_array_deinit(&defines);
|
||||
}
|
||||
};
|
||||
|
||||
setup_compile_and_load_bg_shader(&viewer->shader_manager);
|
||||
fastgltf::iterateSceneNodes(model->asset, 0, fastgltf::math::fmat4x4(), iterate_callback);
|
||||
}
|
||||
|
||||
static void setup_compile_and_load_bg_shader(lv_opengl_shader_manager_t * manager)
|
||||
{
|
||||
lv_opengl_shader_define_t frag_defs[1] { { "TONEMAP_KHR_PBR_NEUTRAL", NULL, false} };
|
||||
uint32_t frag_shader_hash ;
|
||||
uint32_t vert_shader_hash;
|
||||
lv_result_t res = lv_opengl_shader_manager_select_shader(manager, "cubemap.frag", frag_defs, 1,
|
||||
LV_OPENGL_GLSL_VERSION_300ES,
|
||||
&frag_shader_hash);
|
||||
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
res = lv_opengl_shader_manager_select_shader(manager, "cubemap.vert", nullptr, 0, LV_OPENGL_GLSL_VERSION_300ES,
|
||||
&vert_shader_hash);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
|
||||
lv_opengl_shader_program_t * program = lv_opengl_shader_manager_get_program(manager, frag_shader_hash,
|
||||
vert_shader_hash);
|
||||
|
||||
manager->bg_program = lv_opengl_shader_program_get_id(program);
|
||||
setup_background_environment(manager->bg_program, &manager->bg_vao, &manager->bg_index_buf, &manager->bg_vertex_buf);
|
||||
}
|
||||
|
||||
|
||||
static void setup_background_environment(GLuint program, GLuint * vao, GLuint * indexBuffer, GLuint * vertexBuffer)
|
||||
{
|
||||
int32_t indices[] { 1, 2, 0, 2, 3, 0, 6, 2, 1, 1, 5, 6, 6, 5, 4, 4, 7, 6,
|
||||
6, 3, 2, 7, 3, 6, 3, 7, 0, 7, 4, 0, 5, 1, 0, 4, 5, 0
|
||||
};
|
||||
float verts[] { -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
|
||||
-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
GL_CALL(glUseProgram(program));
|
||||
GL_CALL(glGenVertexArrays(1, vao));
|
||||
GL_CALL(glBindVertexArray(*vao));
|
||||
GL_CALL(glGenBuffers(1, indexBuffer));
|
||||
GL_CALL(glGenBuffers(1, vertexBuffer));
|
||||
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, *vertexBuffer));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW));
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer));
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
|
||||
|
||||
GLint positionAttributeLocation = glGetAttribLocation(program, "a_position");
|
||||
|
||||
// Specify the layout of the vertex data
|
||||
glVertexAttribPointer(positionAttributeLocation, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
||||
glEnableVertexAttribArray(positionAttributeLocation);
|
||||
|
||||
GL_CALL(glBindVertexArray(0));
|
||||
GL_CALL(glUseProgram(0));
|
||||
}
|
||||
|
||||
|
||||
static void display_refr_end_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_gltf_t * viewer = (lv_gltf_t *) lv_event_get_user_data(e);
|
||||
uint32_t model_count = lv_array_size(&viewer->models);
|
||||
for(uint32_t i = 0; i < model_count; ++i) {
|
||||
lv_gltf_model_t * model = *(lv_gltf_model_t **)lv_array_at(&viewer->models, i);
|
||||
lv_gltf_model_send_new_values(model);
|
||||
}
|
||||
}
|
||||
#endif /*LV_USE_GLTF*/
|
||||
192
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_internal.h
Normal file
192
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_internal.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* @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 "../../../drivers/opengles/opengl_shader/lv_opengl_shader_internal.h"
|
||||
#include "../../../widgets/3dtexture/lv_3dtexture_private.h"
|
||||
#include "../gltf_data/lv_gltf_data_internal.h"
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/* ::Gamma Presets::
|
||||
* Standard Gamma value is 2.2
|
||||
* Values range from 0.5 to 3.5, roughly speaking, with
|
||||
* reasonable results between the 1.5 and 2.8 levels.
|
||||
* The value must be enclosed with quotes, as a string literal.
|
||||
*/
|
||||
#define LV_GLTF_GAMMA_BRIGHTEST "3.5"
|
||||
#define LV_GLTF_GAMMA_BRIGHTER "3.0"
|
||||
#define LV_GLTF_GAMMA_BRIGHT "2.6"
|
||||
#define LV_GLTF_GAMMA_STANDARD "2.2"
|
||||
#define LV_GLTF_GAMMA_DARK "1.8"
|
||||
#define LV_GLTF_GAMMA_DARKER "1.3"
|
||||
#define LV_GLTF_GAMMA_DARKEST "0.8"
|
||||
|
||||
#define LV_GLTF_DISTANCE_SCALE_FACTOR 2.5f
|
||||
#define LV_GLTF_TRANSMISSION_PASS_SIZE 256
|
||||
|
||||
/* Apply defaults below if not set explicitly */
|
||||
|
||||
/* Tone-mapping is not applied if linear output is enabled.
|
||||
* Linear output is the default.
|
||||
*/
|
||||
#ifndef LV_GLTF_LINEAR_OUTPUT
|
||||
#define LV_GLTF_LINEAR_OUTPUT 1
|
||||
#endif
|
||||
|
||||
/* If tone-mapping is applied, this adjusts the brightness
|
||||
* and color range of the output. Use stringified values.
|
||||
*/
|
||||
#ifndef LV_GLTF_TONEMAP_GAMMA
|
||||
#define LV_GLTF_TONEMAP_GAMMA LV_GLTF_GAMMA_STANDARD
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* 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 {
|
||||
/* Blend state */
|
||||
GLboolean blend_enabled;
|
||||
GLint blend_src;
|
||||
GLint blend_dst;
|
||||
GLint blend_equation;
|
||||
|
||||
/* Depth state */
|
||||
GLboolean depth_test_enabled;
|
||||
GLboolean depth_mask;
|
||||
GLint depth_func;
|
||||
|
||||
/* Face culling state */
|
||||
GLboolean cull_face_enabled;
|
||||
GLint cull_face_mode;
|
||||
GLint front_face;
|
||||
|
||||
/* Stencil state */
|
||||
GLboolean stencil_test_enabled;
|
||||
GLuint stencil_mask;
|
||||
GLint stencil_func;
|
||||
GLint stencil_ref;
|
||||
GLuint stencil_value_mask;
|
||||
|
||||
/* Buffer bindings */
|
||||
GLuint current_vao;
|
||||
GLuint current_vbo;
|
||||
GLuint current_ibo;
|
||||
GLuint current_program;
|
||||
|
||||
/* Texture state */
|
||||
GLint active_texture;
|
||||
GLuint bound_texture_2d;
|
||||
|
||||
/* Viewport and scissor */
|
||||
GLint viewport[4];
|
||||
GLboolean scissor_test_enabled;
|
||||
GLint scissor_box[4];
|
||||
|
||||
/* Clear values */
|
||||
GLfloat clear_depth;
|
||||
GLfloat clear_color[4];
|
||||
} lv_opengl_state_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_environment_t * environment;
|
||||
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;
|
||||
bool owns_environment;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* 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);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif/* __cplusplus*/
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#endif /*LV_GLTF_VIEW_INTERNAL_H*/
|
||||
1442
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp
Normal file
1442
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_render.cpp
Normal file
File diff suppressed because it is too large
Load Diff
379
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_shader.cpp
Normal file
379
inc/lvgl/src/libs/gltf/gltf_view/lv_gltf_view_shader.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* @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 "../../../drivers/opengles/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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(material.pbrData.baseColorFactor.x() == 0.0f
|
||||
&& material.pbrData.baseColorFactor.y() == 0.0f
|
||||
&& material.pbrData.baseColorFactor.z() == 0.0f
|
||||
&& material.pbrData.metallicFactor == 1.0f
|
||||
&& material.pbrData.roughnessFactor == 1.0f
|
||||
&& material.emissiveStrength > 0.0f) {
|
||||
/* Special case where settings preclude IBL's ability to have visible effect, so disable it entirely */
|
||||
LV_LOG_TRACE("Special case identified, disabling IBL and enabling UNLIT\n");
|
||||
if(add_define(result, "MATERIAL_UNLIT", 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, "USE_IBL", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
const size_t light_count = data->node_by_light_index.size();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if LV_GLTF_LINEAR_OUTPUT
|
||||
if(add_define(result, "LINEAR_OUTPUT", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
if(add_texture_defines(result, material.specularGlossiness->specularGlossinessTexture,
|
||||
"HAS_SPECULARGLOSSINESS_MAP", "HAS_SPECULARGLOSSINESS_UV_TRANSFORM") == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
if(material.transmission) {
|
||||
if(add_define(result, "MATERIAL_TRANSMISSION", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
#if 0 /* Material dispersion is being revisited.*/
|
||||
if(add_define(result, "MATERIAL_DISPERSION", NULL, false) == LV_RESULT_INVALID) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
#endif
|
||||
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 && material.clearcoat->clearcoatFactor > 0.0f) {
|
||||
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 && material.diffuseTransmission->diffuseTransmissionFactor > 0.0f) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* 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*/
|
||||
50
inc/lvgl/src/libs/gltf/math/lv_3dmath.c
Normal file
50
inc/lvgl/src/libs/gltf/math/lv_3dmath.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @file lv_3dmath.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_3dmath.h"
|
||||
#if LV_USE_GLTF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_3dplane_t lv_get_ground_plane(float elevation)
|
||||
{
|
||||
return (lv_3dplane_t) {
|
||||
.origin = {0.f, elevation, 0.f},
|
||||
.direction = {0.f, 1.f, 0.f}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
72
inc/lvgl/src/libs/gltf/math/lv_3dmath.h
Normal file
72
inc/lvgl/src/libs/gltf/math/lv_3dmath.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file lv_3dmath.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_3DMATH_H
|
||||
#define LV_3DMATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} lv_3dpoint_t;
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
} lv_quaternion_t;
|
||||
|
||||
typedef struct {
|
||||
lv_3dpoint_t origin;
|
||||
lv_3dpoint_t direction;
|
||||
} lv_3dplane_t;
|
||||
|
||||
typedef lv_3dplane_t lv_3dray_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get a plane that faces upward, centered at a given height
|
||||
* @param elevation elevation of the ground plane, in world units. this is usually zero
|
||||
* @return ground plane
|
||||
*/
|
||||
lv_3dplane_t lv_get_ground_plane(float elevation);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*LV_3DMATH_H*/
|
||||
78
inc/lvgl/src/libs/gltf/math/lv_gltf_math.cpp
Normal file
78
inc/lvgl/src/libs/gltf/math/lv_gltf_math.cpp
Normal file
@@ -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*/
|
||||
84
inc/lvgl/src/libs/gltf/math/lv_gltf_math.hpp
Normal file
84
inc/lvgl/src/libs/gltf/math/lv_gltf_math.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file lv_gltf_math.hpp
|
||||
* @brief GLTF math utilities and helper functions
|
||||
*/
|
||||
|
||||
#ifndef LV_GLTF_MATH_HPP
|
||||
#define LV_GLTF_MATH_HPP
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GLTF
|
||||
|
||||
#include <fastgltf/math.hpp>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
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;
|
||||
fastgltf::math::fmat4x4 lv_gltf_math_perspective_rh(float fov, float ratio, float z_near, float z_far) noexcept;
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] fastgltf::math::quat<T> lv_gltf_math_euler_to_quaternion(T P, T Y, T R)
|
||||
{
|
||||
// Convert degrees to radians if necessary
|
||||
// roll = roll * (M_PI / 180.0);
|
||||
// pitch = pitch * (M_PI / 180.0);
|
||||
// yaw = yaw * (M_PI / 180.0);
|
||||
T H = T(0.5);
|
||||
Y *= H;
|
||||
P *= H;
|
||||
R *= H;
|
||||
T cy = cos(Y), sy = sin(Y), cp = cos(P), sp = sin(P), cr = cos(R), sr = sin(R);
|
||||
T cr_cp = cr * cp, sp_sy = sp * sy, sr_cp = sr * cp, sp_cy = sp * cy;
|
||||
return fastgltf::math::quat<T>(
|
||||
sr_cp * cy - cr * sp_sy, // X
|
||||
sr_cp * sy + cr * sp_cy, // Y
|
||||
cr_cp * sy - sr * sp_cy, // Z
|
||||
cr_cp * cy + sr * sp_sy // W
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] fastgltf::math::vec<T, 3> lv_gltf_math_quaternion_to_euler(fastgltf::math::quat<T> q)
|
||||
{
|
||||
T Q11 = q[1] * q[1];
|
||||
// Roll (Z)
|
||||
T sinr_cosp = T(2.0) * (q[3] * q[0] + q[1] * q[2]);
|
||||
T cosr_cosp = T(1.0) - T(2.0) * (q[0] * q[0] + Q11);
|
||||
// Pitch (X)
|
||||
T sinp = T(2.0) * (q[3] * q[1] - q[2] * q[0]);
|
||||
// Yaw (Y)
|
||||
T siny_cosp = T(2.0) * (q[3] * q[2] + q[0] * q[1]);
|
||||
T cosy_cosp = T(1.0) - T(2.0) * (Q11 + q[2] * q[2]);
|
||||
|
||||
return fastgltf::math::vec<T, 3>(
|
||||
(std::abs(sinp) >= T(1)) ? std::copysign(T(M_PI) / T(2), sinp) : std::asin(sinp),
|
||||
std::atan2(siny_cosp, cosy_cosp),
|
||||
std::atan2(sinr_cosp, cosr_cosp)
|
||||
);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GLTF*/
|
||||
#endif /*LV_GLTF_MATH_HPP*/
|
||||
8366
inc/lvgl/src/libs/gltf/stb_image/stb_image.h
Normal file
8366
inc/lvgl/src/libs/gltf/stb_image/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user