This source file includes following definitions.
- PathExtrusion_GetNode
- TraversePathExtrusion
- compositor_init_path_extrusion
- PlanarExtrusion_GetNode
- TraversePlanarExtrusion
- compositor_init_planar_extrusion
- PlaneClipper_GetNode
- TraversePlaneClipper
- compositor_init_plane_clipper
- OffscreenGroup_GetNode
- TraverseOffscreenGroup
- compositor_init_offscreen_group
- DepthGroup_GetNode
- TraverseDepthGroup
- compositor_init_depth_group
- TraverseDepthViewPoint
- compositor_init_depth_viewpoint
- IndexedCurve2D_GetNode
- TraverseIndexedCurve2D
- compositor_init_idx_curve2d
- Untransform_GetNode
- TraverseUntransform
- compositor_init_untransform
- StyleGroup_GetNode
- TraverseStyleGroup
- compositor_init_style_group
- TestSensor_GetNode
- TraverseTestSensor
- TestSensor_OnTrigger
- compositor_init_test_sensor
- CustomTexture_GetNode
- TraverseCustomTexture
- CustomTexture_update
- compositor_init_custom_texture
- TraverseVRGeometry
- compositor_init_vr_geometry
- gf_sc_init_hardcoded_proto
- gf_sc_uri_is_hardcoded_proto
- gf_sc_hardcoded_proto_get_texture_handler
#include "nodes_stacks.h"
#include "visual_manager.h"
#include "offscreen_cache.h"
#include "mpeg4_grouping.h"
#include <gpac/modules/hardcoded_proto.h>
#include <gpac/internal/terminal_dev.h>
#include "texturing.h"
#define CHECK_FIELD(__name, __index, __type) \
if (gf_node_get_field(node, __index, &field) != GF_OK) {\
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[HardcodedProtos] Cannot get field index %d\n", __index));\
return GF_FALSE; \
}\
if (field.fieldType != __type) {\
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[HardcodedProtos] %s field idx %d (%s) is not of type %s\n", __name, field.fieldIndex, field.name, gf_sg_vrml_get_field_type_by_name(__type) ));\
return GF_FALSE;\
}
#ifndef GPAC_DISABLE_VRML
#ifndef GPAC_DISABLE_3D
typedef struct
{
GF_Node *geometry;
MFVec3f *spine;
Bool beginCap;
Bool endCap;
Fixed creaseAngle;
MFRotation *orientation;
MFVec2f *scale;
Bool txAlongSpine;
} PathExtrusion;
static Bool PathExtrusion_GetNode(GF_Node *node, PathExtrusion *path_ext)
{
GF_FieldInfo field;
memset(path_ext, 0, sizeof(PathExtrusion));
CHECK_FIELD("PathExtrusion", 0, GF_SG_VRML_SFNODE);
path_ext->geometry = * (GF_Node **) field.far_ptr;
CHECK_FIELD("PathExtrusion", 1, GF_SG_VRML_MFVEC3F);
path_ext->spine = (MFVec3f *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 2, GF_SG_VRML_SFBOOL);
path_ext->beginCap = *(SFBool *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 3, GF_SG_VRML_SFBOOL);
path_ext->endCap = *(SFBool *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 4, GF_SG_VRML_SFFLOAT);
path_ext->creaseAngle = *(SFFloat *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 5, GF_SG_VRML_MFROTATION);
path_ext->orientation = (MFRotation *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 6, GF_SG_VRML_MFVEC2F);
path_ext->scale = (MFVec2f *) field.far_ptr;
CHECK_FIELD("PathExtrusion", 7, GF_SG_VRML_SFBOOL);
path_ext->txAlongSpine = *(SFBool *) field.far_ptr;
return GF_TRUE;
}
static void TraversePathExtrusion(GF_Node *node, void *rs, Bool is_destroy)
{
PathExtrusion path_ext;
Drawable *stack_2d;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
if (is_destroy) {
drawable_3d_del(node);
return;
}
if (!PathExtrusion_GetNode(node, &path_ext)) return;
if (!path_ext.geometry) return;
if (gf_node_dirty_get(node)) {
u32 mode = tr_state->traversing_mode;
tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
gf_node_traverse(path_ext.geometry, tr_state);
tr_state->traversing_mode = mode;
gf_node_dirty_clear(node, 0);
switch (gf_node_get_tag(path_ext.geometry) ) {
case TAG_MPEG4_Circle:
case TAG_MPEG4_Ellipse:
case TAG_MPEG4_Rectangle:
case TAG_MPEG4_Curve2D:
case TAG_MPEG4_XCurve2D:
case TAG_MPEG4_IndexedFaceSet2D:
case TAG_MPEG4_IndexedLineSet2D:
stack_2d = (Drawable*)gf_node_get_private(path_ext.geometry);
if (!stack_2d) return;
mesh_extrude_path(stack->mesh, stack_2d->path, path_ext.spine, path_ext.creaseAngle, path_ext.beginCap, path_ext.endCap, path_ext.orientation, path_ext.scale, path_ext.txAlongSpine);
break;
case TAG_MPEG4_Text:
compositor_extrude_text(path_ext.geometry, tr_state, stack->mesh, path_ext.spine, path_ext.creaseAngle, path_ext.beginCap, path_ext.endCap, path_ext.orientation, path_ext.scale, path_ext.txAlongSpine);
break;
}
}
if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
visual_3d_draw(tr_state, stack->mesh);
} else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
tr_state->bbox = stack->mesh->bounds;
}
}
static void compositor_init_path_extrusion(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraversePathExtrusion);
}
typedef struct
{
GF_Node *geometry;
GF_Node *spine;
Bool beginCap;
Bool endCap;
Fixed creaseAngle;
MFFloat *orientationKeys;
MFRotation *orientation;
MFFloat *scaleKeys;
MFVec2f *scale;
Bool txAlongSpine;
} PlanarExtrusion;
static Bool PlanarExtrusion_GetNode(GF_Node *node, PlanarExtrusion *path_ext)
{
GF_FieldInfo field;
memset(path_ext, 0, sizeof(PathExtrusion));
CHECK_FIELD("PlanarExtrusion", 0, GF_SG_VRML_SFNODE);
path_ext->geometry = * (GF_Node **) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 1, GF_SG_VRML_SFNODE);
path_ext->spine = * (GF_Node **) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 2, GF_SG_VRML_SFBOOL);
path_ext->beginCap = *(SFBool *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 3, GF_SG_VRML_SFBOOL);
path_ext->endCap = *(SFBool *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 4, GF_SG_VRML_SFFLOAT);
path_ext->creaseAngle = *(SFFloat *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 5, GF_SG_VRML_MFFLOAT);
path_ext->orientationKeys = (MFFloat *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 6, GF_SG_VRML_MFROTATION);
path_ext->orientation = (MFRotation *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 7, GF_SG_VRML_MFFLOAT);
path_ext->scaleKeys = (MFFloat *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 8, GF_SG_VRML_MFVEC2F);
path_ext->scale = (MFVec2f *) field.far_ptr;
CHECK_FIELD("PlanarExtrusion", 9, GF_SG_VRML_SFBOOL);
path_ext->txAlongSpine = *(SFBool *) field.far_ptr;
return GF_TRUE;
}
static void TraversePlanarExtrusion(GF_Node *node, void *rs, Bool is_destroy)
{
PlanarExtrusion plane_ext;
Drawable *stack_2d;
u32 i, j, k;
MFVec3f spine_vec;
SFVec3f d;
Fixed spine_len;
GF_Rect bounds;
GF_Path *geo, *spine;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
if (is_destroy) {
drawable_3d_del(node);
return;
}
if (!PlanarExtrusion_GetNode(node, &plane_ext)) return;
if (!plane_ext.geometry || !plane_ext.spine) return;
if (gf_node_dirty_get(node)) {
u32 cur, nb_pts;
u32 mode = tr_state->traversing_mode;
geo = spine = NULL;
tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
gf_node_traverse(plane_ext.geometry, tr_state);
gf_node_traverse(plane_ext.spine, tr_state);
tr_state->traversing_mode = mode;
gf_node_dirty_clear(node, 0);
switch (gf_node_get_tag(plane_ext.geometry) ) {
case TAG_MPEG4_Circle:
case TAG_MPEG4_Ellipse:
case TAG_MPEG4_Rectangle:
case TAG_MPEG4_Curve2D:
case TAG_MPEG4_XCurve2D:
case TAG_MPEG4_IndexedFaceSet2D:
case TAG_MPEG4_IndexedLineSet2D:
stack_2d = (Drawable*)gf_node_get_private(plane_ext.geometry);
if (stack_2d) geo = stack_2d->path;
break;
default:
return;
}
switch (gf_node_get_tag(plane_ext.spine) ) {
case TAG_MPEG4_Circle:
case TAG_MPEG4_Ellipse:
case TAG_MPEG4_Rectangle:
case TAG_MPEG4_Curve2D:
case TAG_MPEG4_XCurve2D:
case TAG_MPEG4_IndexedFaceSet2D:
case TAG_MPEG4_IndexedLineSet2D:
stack_2d = (Drawable*)gf_node_get_private(plane_ext.spine);
if (stack_2d) spine = stack_2d->path;
break;
default:
return;
}
if (!geo || !spine) return;
mesh_reset(stack->mesh);
gf_path_flatten(spine);
gf_path_get_bounds(spine, &bounds);
gf_path_flatten(geo);
gf_path_get_bounds(geo, &bounds);
cur = 0;
for (i=0; i<spine->n_contours; i++) {
nb_pts = 1 + spine->contours[i] - cur;
spine_vec.vals = NULL;
gf_sg_vrml_mf_alloc(&spine_vec, GF_SG_VRML_MFVEC3F, nb_pts);
spine_len = 0;
for (j=cur; j<nb_pts; j++) {
spine_vec.vals[j].x = spine->points[j].x;
spine_vec.vals[j].y = spine->points[j].y;
spine_vec.vals[j].z = 0;
if (j) {
gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
spine_len += gf_vec_len(d);
}
}
cur += nb_pts;
if (!plane_ext.orientation->count && !plane_ext.scale->count) {
mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
plane_ext.beginCap, plane_ext.endCap, NULL, NULL, plane_ext.txAlongSpine);
}
else {
MFRotation ori;
MFVec2f scale;
Fixed cur_len, frac;
ori.vals = NULL;
gf_sg_vrml_mf_alloc(&ori, GF_SG_VRML_MFROTATION, nb_pts);
scale.vals = NULL;
gf_sg_vrml_mf_alloc(&scale, GF_SG_VRML_MFVEC2F, nb_pts);
cur_len = 0;
if (!plane_ext.orientation->count) ori.vals[0].y = FIX_ONE;
if (!plane_ext.scale->count) scale.vals[0].x = scale.vals[0].y = FIX_ONE;
for (j=0; j<nb_pts; j++) {
if (j) {
gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
cur_len += gf_vec_len(d);
ori.vals[j] = ori.vals[j-1];
scale.vals[j] = scale.vals[j-1];
}
if (plane_ext.orientation->count && (plane_ext.orientation->count == plane_ext.orientationKeys->count)) {
frac = gf_divfix(cur_len , spine_len);
if (frac < plane_ext.orientationKeys->vals[0]) ori.vals[j] = plane_ext.orientation->vals[0];
else if (frac >= plane_ext.orientationKeys->vals[plane_ext.orientationKeys->count-1]) ori.vals[j] = plane_ext.orientation->vals[plane_ext.orientationKeys->count-1];
else {
for (k=1; k<plane_ext.orientationKeys->count; k++) {
Fixed kDiff = plane_ext.orientationKeys->vals[k] - plane_ext.orientationKeys->vals[k-1];
if (!kDiff) continue;
if (frac < plane_ext.orientationKeys->vals[k-1]) continue;
if (frac > plane_ext.orientationKeys->vals[k]) continue;
frac = gf_divfix(frac - plane_ext.orientationKeys->vals[k-1], kDiff);
break;
}
ori.vals[j] = gf_sg_sfrotation_interpolate(plane_ext.orientation->vals[k-1], plane_ext.orientation->vals[k], frac);
}
}
if (plane_ext.scale->count == plane_ext.scaleKeys->count) {
frac = gf_divfix(cur_len , spine_len);
if (frac <= plane_ext.scaleKeys->vals[0]) scale.vals[j] = plane_ext.scale->vals[0];
else if (frac >= plane_ext.scaleKeys->vals[plane_ext.scaleKeys->count-1]) scale.vals[j] = plane_ext.scale->vals[plane_ext.scale->count-1];
else {
for (k=1; k<plane_ext.scaleKeys->count; k++) {
Fixed kDiff = plane_ext.scaleKeys->vals[k] - plane_ext.scaleKeys->vals[k-1];
if (!kDiff) continue;
if (frac < plane_ext.scaleKeys->vals[k-1]) continue;
if (frac > plane_ext.scaleKeys->vals[k]) continue;
frac = gf_divfix(frac - plane_ext.scaleKeys->vals[k-1], kDiff);
break;
}
scale.vals[j].x = gf_mulfix(plane_ext.scale->vals[k].x - plane_ext.scale->vals[k-1].x, frac) + plane_ext.scale->vals[k-1].x;
scale.vals[j].y = gf_mulfix(plane_ext.scale->vals[k].y - plane_ext.scale->vals[k-1].y, frac) + plane_ext.scale->vals[k-1].y;
}
}
}
mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
plane_ext.beginCap, plane_ext.endCap, &ori, &scale, plane_ext.txAlongSpine);
gf_sg_vrml_mf_reset(&ori, GF_SG_VRML_MFROTATION);
gf_sg_vrml_mf_reset(&scale, GF_SG_VRML_MFVEC2F);
}
gf_sg_vrml_mf_reset(&spine_vec, GF_SG_VRML_MFVEC3F);
}
mesh_update_bounds(stack->mesh);
gf_mesh_build_aabbtree(stack->mesh);
}
if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
visual_3d_draw(tr_state, stack->mesh);
} else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
tr_state->bbox = stack->mesh->bounds;
}
}
void compositor_init_planar_extrusion(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraversePlanarExtrusion);
}
typedef struct
{
BASE_NODE
CHILDREN
GF_Plane plane;
} PlaneClipper;
typedef struct
{
GROUPING_NODE_STACK_3D
PlaneClipper pc;
} PlaneClipperStack;
static Bool PlaneClipper_GetNode(GF_Node *node, PlaneClipper *pc)
{
GF_FieldInfo field;
memset(pc, 0, sizeof(PlaneClipper));
pc->sgprivate = node->sgprivate;
CHECK_FIELD("PlaneClipper", 0, GF_SG_VRML_SFVEC3F);
pc->plane.normal = * (SFVec3f *) field.far_ptr;
CHECK_FIELD("PlaneClipper", 1, GF_SG_VRML_SFFLOAT);
pc->plane.d = * (SFFloat *) field.far_ptr;
CHECK_FIELD("PlaneClipper", 2, GF_SG_VRML_MFNODE);
pc->children = *(GF_ChildNodeItem **) field.far_ptr;
return GF_TRUE;
}
static void TraversePlaneClipper(GF_Node *node, void *rs, Bool is_destroy)
{
PlaneClipperStack *stack = (PlaneClipperStack *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
group_3d_delete(node);
return;
}
if (gf_node_dirty_get(node)) {
PlaneClipper_GetNode(node, &stack->pc);
gf_node_dirty_clear(node, 0);
}
if (tr_state->num_clip_planes==MAX_USER_CLIP_PLANES) {
group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
return;
}
if (tr_state->traversing_mode == TRAVERSE_SORT) {
GF_Matrix mx;
gf_mx_copy(mx, tr_state->model_matrix);
visual_3d_set_clip_plane(tr_state->visual, stack->pc.plane, &mx, GF_FALSE);
tr_state->num_clip_planes++;
group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
visual_3d_reset_clip_plane(tr_state->visual);
tr_state->num_clip_planes--;
} else {
tr_state->clip_planes[tr_state->num_clip_planes] = stack->pc.plane;
gf_mx_apply_plane(&tr_state->model_matrix, &tr_state->clip_planes[tr_state->num_clip_planes]);
tr_state->num_clip_planes++;
group_3d_traverse((GF_Node*)&stack->pc, (GroupingNode*)stack, tr_state);
tr_state->num_clip_planes--;
}
}
void compositor_init_plane_clipper(GF_Compositor *compositor, GF_Node *node)
{
PlaneClipper pc;
if (PlaneClipper_GetNode(node, &pc)) {
PlaneClipperStack *stack;
GF_SAFEALLOC(stack, PlaneClipperStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate plane clipper stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraversePlaneClipper);
gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
stack->pc = pc;
gf_node_proto_set_grouping(node);
}
}
#endif
typedef struct
{
BASE_NODE
CHILDREN
s32 offscreen;
Fixed opacity;
} OffscreenGroup;
typedef struct
{
GROUPING_MPEG4_STACK_2D
#ifndef GF_SR_USE_VIDEO_CACHE
struct _group_cache *cache;
#endif
OffscreenGroup og;
Bool detached;
} OffscreenGroupStack;
static Bool OffscreenGroup_GetNode(GF_Node *node, OffscreenGroup *og)
{
GF_FieldInfo field;
memset(og, 0, sizeof(OffscreenGroup));
og->sgprivate = node->sgprivate;
CHECK_FIELD("OffscreenGroup", 0, GF_SG_VRML_MFNODE);
og->children = *(GF_ChildNodeItem **) field.far_ptr;
CHECK_FIELD("OffscreenGroup", 1, GF_SG_VRML_SFINT32);
og->offscreen = * (SFInt32 *) field.far_ptr;
CHECK_FIELD("OffscreenGroup", 2, GF_SG_VRML_SFFLOAT);
og->opacity = * (SFFloat *) field.far_ptr;
return GF_TRUE;
}
static void TraverseOffscreenGroup(GF_Node *node, void *rs, Bool is_destroy)
{
OffscreenGroupStack *stack = (OffscreenGroupStack *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
if (stack->cache) group_cache_del(stack->cache);
gf_free(stack);
return;
}
if (tr_state->traversing_mode==TRAVERSE_SORT) {
if (!stack->detached && (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY)) {
OffscreenGroup_GetNode(node, &stack->og);
if (stack->og.offscreen) {
stack->flags |= GROUP_IS_CACHED | GROUP_PERMANENT_CACHE;
if (!stack->cache) {
stack->cache = group_cache_new(tr_state->visual->compositor, (GF_Node*)&stack->og);
}
stack->cache->opacity = stack->og.opacity;
stack->cache->drawable->flags |= DRAWABLE_HAS_CHANGED;
} else {
if (stack->cache) group_cache_del(stack->cache);
stack->cache = NULL;
stack->flags &= ~(GROUP_IS_CACHED|GROUP_PERMANENT_CACHE);
}
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
}
if (stack->cache) {
if (stack->detached)
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
tr_state->subscene_not_over = 0;
group_cache_traverse((GF_Node *)&stack->og, stack->cache, tr_state, stack->cache->force_recompute, GF_TRUE, stack->detached ? GF_TRUE : GF_FALSE);
if (gf_node_dirty_get(node)) {
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
} else if ((stack->og.offscreen==2) && !stack->detached && !tr_state->subscene_not_over && stack->cache->txh.width && stack->cache->txh.height) {
GF_FieldInfo field;
if (gf_node_get_field(node, 0, &field) == GF_OK) {
gf_node_unregister_children(node, *(GF_ChildNodeItem **) field.far_ptr);
*(GF_ChildNodeItem **) field.far_ptr = NULL;
stack->detached = GF_TRUE;
}
if (gf_node_get_field(node, 3, &field) == GF_OK) {
*(SFBool *) field.far_ptr = 1;
}
}
} else {
group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
}
}
else if (stack->cache && (tr_state->traversing_mode == TRAVERSE_DRAW_2D)) {
group_cache_draw(stack->cache, tr_state);
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
} else if (!stack->detached) {
group_2d_traverse((GF_Node *)&stack->og, (GroupingNode2D*)stack, tr_state);
} else {
if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
tr_state->bounds = stack->bounds;
}
else if (stack->cache && (tr_state->traversing_mode == TRAVERSE_PICK)) {
vrml_drawable_pick(stack->cache->drawable, tr_state);
}
}
}
void compositor_init_offscreen_group(GF_Compositor *compositor, GF_Node *node)
{
OffscreenGroup og;
if (OffscreenGroup_GetNode(node, &og)) {
OffscreenGroupStack *stack;
GF_SAFEALLOC(stack, OffscreenGroupStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate offscreen group stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseOffscreenGroup);
stack->og = og;
if (og.offscreen) stack->flags |= GROUP_IS_CACHED;
gf_node_proto_set_grouping(node);
}
}
typedef struct
{
BASE_NODE
CHILDREN
Fixed depth_gain, depth_offset;
} DepthGroup;
typedef struct
{
GROUPING_MPEG4_STACK_2D
DepthGroup dg;
} DepthGroupStack;
static Bool DepthGroup_GetNode(GF_Node *node, DepthGroup *dg)
{
GF_FieldInfo field;
memset(dg, 0, sizeof(DepthGroup));
dg->sgprivate = node->sgprivate;
CHECK_FIELD("DepthGroup", 0, GF_SG_VRML_MFNODE);
dg->children = *(GF_ChildNodeItem **) field.far_ptr;
CHECK_FIELD("DepthGroup", 1, GF_SG_VRML_SFINT32);
CHECK_FIELD("DepthGroup", 2, GF_SG_VRML_SFFLOAT);
dg->depth_gain = * (SFFloat *) field.far_ptr;
CHECK_FIELD("DepthGroup", 3, GF_SG_VRML_SFFLOAT);
dg->depth_offset = * (SFFloat *) field.far_ptr;
return GF_TRUE;
}
static void TraverseDepthGroup(GF_Node *node, void *rs, Bool is_destroy)
{
#ifdef GF_SR_USE_DEPTH
Fixed depth_gain, depth_offset;
#endif
DepthGroupStack *stack = (DepthGroupStack *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
gf_free(stack);
return;
}
if (tr_state->traversing_mode==TRAVERSE_SORT) {
if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
}
}
DepthGroup_GetNode(node, &stack->dg);
#ifdef GF_SR_USE_DEPTH
depth_gain = tr_state->depth_gain;
depth_offset = tr_state->depth_offset;
tr_state->depth_offset = gf_mulfix(stack->dg.depth_offset, tr_state->depth_gain) + tr_state->depth_offset;
tr_state->depth_gain = gf_mulfix(tr_state->depth_gain, stack->dg.depth_gain);
#endif
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
GF_Matrix mx_bckup, mx;
gf_mx_copy(mx_bckup, tr_state->model_matrix);
gf_mx_init(mx);
mx.m[14] = gf_mulfix(stack->dg.depth_offset, tr_state->visual->compositor->depth_gl_scale);
gf_mx_add_matrix(&tr_state->model_matrix, &mx);
group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_bckup);
} else
#endif
{
group_2d_traverse((GF_Node *)&stack->dg, (GroupingNode2D*)stack, tr_state);
}
#ifdef GF_SR_USE_DEPTH
tr_state->depth_gain = depth_gain;
tr_state->depth_offset = depth_offset;
#endif
}
void compositor_init_depth_group(GF_Compositor *compositor, GF_Node *node)
{
DepthGroup dg;
if (DepthGroup_GetNode(node, &dg)) {
DepthGroupStack *stack;
GF_SAFEALLOC(stack, DepthGroupStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate depth group stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseDepthGroup);
stack->dg = dg;
gf_node_proto_set_grouping(node);
} else GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Unable to initialize depth group \n"));
}
#ifdef GF_SR_USE_DEPTH
static void TraverseDepthViewPoint(GF_Node *node, void *rs, Bool is_destroy)
{
if (!is_destroy && gf_node_dirty_get(node)) {
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
GF_FieldInfo field;
gf_node_dirty_clear(node, 0);
tr_state->visual->depth_vp_position = 0;
tr_state->visual->depth_vp_range = 0;
#ifndef GPAC_DISABLE_3D
if (!tr_state->camera) return;
tr_state->camera->flags |= CAM_IS_DIRTY;
#endif
if (gf_node_get_field(node, 0, &field) != GF_OK) return;
if (field.fieldType != GF_SG_VRML_SFBOOL) return;
if ( *(SFBool *) field.far_ptr) {
if (gf_node_get_field(node, 1, &field) != GF_OK) return;
if (field.fieldType != GF_SG_VRML_SFFLOAT) return;
tr_state->visual->depth_vp_position = *(SFFloat *) field.far_ptr;
if (gf_node_get_field(node, 2, &field) != GF_OK) return;
if (field.fieldType != GF_SG_VRML_SFFLOAT) return;
tr_state->visual->depth_vp_range = *(SFFloat *) field.far_ptr;
}
#ifndef GPAC_DISABLE_3D
if (tr_state->layer3d) gf_node_dirty_set(tr_state->layer3d, GF_SG_NODE_DIRTY, GF_FALSE);
#endif
gf_sc_invalidate(tr_state->visual->compositor, NULL);
}
}
#endif
static void compositor_init_depth_viewpoint(GF_Compositor *compositor, GF_Node *node)
{
#ifdef GF_SR_USE_DEPTH
gf_node_set_callback_function(node, TraverseDepthViewPoint);
#endif
}
typedef struct
{
BASE_NODE
GF_Node *point;
Fixed fineness;
MFInt32 type;
MFInt32 index;
} IndexedCurve2D;
static Bool IndexedCurve2D_GetNode(GF_Node *node, IndexedCurve2D *ic2d)
{
GF_FieldInfo field;
memset(ic2d, 0, sizeof(IndexedCurve2D));
ic2d->sgprivate = node->sgprivate;
CHECK_FIELD("IndexedCurve2D", 0, GF_SG_VRML_SFNODE);
ic2d->point = * (GF_Node **) field.far_ptr;
CHECK_FIELD("IndexedCurve2D", 1, GF_SG_VRML_SFFLOAT);
ic2d->fineness = *(SFFloat *) field.far_ptr;
CHECK_FIELD("IndexedCurve2D", 2, GF_SG_VRML_MFINT32);
ic2d->type = *(MFInt32 *) field.far_ptr;
CHECK_FIELD("IndexedCurve2D", 3, GF_SG_VRML_MFINT32);
ic2d->index = *(MFInt32 *) field.far_ptr;
return GF_TRUE;
}
void curve2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state, MFInt32 *idx);
static void TraverseIndexedCurve2D(GF_Node *node, void *rs, Bool is_destroy)
{
DrawableContext *ctx;
IndexedCurve2D ic2d;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
Drawable *stack = (Drawable *)gf_node_get_private(node);
if (is_destroy) {
drawable_node_del(node);
return;
}
if (gf_node_dirty_get(node)) {
if (!IndexedCurve2D_GetNode(node, &ic2d)) return;
curve2d_check_changes((GF_Node*) &ic2d, stack, tr_state, &ic2d.index);
}
switch (tr_state->traversing_mode) {
#ifndef GPAC_DISABLE_3D
case TRAVERSE_DRAW_3D:
if (!stack->mesh) {
stack->mesh = new_mesh();
mesh_from_path(stack->mesh, stack->path);
}
visual_3d_draw_2d(stack, tr_state);
return;
#endif
case TRAVERSE_PICK:
vrml_drawable_pick(stack, tr_state);
return;
case TRAVERSE_GET_BOUNDS:
gf_path_get_bounds(stack->path, &tr_state->bounds);
return;
case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) return;
#endif
ctx = drawable_init_context_mpeg4(stack, tr_state);
if (!ctx) return;
drawable_finalize_sort(ctx, tr_state, NULL);
return;
}
}
static void compositor_init_idx_curve2d(GF_Compositor *compositor, GF_Node *node)
{
drawable_stack_new(compositor, node);
gf_node_set_callback_function(node, TraverseIndexedCurve2D);
}
typedef struct
{
BASE_NODE
CHILDREN
} Untransform;
typedef struct
{
GROUPING_MPEG4_STACK_2D
Untransform untr;
} UntransformStack;
static Bool Untransform_GetNode(GF_Node *node, Untransform *tr)
{
GF_FieldInfo field;
memset(tr, 0, sizeof(Untransform));
tr->sgprivate = node->sgprivate;
CHECK_FIELD("Untransform", 0, GF_SG_VRML_MFNODE);
tr->children = *(GF_ChildNodeItem **) field.far_ptr;
return GF_TRUE;
}
static void TraverseUntransform(GF_Node *node, void *rs, Bool is_destroy)
{
UntransformStack *stack = (UntransformStack *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
gf_free(stack);
return;
}
if (tr_state->traversing_mode==TRAVERSE_SORT) {
if (gf_node_dirty_get(node)) {
Untransform_GetNode(node, &stack->untr);
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
}
}
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
GF_Matrix mx_model;
GF_Camera backup_cam;
if (!tr_state->camera) return;
gf_mx_copy(mx_model, tr_state->model_matrix);
gf_mx_init(tr_state->model_matrix);
memcpy(&backup_cam, tr_state->camera, sizeof(GF_Camera));
camera_invalidate(tr_state->camera);
tr_state->camera->is_3D = GF_FALSE;
tr_state->camera->flags |= CAM_NO_LOOKAT;
tr_state->camera->end_zoom = FIX_ONE;
camera_update(tr_state->camera, NULL, GF_TRUE);
if (tr_state->traversing_mode == TRAVERSE_SORT) {
visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
visual_3d_projection_matrix_modified(tr_state->visual);
gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_model);
memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
visual_3d_projection_matrix_modified(tr_state->visual);
visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
} else if (tr_state->traversing_mode == TRAVERSE_PICK) {
Fixed prev_dist = tr_state->visual->compositor->hit_square_dist;
GF_Ray r = tr_state->ray;
tr_state->ray.orig.x = INT2FIX(tr_state->pick_x);
tr_state->ray.orig.y = INT2FIX(tr_state->pick_y);
tr_state->ray.orig.z = 0;
tr_state->ray.dir.x = 0;
tr_state->ray.dir.y = 0;
tr_state->ray.dir.z = -FIX_ONE;
tr_state->visual->compositor->hit_square_dist=0;
gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_model);
memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
tr_state->ray = r;
if (!tr_state->visual->compositor->hit_square_dist)
tr_state->visual->compositor->hit_square_dist = prev_dist;
} else {
gf_node_traverse_children((GF_Node *)&stack->untr, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_model);
memcpy(tr_state->camera, &backup_cam, sizeof(GF_Camera));
}
} else
#endif
{
GF_Matrix2D mx2d_backup;
gf_mx2d_copy(mx2d_backup, tr_state->transform);
gf_mx2d_init(tr_state->transform);
group_2d_traverse((GF_Node *)&stack->untr, (GroupingNode2D *)stack, tr_state);
gf_mx2d_copy(tr_state->transform, mx2d_backup);
}
}
void compositor_init_untransform(GF_Compositor *compositor, GF_Node *node)
{
Untransform tr;
if (Untransform_GetNode(node, &tr)) {
UntransformStack *stack;
GF_SAFEALLOC(stack, UntransformStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate untransform stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseUntransform);
stack->untr = tr;
gf_node_proto_set_grouping(node);
}
}
typedef struct
{
BASE_NODE
CHILDREN
GF_Node *appearance;
} StyleGroup;
typedef struct
{
GROUPING_MPEG4_STACK_2D
StyleGroup sg;
} StyleGroupStack;
static Bool StyleGroup_GetNode(GF_Node *node, StyleGroup *sg)
{
GF_FieldInfo field;
memset(sg, 0, sizeof(StyleGroup));
sg->sgprivate = node->sgprivate;
CHECK_FIELD("StyleGroup", 0, GF_SG_VRML_MFNODE);
sg->children = *(GF_ChildNodeItem **) field.far_ptr;
CHECK_FIELD("StyleGroup", 1, GF_SG_VRML_SFNODE);
sg->appearance = *(GF_Node **)field.far_ptr;
return GF_TRUE;
}
static void TraverseStyleGroup(GF_Node *node, void *rs, Bool is_destroy)
{
Bool set = GF_FALSE;
StyleGroupStack *stack = (StyleGroupStack *)gf_node_get_private(node);
GF_TraverseState *tr_state = (GF_TraverseState *) rs;
if (is_destroy) {
gf_free(stack);
return;
}
if (tr_state->traversing_mode==TRAVERSE_SORT) {
if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
gf_node_dirty_set(node, GF_SG_CHILD_DIRTY, GF_FALSE);
}
}
StyleGroup_GetNode(node, &stack->sg);
if (!tr_state->override_appearance) {
set = GF_TRUE;
tr_state->override_appearance = stack->sg.appearance;
}
group_2d_traverse((GF_Node *)&stack->sg, (GroupingNode2D*)stack, tr_state);
if (set) {
tr_state->override_appearance = NULL;
}
}
void compositor_init_style_group(GF_Compositor *compositor, GF_Node *node)
{
StyleGroup sg;
if (StyleGroup_GetNode(node, &sg)) {
StyleGroupStack *stack;
GF_SAFEALLOC(stack, StyleGroupStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate style group stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseStyleGroup);
stack->sg = sg;
gf_node_proto_set_grouping(node);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Unable to initialize style group\n"));
}
}
typedef struct
{
BASE_NODE
Bool onTrigger;
Fixed value;
} TestSensor;
typedef struct
{
TestSensor ts;
} TestSensorStack;
static Bool TestSensor_GetNode(GF_Node *node, TestSensor *ts)
{
GF_FieldInfo field;
memset(ts, 0, sizeof(TestSensor));
ts->sgprivate = node->sgprivate;
CHECK_FIELD("TestSensor", 0, GF_SG_VRML_SFBOOL);
if (field.eventType != GF_SG_EVENT_IN) return GF_FALSE;
ts->onTrigger = *(SFBool *)field.far_ptr;
CHECK_FIELD("TestSensor", 1, GF_SG_VRML_SFFLOAT);
if (field.eventType != GF_SG_EVENT_EXPOSED_FIELD) return GF_FALSE;
ts->value = *(SFFloat *)field.far_ptr;
CHECK_FIELD("TestSensor", 2, GF_SG_VRML_SFFLOAT);
if (field.eventType != GF_SG_EVENT_OUT) return GF_FALSE;
return GF_TRUE;
}
static void TraverseTestSensor(GF_Node *node, void *rs, Bool is_destroy)
{
TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node);
if (is_destroy) {
gf_free(stack);
return;
}
}
void TestSensor_OnTrigger(GF_Node *node, struct _route *route)
{
GF_FieldInfo field;
Fixed value;
TestSensorStack *stack = (TestSensorStack *)gf_node_get_private(node);
TestSensor_GetNode(node, &stack->ts);
if (stack->ts.onTrigger) {
value = stack->ts.value;
} else {
value = 1-stack->ts.value;
}
gf_node_get_field(node, 2, &field);
*(SFFloat*)field.far_ptr = value;
gf_node_event_out(node, 2);
}
void compositor_init_test_sensor(GF_Compositor *compositor, GF_Node *node)
{
TestSensor ts;
if (TestSensor_GetNode(node, &ts)) {
GF_Err e;
TestSensorStack *stack;
GF_SAFEALLOC(stack, TestSensorStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate test sensor stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseTestSensor);
stack->ts = ts;
e = gf_node_set_proto_eventin_handler(node, 0, TestSensor_OnTrigger);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to initialize Proto TestSensor callback: %s\n", gf_error_to_string(e) ));
}
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize test sensor\n"));
}
}
typedef struct
{
BASE_NODE
Fixed intensity;
} CustomTexture;
typedef struct
{
CustomTexture tx;
GF_TextureHandler txh;
u32 gl_id;
} CustomTextureStack;
static Bool CustomTexture_GetNode(GF_Node *node, CustomTexture *tx)
{
GF_FieldInfo field;
memset(tx, 0, sizeof(CustomTexture));
tx->sgprivate = node->sgprivate;
CHECK_FIELD("CustomTexture", 0, GF_SG_VRML_SFFLOAT);
if (field.eventType != GF_SG_EVENT_EXPOSED_FIELD) return GF_FALSE;
tx->intensity = *(SFFloat *)field.far_ptr;
return GF_TRUE;
}
static void TraverseCustomTexture(GF_Node *node, void *rs, Bool is_destroy)
{
CustomTextureStack *stack = (CustomTextureStack *)gf_node_get_private(node);
if (is_destroy) {
gf_sc_texture_destroy(&stack->txh);
gf_free(stack);
return;
}
}
#ifndef GPAC_DISABLE_3D
#include "gl_inc.h"
#endif
static void CustomTexture_update(GF_TextureHandler *txh)
{
#ifndef GPAC_DISABLE_3D
char data[12];
#endif
CustomTextureStack *stack = gf_node_get_private(txh->owner);
if (!txh->tx_io) {
gf_sc_texture_allocate(txh);
if (!txh->tx_io) return;
}
#ifndef GPAC_DISABLE_3D
if (! gf_sc_texture_get_gl_id(txh)) {
txh->transparent = 0;
txh->pixelformat = GF_PIXEL_RGB_24;
gf_sc_texture_set_data(txh);
gf_sc_texture_push_image(txh, GF_FALSE, GF_FALSE);
stack->gl_id = gf_sc_texture_get_gl_id(txh);
}
#endif
CustomTexture_GetNode(txh->owner, &stack->tx);
#ifndef GPAC_DISABLE_3D
memset(data, 0, sizeof(char)*12);
data[0] = (char) (0xFF * FIX2FLT(stack->tx.intensity));
data[4] = (char) (0xFF * FIX2FLT(stack->tx.intensity));
data[8] = (char) (0xFF * FIX2FLT(stack->tx.intensity));
glBindTexture( GL_TEXTURE_2D, stack->gl_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
#endif
}
void compositor_init_custom_texture(GF_Compositor *compositor, GF_Node *node)
{
CustomTexture tx;
if (CustomTexture_GetNode(node, &tx)) {
CustomTextureStack *stack;
GF_SAFEALLOC(stack, CustomTextureStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate custom texture group stack\n"));
return;
}
gf_node_set_private(node, stack);
gf_node_set_callback_function(node, TraverseCustomTexture);
stack->tx = tx;
gf_sc_texture_setup(&stack->txh, compositor, node);
stack->txh.update_texture_fcnt = CustomTexture_update;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unable to initialize custom texture\n"));
}
}
#ifndef GPAC_DISABLE_3D
static void TraverseVRGeometry(GF_Node *node, void *rs, Bool is_destroy)
{
GF_TextureHandler *txh;
GF_MediaObjectVRInfo vrinfo;
GF_MeshSphereAngles sphere_angles;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);
if (is_destroy) {
drawable_3d_del(node);
return;
}
if (!tr_state->appear || ! ((M_Appearance *)tr_state->appear)->texture)
return;
txh = gf_sc_texture_get_handler( ((M_Appearance *) tr_state->appear)->texture );
if (!txh->stream) return;
if (gf_node_dirty_get(node) || (tr_state->traversing_mode==TRAVERSE_DRAW_3D)) {
if (! gf_mo_get_srd_info(txh->stream, &vrinfo))
return;
sphere_angles.min_phi = -GF_PI2 + GF_PI * vrinfo.srd_y / vrinfo.srd_max_y;
sphere_angles.max_phi = -GF_PI2 + GF_PI * (vrinfo.srd_h + vrinfo.srd_y) / vrinfo.srd_max_y;
sphere_angles.min_theta = GF_2PI * vrinfo.srd_x / vrinfo.srd_max_x;
sphere_angles.max_theta = GF_2PI * ( vrinfo.srd_w + vrinfo.srd_x ) / vrinfo.srd_max_x;
if (gf_node_dirty_get(node)) {
u32 radius;
mesh_reset(stack->mesh);
radius = MAX(vrinfo.scene_width, vrinfo.scene_height) / 4;
if (!radius) {
radius = 100;
}
if (radius) {
mesh_new_sphere(stack->mesh, -1 * INT2FIX(radius), GF_FALSE, &sphere_angles);
txh->flags &= ~GF_SR_TEXTURE_REPEAT_S;
txh->flags &= ~GF_SR_TEXTURE_REPEAT_T;
}
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
}
if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
GF_Vec center, target, ref;
Fixed r, theta_angle, phi_angle;
DrawAspect2D asp;
Bool visible = GF_FALSE;
Fixed center_phi = sphere_angles.min_phi + (sphere_angles.max_phi - sphere_angles.min_phi) / 2;
Fixed center_theta = sphere_angles.min_theta + (sphere_angles.max_theta - sphere_angles.min_theta) / 2;
visual_3d_enable_depth_buffer(tr_state->visual, GF_FALSE);
visual_3d_enable_antialias(tr_state->visual, GF_FALSE);
visual_3d_draw(tr_state, stack->mesh);
visual_3d_enable_depth_buffer(tr_state->visual, GF_TRUE);
memset(&asp, 0, sizeof(DrawAspect2D));
drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
center.y = gf_sin(center_phi);
r = gf_sqrt(FIX_ONE - gf_mulfix(center.y, center.y) );
center.x = gf_mulfix(r, gf_cos(center_theta) );
center.z = gf_mulfix(r, gf_sin(center_theta) );
gf_vec_norm(¢er);
ref = center;
ref.y = 0;
gf_vec_norm(&ref);
target = camera_get_target_dir(tr_state->camera);
target.y=0;
gf_vec_norm(&target);
theta_angle = gf_acos( gf_vec_dot(target, ref) );
theta_angle-=GF_PI;
if (theta_angle<0) theta_angle = -theta_angle;
ref = center;
ref.x = 0;
gf_vec_norm(&ref);
target = camera_get_target_dir(tr_state->camera);
target.x=0;
gf_vec_norm(&target);
phi_angle = gf_acos( gf_vec_dot(target, ref) );
phi_angle-=GF_PI;
if (phi_angle<-GF_PI2) phi_angle += GF_PI;
if ((theta_angle < tr_state->camera->fieldOfView/2 + (sphere_angles.max_theta-sphere_angles.min_theta)/2)
&& (phi_angle < tr_state->camera->fieldOfView/2 + (sphere_angles.max_phi-sphere_angles.min_phi) /2)
) {
visible = GF_TRUE;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Texure %d Partial sphere is %s - Angle center-cam is %.02f h %.02f v\n", txh->stream->OD_ID, visible ? "visible" : "hidden", theta_angle, phi_angle));
if (visible) {
gf_mo_hint_quality_degradation(asp.fill_texture->stream, 0);
} else {
gf_mo_hint_quality_degradation(asp.fill_texture->stream, 100);
}
}
}
if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
tr_state->bbox = stack->mesh->bounds;
}
}
static void compositor_init_vr_geometry(GF_Compositor *compositor, GF_Node *node)
{
drawable_3d_new(node);
gf_node_set_callback_function(node, TraverseVRGeometry);
}
#endif
void gf_sc_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node)
{
MFURL *proto_url;
GF_Proto *proto;
u32 i, j;
GF_HardcodedProto *ifce;
proto = gf_node_get_proto(node);
if (!proto) return;
proto_url = gf_sg_proto_get_extern_url(proto);
for (i=0; i<proto_url->count; i++) {
const char *url = proto_url->vals[0].url;
if (!url) continue;
#ifndef GPAC_DISABLE_3D
if (!strcmp(url, "urn:inet:gpac:builtin:PathExtrusion")) {
compositor_init_path_extrusion(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:PlanarExtrusion")) {
compositor_init_planar_extrusion(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:PlaneClipper")) {
compositor_init_plane_clipper(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:VRGeometry")) {
compositor_init_vr_geometry(compositor, node);
return;
}
#endif
if (!strcmp(url, "urn:inet:gpac:builtin:TextureText")) {
compositor_init_texture_text(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:OffscreenGroup")) {
compositor_init_offscreen_group(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:DepthGroup")) {
compositor_init_depth_group(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:DepthViewPoint")) {
compositor_init_depth_viewpoint(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:IndexedCurve2D")) {
compositor_init_idx_curve2d(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:Untransform")) {
compositor_init_untransform(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:FlashShape")) {
compositor_init_hc_flashshape(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:StyleGroup")) {
compositor_init_style_group(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:TestSensor")) {
compositor_init_test_sensor(compositor, node);
return;
}
if (!strcmp(url, "urn:inet:gpac:builtin:CustomTexture")) {
compositor_init_custom_texture(compositor, node);
return;
}
if (compositor->proto_modules) {
j = 0;
while ( (ifce = (GF_HardcodedProto *)gf_list_enum(compositor->proto_modules, &j) )) {
if ( ifce->can_load_proto(url) && ifce->init(ifce, compositor, node, url) ) {
return;
}
}
}
}
}
Bool gf_sc_uri_is_hardcoded_proto(GF_Compositor *compositor, const char *uri)
{
if (compositor && compositor->proto_modules ) {
u32 j = 0;
GF_HardcodedProto *ifce;
while ( (ifce = (GF_HardcodedProto *)gf_list_enum(compositor->proto_modules, &j) )) {
if ( ifce->can_load_proto(uri)) {
return GF_TRUE;
}
}
}
return GF_FALSE;
}
GF_TextureHandler *gf_sc_hardcoded_proto_get_texture_handler(GF_Node *n)
{
MFURL *proto_url;
GF_Proto *proto;
u32 i;
proto = gf_node_get_proto(n);
if (!proto) return NULL;
proto_url = gf_sg_proto_get_extern_url(proto);
for (i=0; i<proto_url->count; i++) {
const char *url = proto_url->vals[0].url;
if (!strcmp(url, "urn:inet:gpac:builtin:CustomTexture")) {
CustomTextureStack *stack = gf_node_get_private(n);
if (stack) return &stack->txh;
}
}
return NULL;
}
#endif