This source file includes following definitions.
- drawable_3d_new
- drawable_3d_del
- drawable3d_check_focus_highlight
- visual_3d_setup_traversing_state
- visual_3d_viewpoint_change
- visual_3d_setup_projection
- visual_3d_draw_background
- visual_3d_draw_background_on_axis
- visual_3d_init_draw
- visual_3d_has_alpha
- visual_3d_register_context
- visual_3d_flush_contexts
- visual_3d_draw_node
- visual_3d_setup_clipper
- visual_3d_draw_frame
- reset_collide_cursor
- visual_3d_check_collisions
- visual_3d_node_cull
- visual_3d_pick_node
- visual_3d_vrml_drawable_pick
- visual_3d_vrml_drawable_collide
- visual_3d_setup_texture_2d
- visual_3d_set_2d_strike
- visual_3d_draw_2d_with_aspect
- visual_3d_draw_2d
- visual_3d_draw_from_context
- visual_3d_setup_material
- visual_3d_setup_texture
- visual_3d_disable_texture
- visual_3d_setup_appearance
- visual_3d_draw
- visual_3d_projection_matrix_modified
- visual_3d_enable_headlight
- visual_3d_set_material_2d
- visual_3d_set_material_2d_argb
- visual_3d_set_clipper_2d
- visual_3d_reset_clipper_2d
- visual_3d_set_clip_plane
- visual_3d_reset_clip_plane
- visual_3d_set_material
- visual_3d_set_shininess
- visual_3d_set_state
- visual_3d_set_texture_matrix
- visual_3d_has_inactive_light
- visual_3d_add_point_light
- visual_3d_add_spot_light
- visual_3d_add_directional_light
- visual_3d_remove_last_light
- visual_3d_clear_all_lights
- visual_3d_set_fog
#include "visual_manager.h"
#include "texturing.h"
#include "nodes_stacks.h"
#include <gpac/options.h>
#ifndef GPAC_DISABLE_3D
Drawable3D *drawable_3d_new(GF_Node *node)
{
Drawable3D *tmp;
GF_SAFEALLOC(tmp, Drawable3D);
if (!tmp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate drawable 3D stack\n"));
return NULL;
}
tmp->mesh = new_mesh();
gf_node_set_private(node, tmp);
return tmp;
}
void drawable_3d_del(GF_Node *n)
{
Drawable3D *d = (Drawable3D *)gf_node_get_private(n);
if (d) {
if (d->mesh) mesh_free(d->mesh);
gf_free(d);
}
gf_sc_check_focus_upon_destroy(n);
}
void drawable3d_check_focus_highlight(GF_Node *node, GF_TraverseState *tr_state, GF_BBox *orig_bounds)
{
Drawable *hlight;
GF_Node *prev_node;
u32 prev_mode;
GF_BBox *bounds;
GF_Matrix cur;
GF_Compositor *compositor = tr_state->visual->compositor;
if (compositor->disable_focus_highlight) return;
if (compositor->focus_node!=node) return;
hlight = compositor->focus_highlight;
if (!hlight) return;
prev_node = gf_node_get_private(hlight->node);
if (prev_node != node) {
gf_node_set_private(hlight->node, node);
drawable_reset_path(hlight);
gf_path_reset(hlight->path);
}
if (!orig_bounds) {
gf_mx_copy(cur, tr_state->model_matrix);
gf_mx_init(tr_state->model_matrix);
prev_mode = tr_state->traversing_mode;
tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
tr_state->bbox.is_set = 0;
gf_node_traverse_children(node, tr_state);
tr_state->traversing_mode = prev_mode;
gf_mx_copy(tr_state->model_matrix, cur);
bounds = &tr_state->bbox;
} else {
bounds = orig_bounds;
}
visual_3d_draw_bbox(tr_state, bounds);
}
static void visual_3d_setup_traversing_state(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
tr_state->visual = visual;
tr_state->camera = &visual->camera;
#ifndef GPAC_DISABLE_VRML
tr_state->backgrounds = visual->back_stack;
tr_state->viewpoints = visual->view_stack;
tr_state->fogs = visual->fog_stack;
tr_state->navigations = visual->navigation_stack;
#endif
tr_state->color_mat.identity = 1;
tr_state->camera->vp.x = tr_state->camera->vp.y = 0;
tr_state->min_hsize = INT2FIX(MIN(visual->width, visual->height) / 2);
if (!tr_state->min_hsize) tr_state->min_hsize = FIX_ONE;
if (visual->compositor->visual==visual) {
if (tr_state->visual->compositor->has_size_info) {
tr_state->camera->vp.x = INT2FIX(tr_state->visual->compositor->vp_x);
tr_state->camera->vp.y = INT2FIX(tr_state->visual->compositor->vp_y);
tr_state->camera->vp.width = INT2FIX(tr_state->visual->compositor->vp_width);
tr_state->camera->vp.height = INT2FIX(tr_state->visual->compositor->vp_height);
if (visual->type_3d==0) {
tr_state->camera->width = INT2FIX(tr_state->visual->width);
tr_state->camera->height = INT2FIX(tr_state->visual->height);
} else {
tr_state->camera->width = INT2FIX(tr_state->visual->compositor->vp_width);
tr_state->camera->height = INT2FIX(tr_state->visual->compositor->vp_height);
}
} else {
Fixed sw, sh;
sw = INT2FIX(tr_state->visual->compositor->vp_width);
sh = INT2FIX(tr_state->visual->compositor->vp_height);
if (tr_state->visual->compositor->recompute_ar
|| (sw!=tr_state->camera->vp.width)
|| (sh!=tr_state->camera->vp.height)) {
tr_state->camera->width = tr_state->camera->vp.width = INT2FIX(tr_state->visual->compositor->vp_width);
tr_state->camera->height = tr_state->camera->vp.height = INT2FIX(tr_state->visual->compositor->vp_height);
tr_state->camera->flags |= CAM_IS_DIRTY;
}
}
}
else {
tr_state->camera->vp.width = tr_state->camera->width = INT2FIX(visual->width);
tr_state->camera->vp.height = tr_state->camera->height = INT2FIX(visual->height);
}
if (!tr_state->pixel_metrics) {
if (tr_state->camera->height > tr_state->camera->width) {
tr_state->camera->height = 2*gf_divfix(tr_state->camera->height , tr_state->camera->width);
tr_state->camera->width = 2*FIX_ONE;
} else {
tr_state->camera->width = 2 * gf_divfix(tr_state->camera->width, tr_state->camera->height);
tr_state->camera->height = 2 * FIX_ONE;
}
}
tr_state->bbox.max_edge.x = tr_state->camera->width / 2;
tr_state->bbox.min_edge.x = -tr_state->bbox.max_edge.x;
tr_state->bbox.max_edge.y = tr_state->camera->height / 2;
tr_state->bbox.min_edge.y = -tr_state->bbox.max_edge.y;
tr_state->bbox.max_edge.z = tr_state->bbox.min_edge.z = 0;
tr_state->bbox.is_set = 1;
}
void visual_3d_viewpoint_change(GF_TraverseState *tr_state, GF_Node *vp, Bool animate_change, Fixed fieldOfView, SFVec3f position, SFRotation orientation, SFVec3f local_center)
{
Fixed dist;
SFVec3f d;
tr_state->camera->z_near = tr_state->camera->avatar_size.x ;
if (tr_state->camera->z_near<=0) tr_state->camera->z_near = FIX_ONE/2;
else if (tr_state->camera->z_near>=FIX_ONE) tr_state->camera->z_near = FIX_ONE/2;
tr_state->camera->z_near /= 2;
tr_state->camera->z_far = tr_state->camera->visibility;
if (tr_state->camera->z_far<=0) {
Fixed ar = gf_divfix(tr_state->vp_size.x, tr_state->vp_size.y);
if (ar>FIX_ONE) ar = FIX_ONE;
tr_state->camera->z_far = gf_muldiv(
MAX(tr_state->vp_size.x,tr_state->vp_size.y),
MAX(tr_state->camera->width, tr_state->camera->height),
gf_mulfix(ar*2, gf_tan(fieldOfView/2))
);
if (tr_state->camera->z_far <= tr_state->camera->z_near) {
tr_state->camera->z_far = FIX_MAX/4;
}
}
if (vp) {
if (0 && gf_sg_use_pixel_metrics(gf_node_get_graph(vp))) {
GF_Matrix mx;
gf_mx_init(mx);
gf_mx_add_scale(&mx, tr_state->min_hsize, tr_state->min_hsize, tr_state->min_hsize);
gf_mx_apply_vec(&mx, &position);
gf_mx_apply_vec(&mx, &local_center);
}
}
else if (tr_state->pixel_metrics) {
if (tr_state->visual != tr_state->visual->compositor->visual) {
position.z = gf_divfix(tr_state->camera->width, 2*gf_tan(fieldOfView/2) );
} else {
position.z = gf_mulfix(position.z, tr_state->min_hsize);
}
}
#ifdef GF_SR_USE_DEPTH
if (tr_state->visual->compositor->auto_calibration && tr_state->visual->compositor->video_out->view_distance) {
Fixed view_distance, disparity;
view_distance = tr_state->visual->compositor->video_out->view_distance * tr_state->visual->compositor->video_out->dpi_x;
view_distance = gf_divfix(view_distance , FLT2FIX(2.54f) );
disparity = INT2FIX(tr_state->visual->compositor->video_out->disparity);
if (tr_state->visual->depth_vp_range) {
position.z = view_distance;
tr_state->camera->z_near = view_distance - tr_state->visual->depth_vp_position + tr_state->visual->depth_vp_range/2;
tr_state->camera->z_far = view_distance - tr_state->visual->depth_vp_position - tr_state->visual->depth_vp_range/2;
}
else if (disparity) {
Fixed half_interocular_dist_pixel = FLT2FIX(1.3386) * tr_state->visual->compositor->video_out->dpi_x;
position.z = view_distance;
tr_state->camera->z_near = view_distance -
gf_divfix( gf_mulfix(disparity,view_distance), (half_interocular_dist_pixel + disparity));
}
else if (tr_state->visual->compositor->display_depth) {
Fixed dist = INT2FIX(tr_state->visual->compositor->display_depth);
if (dist<0) dist = INT2FIX(tr_state->visual->height);
#if 1
view_distance = gf_divfix(tr_state->visual->height, 2*gf_tan(fieldOfView/2) );
#else
view_distance = gf_muldiv(view_distance, tr_state->visual->height, tr_state->visual->compositor->video_out->max_screen_height);
fieldOfView = 2*gf_atan2(tr_state->visual->height/2, view_distance);
#endif
position.z = view_distance;
tr_state->camera->z_near = view_distance - 2*dist/3;
tr_state->camera->z_far = view_distance + dist/2;
}
}
#endif
gf_vec_diff(d, position, local_center);
dist = gf_vec_len(d);
if (!dist || (dist<tr_state->camera->z_near) || (dist > tr_state->camera->z_far)) {
if (dist > tr_state->camera->z_far)
tr_state->camera->z_far = 2*dist;
dist = 10 * tr_state->camera->avatar_size.x;
if ((dist<tr_state->camera->z_near) || (dist > tr_state->camera->z_far))
dist = (tr_state->camera->avatar_size.x + tr_state->camera->z_far) / 5;
}
tr_state->camera->vp_dist = dist;
tr_state->camera->vp_position = position;
tr_state->camera->vp_orientation = orientation;
tr_state->camera->vp_fov = fieldOfView;
tr_state->camera->examine_center = local_center;
camera_reset_viewpoint(tr_state->camera, animate_change);
if (tr_state->layer3d) gf_node_dirty_set(tr_state->layer3d, GF_SG_VRML_BINDABLE_DIRTY, 0);
gf_sc_invalidate(tr_state->visual->compositor, NULL);
}
void visual_3d_setup_projection(GF_TraverseState *tr_state, Bool is_layer)
{
#ifndef GPAC_DISABLE_VRML
GF_Node *bindable;
#endif
u32 mode = tr_state->traversing_mode;
tr_state->traversing_mode = TRAVERSE_BINDABLE;
#ifndef GPAC_DISABLE_VRML
bindable = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
if (Bindable_GetIsBound(bindable)) {
gf_node_traverse(bindable, tr_state);
tr_state->camera->had_viewpoint = 1;
} else
#endif
if (tr_state->camera->had_viewpoint) {
u32 had_vp = tr_state->camera->had_viewpoint;
tr_state->camera->had_viewpoint = 0;
if (tr_state->camera->is_3D) {
SFVec3f pos, center;
SFRotation r;
Fixed fov = GF_PI/4;
#ifdef GF_SR_USE_DEPTH
if (tr_state->visual->compositor->auto_calibration && tr_state->visual->compositor->video_out->view_distance) {
Fixed view_distance = tr_state->visual->compositor->video_out->view_distance * tr_state->visual->compositor->video_out->dpi_x;
view_distance = gf_divfix(view_distance , FLT2FIX(2.54f) );
fov = 2*gf_atan2( INT2FIX(tr_state->visual->compositor->video_out->max_screen_width)/2, view_distance);
}
#endif
pos.x = pos.y = 0;
pos.z = INT2FIX(10);
center.x = center.y = center.z = 0;
r.q = r.x = r.z = 0;
r.y = FIX_ONE;
visual_3d_viewpoint_change(tr_state, NULL, 0, fov, pos, r, center);
if (had_vp == 2) {
camera_stop_anim(tr_state->camera);
camera_reset_viewpoint(tr_state->camera, 0);
if (!is_layer && gf_sc_fit_world_to_screen(tr_state->visual->compositor) == 0) {
tr_state->camera->had_viewpoint = 2;
}
}
} else {
tr_state->camera->flags &= ~CAM_HAS_VIEWPORT;
tr_state->camera->flags |= CAM_IS_DIRTY;
}
}
if (tr_state->visual->nb_views>1) {
s32 view_idx;
Fixed interocular_dist_pixel;
Fixed delta = 0;
interocular_dist_pixel = tr_state->visual->compositor->interoccular_distance + tr_state->visual->compositor->interoccular_offset;
view_idx = tr_state->visual->current_view;
view_idx -= tr_state->visual->nb_views/2;
delta = interocular_dist_pixel * view_idx;
if (! (tr_state->visual->nb_views % 2)) {
delta += interocular_dist_pixel/2;
}
if (tr_state->visual->reverse_views) delta = - delta;
tr_state->camera->flags |= CAM_IS_DIRTY;
camera_update_stereo(tr_state->camera, &tr_state->transform, tr_state->visual->center_coords, delta, tr_state->visual->compositor->video_out->view_distance, tr_state->visual->compositor->focus_distance, tr_state->visual->camera_layout);
} else {
camera_update(tr_state->camera, &tr_state->transform, tr_state->visual->center_coords);
}
visual_3d_projection_matrix_modified(tr_state->visual);
gf_mx_init(tr_state->model_matrix);
tr_state->traversing_mode = mode;
#ifdef GF_SR_USE_DEPTH
tr_state->depth_offset = 0;
tr_state->depth_gain = FIX_ONE;
#endif
}
static void visual_3d_draw_background(GF_TraverseState *tr_state, u32 layer_type)
{
u32 mode;
#ifndef GPAC_DISABLE_VRML
GF_Node *bindable;
#endif
mode = tr_state->traversing_mode;
tr_state->traversing_mode = TRAVERSE_BINDABLE;
if (layer_type) visual_3d_clear_depth(tr_state->visual);
if (layer_type==2) {
SFColor col;
col.red = INT2FIX((tr_state->visual->compositor->back_color>>16)&0xFF) / 255;
col.green = INT2FIX((tr_state->visual->compositor->back_color>>8)&0xFF) / 255;
col.blue = INT2FIX((tr_state->visual->compositor->back_color)&0xFF) / 255;
visual_3d_clear(tr_state->visual, col, 0);
}
#ifndef GPAC_DISABLE_VRML
bindable = (GF_Node*) gf_list_get(tr_state->backgrounds, 0);
if (Bindable_GetIsBound(bindable)) {
gf_node_traverse(bindable, tr_state);
}
else
#endif
if (!layer_type) {
SFColor col;
Fixed alpha = 0;
col.red = INT2FIX((tr_state->visual->compositor->back_color>>16)&0xFF) / 255;
col.green = INT2FIX((tr_state->visual->compositor->back_color>>8)&0xFF) / 255;
col.blue = INT2FIX((tr_state->visual->compositor->back_color)&0xFF) / 255;
if (tr_state->visual==tr_state->visual->compositor->visual) {
alpha = FIX_ONE;
if (tr_state->visual->compositor->user && (tr_state->visual->compositor->user->init_flags & GF_TERM_WINDOW_TRANSPARENT) ) {
alpha = 0;
}
}
visual_3d_clear(tr_state->visual, col, alpha);
}
tr_state->traversing_mode = mode;
}
static void visual_3d_draw_background_on_axis(GF_TraverseState *tr_state, u32 layer_type)
{
GF_Matrix proj, model;
GF_Camera *cam = &tr_state->visual->camera;
Fixed ar = gf_divfix(cam->width, cam->height);
tr_state->visual->camera_layout = 0;
gf_mx_copy(proj, cam->projection);
gf_mx_copy(model, cam->modelview);
gf_mx_perspective(&cam->projection, cam->fieldOfView, ar, cam->z_near, cam->z_far);
visual_3d_projection_matrix_modified(tr_state->visual);
gf_mx_lookat(&cam->modelview, cam->position, cam->target, cam->up);
visual_3d_draw_background(tr_state, layer_type);
tr_state->visual->camera_layout = GF_3D_CAMERA_OFFAXIS;
gf_mx_copy(cam->projection, proj);
gf_mx_copy(cam->modelview, model);
}
void visual_3d_init_draw(GF_TraverseState *tr_state, u32 layer_type)
{
#ifndef GPAC_DISABLE_VRML
GF_Node *bindable;
#endif
Bool off_axis_background = (tr_state->camera->is_3D && (tr_state->visual->camera_layout==GF_3D_CAMERA_OFFAXIS)) ? 1 : 0;
tr_state->traversing_mode = TRAVERSE_BINDABLE;
#ifndef GPAC_DISABLE_VRML
bindable = tr_state->navigations ? (GF_Node*) gf_list_get(tr_state->navigations, 0) : NULL;
if (Bindable_GetIsBound(bindable)) {
gf_node_traverse(bindable, tr_state);
tr_state->camera->had_nav_info = 1;
} else
#endif
if (tr_state->camera->had_nav_info) {
tr_state->camera->avatar_size.x = FLT2FIX(0.25f);
tr_state->camera->avatar_size.y = FLT2FIX(1.6f);
tr_state->camera->avatar_size.z = FLT2FIX(0.75f);
tr_state->camera->visibility = 0;
tr_state->camera->speed = FIX_ONE;
if (layer_type) {
tr_state->camera->navigation_flags = NAV_HEADLIGHT;
tr_state->camera->navigate_mode = GF_NAVIGATE_NONE;
} else {
tr_state->camera->navigation_flags = NAV_ANY | NAV_HEADLIGHT;
if (tr_state->camera->is_3D) {
if (tr_state->visual->compositor->default_navigation_mode != GF_NAVIGATE_NONE) {
tr_state->camera->navigate_mode = tr_state->visual->compositor->default_navigation_mode;
} else {
tr_state->camera->navigate_mode = (tr_state->visual->type_3d==3) ? GF_NAVIGATE_EXAMINE : GF_NAVIGATE_WALK;
}
#ifdef GF_SR_USE_DEPTH
#endif
} else {
tr_state->camera->navigate_mode = GF_NAVIGATE_NONE;
}
}
tr_state->camera->had_nav_info = 0;
if (tr_state->pixel_metrics) {
tr_state->camera->visibility = gf_mulfix(tr_state->camera->visibility, tr_state->min_hsize);
tr_state->camera->avatar_size.x = gf_mulfix(tr_state->camera->avatar_size.x, tr_state->min_hsize);
tr_state->camera->avatar_size.y = gf_mulfix(tr_state->camera->avatar_size.y, tr_state->min_hsize);
tr_state->camera->avatar_size.z = gf_mulfix(tr_state->camera->avatar_size.z, tr_state->min_hsize);
}
}
if (camera_animate(tr_state->camera)) {
if (tr_state->visual->compositor->active_layer) gf_node_dirty_set(tr_state->visual->compositor->active_layer, 0, 1);
gf_sc_invalidate(tr_state->visual->compositor, NULL);
}
visual_3d_enable_depth_buffer(tr_state->visual, tr_state->camera->is_3D);
if ((tr_state->visual->autostereo_type==GF_3D_STEREO_SIDE) || (tr_state->visual->autostereo_type==GF_3D_STEREO_HEADSET)) {
GF_Rect orig_vp = tr_state->camera->vp;
Fixed vp_width = orig_vp.width;
Fixed old_w = tr_state->camera->width;
Fixed old_h = tr_state->camera->height;
if (tr_state->visual->autostereo_type==GF_3D_STEREO_HEADSET) {
Fixed max_width = INT2FIX(tr_state->visual->compositor->display_width) / tr_state->visual->nb_views;
Fixed max_height = INT2FIX(tr_state->visual->compositor->display_height);
#if 0
Fixed ratio = gf_divfix(vp_width, vp_height);
if (max_width < gf_mulfix(ratio, max_height) ) {
tr_state->camera->vp.width = max_width;
} else {
tr_state->camera->vp.width = gf_mulfix(ratio, max_height);
}
tr_state->camera->vp.height = gf_divfix(tr_state->camera->vp.width, ratio);
#else
tr_state->camera->vp.width = max_width;
tr_state->camera->vp.height = max_height;
#endif
tr_state->camera->width = max_width;
tr_state->camera->height = max_height;
tr_state->camera->vp.x = (INT2FIX(tr_state->visual->compositor->display_width) - tr_state->visual->nb_views*tr_state->camera->vp.width)/2 + tr_state->visual->current_view * tr_state->camera->vp.width;
tr_state->camera->vp.y = (INT2FIX(tr_state->visual->compositor->display_height) - tr_state->camera->vp.height)/2;
} else {
tr_state->camera->vp.width = vp_width / tr_state->visual->nb_views;
tr_state->camera->vp.x += tr_state->visual->current_view * tr_state->camera->vp.width;
}
if (!tr_state->visual->current_view) {
SFColor col;
col.red = INT2FIX((tr_state->visual->compositor->back_color>>16)&0xFF) / 255;
col.green = INT2FIX((tr_state->visual->compositor->back_color>>8)&0xFF) / 255;
col.blue = INT2FIX((tr_state->visual->compositor->back_color)&0xFF) / 255;
visual_3d_set_viewport(tr_state->visual, orig_vp);
visual_3d_clear(tr_state->visual, col, 0);
}
visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
visual_3d_set_scissor(tr_state->visual, &tr_state->camera->vp);
if (off_axis_background) {
visual_3d_draw_background_on_axis(tr_state, layer_type);
}
visual_3d_setup_projection(tr_state, layer_type);
tr_state->camera->vp = orig_vp;
tr_state->camera->width = old_w;
tr_state->camera->height = old_h;
} else if (tr_state->visual->autostereo_type==GF_3D_STEREO_TOP) {
GF_Rect orig_vp;
orig_vp = tr_state->camera->vp;
tr_state->camera->vp.height = tr_state->camera->vp.height / tr_state->visual->nb_views;
if (tr_state->visual == tr_state->visual->compositor->visual) {
Fixed remain = INT2FIX(tr_state->visual->compositor->output_height - orig_vp.height) / tr_state->visual->nb_views;
tr_state->camera->vp.y = remain/2 + tr_state->visual->current_view*remain + tr_state->visual->current_view *tr_state->camera->vp.height;
} else {
tr_state->camera->vp.y = tr_state->visual->height - tr_state->camera->vp.y - tr_state->camera->vp.height;
}
visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
visual_3d_set_scissor(tr_state->visual, &tr_state->camera->vp);
if (off_axis_background) {
visual_3d_draw_background_on_axis(tr_state, layer_type);
}
visual_3d_setup_projection(tr_state, layer_type);
tr_state->camera->vp = orig_vp;
} else {
visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp);
if (off_axis_background) {
visual_3d_draw_background_on_axis(tr_state, layer_type);
}
visual_3d_setup_projection(tr_state, layer_type);
if (tr_state->visual->autostereo_type) {
visual_3d_clear_depth(tr_state->visual);
}
}
if (!tr_state->camera->is_3D || tr_state->visual->camera_layout != GF_3D_CAMERA_OFFAXIS) {
visual_3d_draw_background(tr_state, layer_type);
}
if (tr_state->visual->type_3d>1) {
visual_3d_enable_headlight(tr_state->visual, (tr_state->camera->navigation_flags & NAV_HEADLIGHT) ? 1 : 0, tr_state->camera);
}
visual_3d_set_scissor(tr_state->visual, NULL);
}
static GFINLINE Bool visual_3d_has_alpha(GF_TraverseState *tr_state, GF_Node *geom)
{
Bool is_mat3D;
Drawable3D *stack;
is_mat3D = 0;
#ifndef GPAC_DISABLE_VRML
if (tr_state->appear) {
GF_Node *mat = ((M_Appearance *)tr_state->appear)->material;
if (mat) {
u32 tag = gf_node_get_tag(mat);
switch (tag) {
case TAG_MPEG4_Material2D:
if (((M_Material2D *)mat)->filled && ((M_Material2D *)mat)->transparency) return 1;
break;
case TAG_MPEG4_Material:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_Material:
#endif
is_mat3D = 1;
if ( ((M_Material *)mat)->transparency) return 1;
break;
case TAG_MPEG4_MaterialKey:
return 1;
break;
}
} else if (tr_state->camera->is_3D) {
GF_TextureHandler *txh = gf_sc_texture_get_handler(((M_Appearance *)tr_state->appear)->texture);
if (txh && txh->transparent) return 1;
}
}
if (tr_state->appear && ( is_mat3D || (gf_node_get_tag(geom)==TAG_MPEG4_Bitmap))) {
GF_TextureHandler *txh = gf_sc_texture_get_handler(((M_Appearance *)tr_state->appear)->texture);
if (txh && txh->transparent) return 1;
}
#endif
if (!tr_state->color_mat.identity) return 1;
stack = (Drawable3D *)gf_node_get_private(geom);
if (stack && stack->mesh && (stack->mesh->flags & MESH_HAS_ALPHA)) return 1;
return 0;
}
void visual_3d_register_context(GF_TraverseState *tr_state, GF_Node *geometry)
{
u32 i, count;
DirectionalLightContext *nl, *ol;
Drawable3DContext *ctx;
Drawable3D *drawable;
assert(tr_state->traversing_mode == TRAVERSE_SORT);
drawable = (Drawable3D*)gf_node_get_private(geometry);
if (!tr_state->camera->is_3D || !visual_3d_has_alpha(tr_state, geometry) || !drawable->mesh) {
tr_state->traversing_mode = TRAVERSE_DRAW_3D;
if (tr_state->has_clip) {
visual_3d_set_clipper_2d(tr_state->visual, tr_state->clipper, NULL);
}
gf_node_traverse(geometry, tr_state);
if (tr_state->appear)
gf_node_dirty_clear(tr_state->appear, 0);
tr_state->traversing_mode = TRAVERSE_SORT;
if (tr_state->has_clip) visual_3d_reset_clipper_2d(tr_state->visual);
return;
}
GF_SAFEALLOC(ctx, Drawable3DContext);
if (!ctx) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate drawable 3D context\n"));
return;
}
ctx->directional_lights = gf_list_new();
ctx->geometry = geometry;
ctx->appearance = tr_state->appear;
memcpy(&ctx->model_matrix, &tr_state->model_matrix, sizeof(GF_Matrix));
ctx->color_mat.identity = tr_state->color_mat.identity;
if (!tr_state->color_mat.identity) memcpy(&ctx->color_mat, &tr_state->color_mat, sizeof(GF_ColorMatrix));
ctx->pixel_metrics = tr_state->pixel_metrics;
ctx->text_split_idx = tr_state->text_split_idx;
i=0;
while ((ol = (DirectionalLightContext*)gf_list_enum(tr_state->local_lights, &i))) {
nl = (DirectionalLightContext*)gf_malloc(sizeof(DirectionalLightContext));
memcpy(nl, ol, sizeof(DirectionalLightContext));
gf_list_add(ctx->directional_lights, nl);
}
ctx->clipper = tr_state->clipper;
ctx->has_clipper = tr_state->has_clip;
ctx->cull_flag = tr_state->cull_flag;
if ((ctx->num_clip_planes = tr_state->num_clip_planes))
memcpy(ctx->clip_planes, tr_state->clip_planes, sizeof(GF_Plane)*MAX_USER_CLIP_PLANES);
tr_state->bbox = drawable->mesh->bounds;
gf_mx_apply_bbox(&ctx->model_matrix, &tr_state->bbox);
gf_mx_apply_bbox(&tr_state->camera->modelview, &tr_state->bbox);
ctx->zmax = tr_state->bbox.max_edge.z;
#ifdef GF_SR_USE_DEPTH
ctx->depth_offset=tr_state->depth_offset;
#endif
count = gf_list_count(tr_state->visual->alpha_nodes_to_draw);
for (i=0; i<count; i++) {
Drawable3DContext *next = (Drawable3DContext *)gf_list_get(tr_state->visual->alpha_nodes_to_draw, i);
if (next->zmax>ctx->zmax) {
gf_list_insert(tr_state->visual->alpha_nodes_to_draw, ctx, i);
return;
}
}
gf_list_add(tr_state->visual->alpha_nodes_to_draw, ctx);
}
void visual_3d_flush_contexts(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
u32 i, idx, count;
Bool pixel_metrics = tr_state->pixel_metrics;
tr_state->traversing_mode = TRAVERSE_DRAW_3D;
count = gf_list_count(visual->alpha_nodes_to_draw);
for (idx=0; idx<count; idx++) {
DirectionalLightContext *dl;
Drawable3DContext *ctx = (Drawable3DContext *)gf_list_get(visual->alpha_nodes_to_draw, idx);
tr_state->local_light_on = 1;
i=0;
while ((dl = (DirectionalLightContext*)gf_list_enum(ctx->directional_lights, &i))) {
GF_Matrix mx;
gf_mx_copy(mx, tr_state->model_matrix);
gf_mx_add_matrix(&tr_state->model_matrix, &dl->light_matrix);
gf_node_traverse(dl->dlight, tr_state);
gf_mx_copy(tr_state->model_matrix, mx);
}
if (ctx->has_clipper) {
visual_3d_set_clipper_2d(visual, ctx->clipper, NULL);
}
for (i=0; i<ctx->num_clip_planes; i++)
visual_3d_set_clip_plane(visual, ctx->clip_planes[i], NULL, 0);
memcpy(&tr_state->model_matrix, &ctx->model_matrix, sizeof(GF_Matrix));
tr_state->color_mat.identity = ctx->color_mat.identity;
if (!tr_state->color_mat.identity) memcpy(&tr_state->color_mat, &ctx->color_mat, sizeof(GF_ColorMatrix));
tr_state->text_split_idx = ctx->text_split_idx;
tr_state->pixel_metrics = ctx->pixel_metrics;
tr_state->cull_flag = ctx->cull_flag;
tr_state->appear = ctx->appearance;
#ifdef GF_SR_USE_DEPTH
tr_state->depth_offset = ctx->depth_offset;
#endif
gf_node_traverse(ctx->geometry, tr_state);
if (tr_state->appear) {
gf_node_dirty_clear(tr_state->appear, 0);
tr_state->appear = NULL;
}
tr_state->local_light_on = 0;
for (i=gf_list_count(ctx->directional_lights); i>0; i--) {
DirectionalLightContext *dl = (DirectionalLightContext*)gf_list_get(ctx->directional_lights, i-1);
gf_node_traverse(dl->dlight, tr_state);
gf_free(dl);
}
if (ctx->has_clipper) visual_3d_reset_clipper_2d(visual);
for (i=0; i<ctx->num_clip_planes; i++) visual_3d_reset_clip_plane(visual);
gf_list_del(ctx->directional_lights);
gf_free(ctx);
}
tr_state->pixel_metrics = pixel_metrics;
gf_list_reset(tr_state->visual->alpha_nodes_to_draw);
}
static void visual_3d_draw_node(GF_TraverseState *tr_state, GF_Node *root_node)
{
#ifndef GPAC_DISABLE_VRML
GF_Node *fog;
#endif
if (!tr_state->camera || !tr_state->visual) return;
visual_3d_init_draw(tr_state, 0);
if ((tr_state->visual==tr_state->visual->compositor->visual) && tr_state->camera->is_3D)
visual_3d_check_collisions(tr_state, root_node, NULL);
#ifndef GPAC_DISABLE_VRML
fog = (GF_Node*) gf_list_get(tr_state->visual->fog_stack, 0);
tr_state->traversing_mode = TRAVERSE_BINDABLE;
if (Bindable_GetIsBound(fog)) gf_node_traverse(fog, tr_state);
#endif
if (tr_state->visual->type_3d>1) {
tr_state->traversing_mode = TRAVERSE_LIGHTING;
gf_node_traverse(root_node, tr_state);
}
tr_state->traversing_mode = TRAVERSE_SORT;
gf_node_traverse(root_node, tr_state);
visual_3d_flush_contexts(tr_state->visual, tr_state);
visual_3d_clear_all_lights(tr_state->visual);
}
void visual_3d_setup_clipper(GF_VisualManager *visual, GF_TraverseState *tr_state)
{
GF_Rect rc;
if (visual->center_coords) {
rc = gf_rect_center(INT2FIX(visual->width), INT2FIX(visual->height));
} else {
rc.width = INT2FIX(visual->width);
rc.height = INT2FIX(visual->height);
rc.x = 0;
rc.y = rc.height;
if (visual->compositor->visual==visual) {
rc.x += INT2FIX(visual->compositor->vp_x);
rc.y += INT2FIX(visual->compositor->vp_y);
}
}
#ifndef GPAC_DISABLE_VRML
if (gf_list_count(visual->view_stack)) {
tr_state->traversing_mode = TRAVERSE_BINDABLE;
tr_state->bounds = rc;
gf_node_traverse((GF_Node *) gf_list_get(visual->view_stack, 0), tr_state);
}
#endif
visual->top_clipper = gf_rect_pixelize(&rc);
tr_state->clipper = rc;
gf_mx_init(tr_state->layer_matrix);
}
Bool visual_3d_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseState *tr_state, Bool is_root_visual)
{
#ifndef GPAC_DISABLE_LOG
u32 time = gf_sys_clock();
#endif
visual_3d_setup(visual);
visual->glsl_flags = 0;
visual_3d_setup_traversing_state(visual, tr_state);
if (is_root_visual) {
Bool auto_stereo = 0;
visual_3d_setup_clipper(visual, tr_state);
if (tr_state->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER) {
visual_3d_init_autostereo(visual);
auto_stereo = 1;
}
#ifndef GPAC_USE_GLES1X
visual_3d_init_shaders(visual);
#endif
for (visual->current_view=0; visual->current_view < visual->nb_views; visual->current_view++) {
GF_SceneGraph *sg;
u32 i;
visual_3d_draw_node(tr_state, root);
i=0;
while ((sg = (GF_SceneGraph*)gf_list_enum(visual->compositor->extra_scenes, &i))) {
tr_state->traversing_mode = TRAVERSE_SORT;
gf_sc_traverse_subscene(visual->compositor, root, sg, tr_state);
}
if (auto_stereo) {
visual_3d_end_auto_stereo_pass(visual);
}
if (is_root_visual) visual->compositor->reset_graphics = 0;
}
} else {
visual_3d_draw_node(tr_state, root);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI] Frame\t%d\t3D drawn in \t%d\tms\n", visual->compositor->frame_number, gf_sys_clock() - time));
return 1;
}
static void reset_collide_cursor(GF_Compositor *compositor)
{
if (compositor->sensor_type == GF_CURSOR_COLLIDE) {
GF_Event evt;
compositor->sensor_type = evt.cursor.cursor_type = GF_CURSOR_NORMAL;
evt.type = GF_EVENT_SET_CURSOR;
compositor->video_out->ProcessEvent(compositor->video_out, &evt);
}
}
void visual_3d_check_collisions(GF_TraverseState *tr_state, GF_Node *on_node, GF_ChildNodeItem *node_list)
{
SFVec3f n, dir;
Bool go;
Fixed diff, pos_diff;
assert(tr_state->visual && tr_state->camera);
if ((tr_state->camera->anim_len && !tr_state->camera->jumping) || !tr_state->visual->compositor->collide_mode || (tr_state->camera->navigate_mode>=GF_NAVIGATE_EXAMINE)) {
tr_state->camera->last_had_ground = 0;
tr_state->camera->last_pos = tr_state->camera->position;
return;
}
if (gf_vec_equal(tr_state->camera->position, tr_state->camera->last_pos)) {
reset_collide_cursor(tr_state->visual->compositor);
return;
}
tr_state->traversing_mode = TRAVERSE_COLLIDE;
tr_state->camera->collide_flags = 0;
tr_state->camera->collide_dist = FIX_MAX;
tr_state->camera->ground_dist = FIX_MAX;
if ((tr_state->camera->navigate_mode==GF_NAVIGATE_WALK) && tr_state->visual->compositor->gravity_on) tr_state->camera->collide_flags |= CF_DO_GRAVITY;
gf_vec_diff(dir, tr_state->camera->position, tr_state->camera->last_pos);
pos_diff = gf_vec_len(dir);
gf_vec_norm(&dir);
diff = 0;
go = 1;
tr_state->camera->last_had_col = 0;
while (go) {
if (pos_diff>tr_state->camera->avatar_size.x) {
pos_diff-=tr_state->camera->avatar_size.x;
diff += tr_state->camera->avatar_size.x;
} else {
diff += pos_diff;
go = 0;
}
n = gf_vec_scale(dir, diff);
gf_vec_add(tr_state->camera->position, tr_state->camera->last_pos, n);
if (on_node) {
gf_node_traverse(on_node, tr_state);
} else if (node_list) {
while (node_list) {
gf_node_traverse(node_list->node, tr_state);
node_list = node_list->next;
}
}
if (tr_state->camera->collide_flags & CF_COLLISION) break;
tr_state->camera->collide_flags &= ~CF_DO_GRAVITY;
}
if (tr_state->camera->collide_flags & CF_GRAVITY) {
diff = tr_state->camera->ground_dist - tr_state->camera->avatar_size.y;
if (tr_state->camera->last_had_ground && (-diff>tr_state->camera->avatar_size.z)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Obstacle detected - too high (dist %g)\n", FIX2FLT(diff)));
tr_state->camera->position = tr_state->camera->last_pos;
tr_state->camera->flags |= CAM_IS_DIRTY;
} else {
if ((tr_state->camera->jumping && fabs(diff)>tr_state->camera->dheight)
|| (!tr_state->camera->jumping && (ABS(diff)>FIX_ONE/1000) )) {
tr_state->camera->last_had_ground = 1;
n = gf_vec_scale(tr_state->camera->up, -diff);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Ground detected camera position: %g %g %g - offset: %g %g %g (dist %g)\n",
FIX2FLT(tr_state->camera->position.x), FIX2FLT(tr_state->camera->position.y), FIX2FLT(tr_state->camera->position.z),
FIX2FLT(n.x), FIX2FLT(n.y), FIX2FLT(n.z), FIX2FLT(diff)));
gf_vec_add(tr_state->camera->position, tr_state->camera->position, n);
gf_vec_add(tr_state->camera->target, tr_state->camera->target, n);
gf_vec_add(tr_state->camera->last_pos, tr_state->camera->position, n);
tr_state->camera->flags |= CAM_IS_DIRTY;
}
}
}
if (tr_state->camera->collide_flags & CF_COLLISION) {
if (tr_state->visual->compositor->sensor_type != GF_CURSOR_COLLIDE) {
GF_Event evt;
tr_state->camera->last_had_col = 1;
evt.type = GF_EVENT_SET_CURSOR;
tr_state->visual->compositor->sensor_type = evt.cursor.cursor_type = GF_CURSOR_COLLIDE;
tr_state->visual->compositor->video_out->ProcessEvent(tr_state->visual->compositor->video_out, &evt);
}
if (tr_state->visual->compositor->collide_mode==GF_COLLISION_NORMAL) {
tr_state->camera->position = tr_state->camera->last_pos;
tr_state->camera->flags |= CAM_IS_DIRTY;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Collision detected - restoring previous avatar position\n"));
} else {
if (tr_state->camera->collide_dist) {
if (tr_state->camera->collide_dist>=tr_state->camera->avatar_size.x)
GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Collision] Collision distance %g greater than avatar collide size %g\n", FIX2FLT(tr_state->camera->collide_dist), FIX2FLT(tr_state->camera->avatar_size.x)));
if (tr_state->camera->collide_dist>=tr_state->camera->avatar_size.x) tr_state->camera->collide_dist = tr_state->camera->avatar_size.x;
gf_vec_diff(n, tr_state->camera->position, tr_state->camera->collide_point);
gf_vec_norm(&n);
n = gf_vec_scale(n, tr_state->camera->avatar_size.x - tr_state->camera->collide_dist);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] offseting camera: position: %g %g %g - offset: %g %g %g\n",
FIX2FLT(tr_state->camera->position.x), FIX2FLT(tr_state->camera->position.y), FIX2FLT(tr_state->camera->position.z),
FIX2FLT(n.x), FIX2FLT(n.y), FIX2FLT(n.z)));
gf_vec_add(tr_state->camera->position, tr_state->camera->position, n);
gf_vec_add(tr_state->camera->target, tr_state->camera->target, n);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Collision detected and camera on hit point - restoring previous avatar position\n"));
tr_state->camera->position = tr_state->camera->last_pos;
}
tr_state->camera->last_pos = tr_state->camera->position;
tr_state->camera->flags |= CAM_IS_DIRTY;
}
} else {
reset_collide_cursor(tr_state->visual->compositor);
tr_state->camera->last_pos = tr_state->camera->position;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] no collision found\n"));
}
if (tr_state->camera->flags & CAM_IS_DIRTY) visual_3d_setup_projection(tr_state, 0);
}
#ifndef GPAC_DISABLE_LOG
static const char *szPlaneNames [] =
{
"Near", "Far", "Left", "Right", "Bottom", "Top"
};
#endif
Bool visual_3d_node_cull(GF_TraverseState *tr_state, GF_BBox *bbox, Bool skip_near)
{
#ifdef DISABLE_VIEW_CULL
tr_state->cull_flag = CULL_INSIDE;
return 1;
#else
GF_BBox b;
Fixed irad, rad;
GF_Camera *cam;
Bool do_sphere;
u32 i, p_idx;
SFVec3f cdiff, vertices[8];
if (!tr_state->camera || (tr_state->cull_flag == CULL_INSIDE)) return 1;
assert(tr_state->cull_flag != CULL_OUTSIDE);
if (!bbox->is_set) {
tr_state->cull_flag = CULL_OUTSIDE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node out (bbox not set)\n"));
return 0;
}
b = *bbox;
gf_mx_apply_bbox_sphere(&tr_state->model_matrix, &b);
cam = tr_state->camera;
if (gf_bbox_point_inside(&b, &cam->position)) {
tr_state->cull_flag = CULL_INTERSECTS;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node intersect (camera in box test)\n"));
return 1;
}
if (tr_state->camera->is_3D) {
gf_vec_diff(cdiff, cam->center, b.center);
rad = b.radius + cam->radius;
if (gf_vec_len(cdiff) > rad) {
tr_state->cull_flag = CULL_OUTSIDE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node out (sphere-sphere test)\n"));
return 0;
}
}
rad = b.radius;
irad = -b.radius;
do_sphere = 1;
i = (tr_state->camera->is_3D) ? (skip_near ? 1 : 0) : 2;
for (; i<6; i++) {
Fixed d;
if (do_sphere) {
d = gf_plane_get_distance(&cam->planes[i], &b.center);
if (d<irad) {
tr_state->cull_flag = CULL_OUTSIDE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node out (sphere-planes test) plane %s\n", szPlaneNames[i]));
return 0;
}
if (d<rad) {
b = *bbox;
gf_mx_apply_bbox(&tr_state->model_matrix, &b);
gf_bbox_get_vertices(b.min_edge, b.max_edge, vertices);
do_sphere = 0;
} else {
continue;
}
}
p_idx = cam->p_idx[i];
d = gf_plane_get_distance(&cam->planes[i], &vertices[p_idx]);
if (d<0) {
tr_state->cull_flag = CULL_OUTSIDE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node out (p-vertex test) plane %s - Distance %g\n", szPlaneNames[i], FIX2FLT(d) ));
return 0;
}
if (i>1) {
d = gf_plane_get_distance(&cam->planes[i], &vertices[7-p_idx]);
if (d<0) {
tr_state->cull_flag = CULL_INTERSECTS;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node intersect (n-vertex test) plane %s - Distance %g\n", szPlaneNames[i], FIX2FLT(d) ));
return 1;
}
}
}
tr_state->cull_flag = CULL_INSIDE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Culling] Node inside (%s test)\n", do_sphere ? "sphere-planes" : "n-p vertex"));
return 1;
#endif
}
void visual_3d_pick_node(GF_VisualManager *visual, GF_TraverseState *tr_state, GF_Event *ev, GF_ChildNodeItem *children)
{
Fixed in_x, in_y, x, y;
SFVec3f start, end;
SFVec4f res;
visual_3d_setup_traversing_state(visual, tr_state);
visual_3d_setup_projection(tr_state, 0);
x = INT2FIX(ev->mouse.x);
y = INT2FIX(ev->mouse.y);
if (!visual->center_coords) {
x = x - INT2FIX(tr_state->camera->width)/2;
y = INT2FIX(tr_state->camera->height)/2 - y;
}
if ((visual->compositor->visual == visual) && visual->compositor->has_size_info) {
Fixed scale = gf_divfix(INT2FIX(visual->width), INT2FIX(visual->compositor->vp_width));
x = gf_mulfix(x, scale);
scale = gf_divfix(INT2FIX(visual->height), INT2FIX(visual->compositor->vp_height));
y = gf_mulfix(y, scale);
}
start.z = visual->camera.z_near;
end.z = visual->camera.z_far;
if (!tr_state->camera->is_3D && !tr_state->pixel_metrics) {
start.x = end.x = gf_divfix(x, tr_state->min_hsize);
start.y = end.y = gf_divfix(y, tr_state->min_hsize);
} else {
start.x = end.x = x;
start.y = end.y = y;
}
in_x = 2*x/ (s32) visual->width;
in_y = 2*y/ (s32) visual->height;
res.x = in_x;
res.y = in_y;
res.z = -FIX_ONE;
res.q = FIX_ONE;
gf_mx_apply_vec_4x4(&visual->camera.unprojection, &res);
if (!res.q) return;
start.x = gf_divfix(res.x, res.q);
start.y = gf_divfix(res.y, res.q);
start.z = gf_divfix(res.z, res.q);
res.x = in_x;
res.y = in_y;
res.z = FIX_ONE;
res.q = FIX_ONE;
gf_mx_apply_vec_4x4(&visual->camera.unprojection, &res);
if (!res.q) return;
end.x = gf_divfix(res.x, res.q);
end.y = gf_divfix(res.y, res.q);
end.z = gf_divfix(res.z, res.q);
tr_state->ray = gf_ray(start, end);
visual->compositor->hit_world_ray = tr_state->ray;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Picking] cast ray\n\tOrigin %.4f %.4f %.4f - End %.4f %.4f %.4f\n\tDir %.4f %.4f %.4f\n",
FIX2FLT(tr_state->ray.orig.x), FIX2FLT(tr_state->ray.orig.y), FIX2FLT(tr_state->ray.orig.z),
FIX2FLT(end.x), FIX2FLT(end.y), FIX2FLT(end.z),
FIX2FLT(tr_state->ray.dir.x), FIX2FLT(tr_state->ray.dir.y), FIX2FLT(tr_state->ray.dir.z)));
visual->compositor->hit_square_dist = 0;
visual->compositor->hit_node = NULL;
gf_list_reset(visual->compositor->sensors);
if (visual->compositor->visual != visual) {
while (children) {
gf_node_traverse(children->node, tr_state);
children = children->next;
}
} else {
gf_node_traverse(gf_sg_get_root_node(visual->compositor->scene), tr_state);
}
}
#ifndef GPAC_DISABLE_VRML
void visual_3d_vrml_drawable_pick(GF_Node *n, GF_TraverseState *tr_state, GF_Mesh *mesh, Drawable *drawable)
{
SFVec3f local_pt, world_pt, vdiff;
SFVec3f hit_normal;
SFVec2f text_coords;
u32 i, count;
Fixed sqdist;
Bool node_is_over;
GF_Compositor *compositor;
GF_Matrix mx;
GF_Ray r;
u32 cull_bckup = tr_state->cull_flag;
if (!mesh && !drawable) return;
count = gf_list_count(tr_state->vrml_sensors);
compositor = tr_state->visual->compositor;
if (mesh) {
if (mesh->mesh_type!=MESH_TRIANGLES)
return;
if (!visual_3d_node_cull(tr_state, &mesh->bounds, 0)) {
tr_state->cull_flag = cull_bckup;
return;
}
}
tr_state->cull_flag = cull_bckup;
r = tr_state->ray;
gf_mx_copy(mx, tr_state->model_matrix);
gf_mx_inverse(&mx);
gf_mx_apply_ray(&mx, &r);
if (compositor->hit_square_dist && !compositor->grabbed_sensor && !tr_state->layer3d) {
GF_Plane p;
GF_BBox box;
SFVec3f hit = compositor->hit_world_point;
gf_mx_apply_vec(&mx, &hit);
p.normal = r.dir;
p.d = -1 * gf_vec_dot(p.normal, hit);
if (mesh)
box = mesh->bounds;
else
gf_bbox_from_rect(&box, &drawable->path->bbox);
if (gf_bbox_plane_relation(&box, &p) == GF_BBOX_FRONT) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Picking] bounding box of node %s (DEF %s) below current hit point - skipping\n", gf_node_get_class_name(n), gf_node_get_name(n)));
return;
}
}
if (drawable) {
DrawAspect2D asp;
node_is_over = 0;
if (compositor_get_2d_plane_intersection(&r, &local_pt)) {
if (gf_path_point_over(drawable->path, local_pt.x, local_pt.y)) {
hit_normal.x = hit_normal.y = 0;
hit_normal.z = FIX_ONE;
text_coords.x = gf_divfix(local_pt.x, drawable->path->bbox.width) + FIX_ONE/2;
text_coords.y = gf_divfix(local_pt.y, drawable->path->bbox.height) + FIX_ONE/2;
node_is_over = 1;
}
memset(&asp, 0, sizeof(DrawAspect2D));
drawable_get_aspect_2d_mpeg4(drawable->node, &asp, tr_state);
if (asp.pen_props.width || asp.line_texture ) {
StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, &asp, tr_state->appear, NULL, 0, NULL);
if (si && si->outline && gf_path_point_over(si->outline, local_pt.x, local_pt.y)) {
hit_normal.x = hit_normal.y = 0;
hit_normal.z = FIX_ONE;
text_coords.x = gf_divfix(local_pt.x, si->outline->bbox.width) + FIX_ONE/2;
text_coords.y = gf_divfix(local_pt.y, si->outline->bbox.height) + FIX_ONE/2;
node_is_over = 1;
}
}
}
} else {
node_is_over = gf_mesh_intersect_ray(mesh, &r, &local_pt, &hit_normal, &text_coords);
}
if (!node_is_over) return;
world_pt = local_pt;
gf_mx_apply_vec(&tr_state->model_matrix, &world_pt);
for (i=0; i<tr_state->num_clip_planes; i++) {
if (gf_plane_get_distance(&tr_state->clip_planes[i], &world_pt) < 0) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Picking] node %s (def %s) is not in clipper half space\n", gf_node_get_class_name(n), gf_node_get_name(n)));
return;
}
}
gf_vec_diff(vdiff, world_pt, tr_state->ray.orig);
sqdist = gf_vec_lensq(vdiff);
if (compositor->hit_square_dist && (compositor->hit_square_dist+FIX_EPSILON<sqdist)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Picking] node %s (def %s) is farther (%g) than current pick (%g)\n", gf_node_get_class_name(n), gf_node_get_name(n), FIX2FLT(sqdist), FIX2FLT(compositor->hit_square_dist)));
return;
}
compositor->hit_square_dist = sqdist;
gf_list_reset(compositor->sensors);
for (i=0; i<count; i++) {
gf_list_add(compositor->sensors, gf_list_get(tr_state->vrml_sensors, i));
}
gf_mx_copy(compositor->hit_world_to_local, tr_state->model_matrix);
gf_mx_copy(compositor->hit_local_to_world, mx);
compositor->hit_local_point = local_pt;
compositor->hit_world_point = world_pt;
compositor->hit_world_ray = tr_state->ray;
compositor->hit_normal = hit_normal;
compositor->hit_texcoords = text_coords;
if (compositor_is_composite_texture(tr_state->appear)) {
compositor->hit_appear = tr_state->appear;
} else {
compositor->hit_appear = NULL;
}
compositor->hit_node = n;
compositor->hit_use_dom_events = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Picking] node %s (def %s) is under mouse - hit %g %g %g\n", gf_node_get_class_name(n), gf_node_get_name(n),
FIX2FLT(world_pt.x), FIX2FLT(world_pt.y), FIX2FLT(world_pt.z)));
}
void visual_3d_vrml_drawable_collide(GF_Node *node, GF_TraverseState *tr_state)
{
SFVec3f pos, v1, v2, collide_pt, last_pos;
Fixed dist, m_dist;
GF_Matrix mx;
u32 cull_backup;
Drawable3D *st = (Drawable3D *)gf_node_get_private(node);
if (!st || !st->mesh) return;
if (st->mesh->mesh_type != MESH_TRIANGLES) return;
#ifndef GPAC_DISABLE_VRML
switch (gf_node_get_tag(node)) {
case TAG_MPEG4_Text:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_Text:
#endif
return;
}
#endif
cull_backup = tr_state->cull_flag;
if (!visual_3d_node_cull(tr_state, &st->mesh->bounds, 1)) {
tr_state->cull_flag = cull_backup;
return;
}
tr_state->cull_flag = cull_backup;
pos = tr_state->camera->position;
last_pos = tr_state->camera->last_pos;
v1 = camera_get_target_dir(tr_state->camera);
v1 = gf_vec_scale(v1, tr_state->camera->avatar_size.x);
gf_vec_add(v1, v1, pos);
v2 = camera_get_right_dir(tr_state->camera);
v2 = gf_vec_scale(v2, tr_state->camera->avatar_size.x);
gf_vec_add(v2, v2, pos);
gf_mx_copy(mx, tr_state->model_matrix);
gf_mx_inverse(&mx);
gf_mx_apply_vec(&mx, &pos);
gf_mx_apply_vec(&mx, &last_pos);
gf_mx_apply_vec(&mx, &v1);
gf_mx_apply_vec(&mx, &v2);
gf_vec_diff(v1, v1, pos);
gf_vec_diff(v2, v2, pos);
dist = gf_vec_len(v1);
m_dist = gf_vec_len(v2);
if (dist<m_dist) m_dist = dist;
if (gf_mesh_closest_face(st->mesh, pos, m_dist, &collide_pt)) {
gf_mx_apply_vec(&tr_state->model_matrix, &collide_pt);
gf_vec_diff(v2, tr_state->camera->position, collide_pt);
dist = gf_vec_len(v2);
if (dist<tr_state->camera->collide_dist) {
tr_state->camera->collide_dist = dist;
tr_state->camera->collide_flags |= CF_COLLISION;
tr_state->camera->collide_point = collide_pt;
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_COMPOSE, GF_LOG_DEBUG)) {
gf_vec_diff(v1, pos, collide_pt);
gf_vec_norm(&v1);
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] found at %g %g %g (WC) - dist (%g) - local normal %g %g %g\n",
FIX2FLT(tr_state->camera->collide_point.x), FIX2FLT(tr_state->camera->collide_point.y), FIX2FLT(tr_state->camera->collide_point.z),
FIX2FLT(dist),
FIX2FLT(v1.x), FIX2FLT(v1.y), FIX2FLT(v1.z)));
}
#endif
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Existing collision (dist %g) closer than current collsion (dist %g)\n", FIX2FLT(tr_state->camera->collide_dist), FIX2FLT(dist) ));
}
}
if (tr_state->camera->collide_flags & CF_DO_GRAVITY) {
GF_Ray r;
Bool intersect;
r.orig = tr_state->camera->position;
r.dir = gf_vec_scale(tr_state->camera->up, -FIX_ONE);
gf_mx_apply_ray(&mx, &r);
intersect = gf_mesh_intersect_ray(st->mesh, &r, &collide_pt, &v1, NULL);
if (intersect) {
gf_mx_apply_vec(&tr_state->model_matrix, &collide_pt);
gf_vec_diff(v2, tr_state->camera->position, collide_pt);
dist = gf_vec_len(v2);
if (dist<tr_state->camera->ground_dist) {
tr_state->camera->ground_dist = dist;
tr_state->camera->collide_flags |= CF_GRAVITY;
tr_state->camera->ground_point = collide_pt;
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Ground found at %g %g %g (WC) - dist %g - local normal %g %g %g\n",
FIX2FLT(tr_state->camera->ground_point.x), FIX2FLT(tr_state->camera->ground_point.y), FIX2FLT(tr_state->camera->ground_point.z),
FIX2FLT(dist),
FIX2FLT(v1.x), FIX2FLT(v1.y), FIX2FLT(v1.z)));
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Collision] Existing ground (dist %g) closer than current (dist %g)\n", FIX2FLT(tr_state->camera->ground_dist), FIX2FLT(dist)));
}
}
}
}
#endif
static GF_TextureHandler *visual_3d_setup_texture_2d(GF_TraverseState *tr_state, DrawAspect2D *asp, GF_Mesh *mesh)
{
if (!asp->fill_texture) return NULL;
if (asp->fill_color && (GF_COL_A(asp->fill_color) != 0xFF)) {
visual_3d_set_material_2d_argb(tr_state->visual, asp->fill_color);
gf_sc_texture_set_blend_mode(asp->fill_texture, TX_MODULATE);
} else {
visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, 0);
gf_sc_texture_set_blend_mode(asp->fill_texture, TX_REPLACE);
}
if (asp->fill_texture->flags & GF_SR_TEXTURE_SVG) {
GF_Rect rc;
gf_rect_from_bbox(&rc, &mesh->bounds);
tr_state->mesh_num_textures = gf_sc_texture_enable_ex(asp->fill_texture, NULL, &rc);
} else {
#ifndef GPAC_DISABLE_VRML
tr_state->mesh_num_textures = gf_sc_texture_enable(asp->fill_texture, tr_state->appear ? ((M_Appearance *)tr_state->appear)->textureTransform : NULL);
#endif
}
if (tr_state->mesh_num_textures) return asp->fill_texture;
return NULL;
}
void visual_3d_set_2d_strike(GF_TraverseState *tr_state, DrawAspect2D *asp)
{
if (asp->line_texture) {
GF_Node *txtrans = NULL;
#ifndef GPAC_DISABLE_VRML
if (tr_state->appear
&& (gf_node_get_tag( ((M_Appearance *)tr_state->appear)->material) == TAG_MPEG4_Material2D)
&& (gf_node_get_tag(((M_Material2D *) ((M_Appearance *)tr_state->appear)->material)->lineProps) == TAG_MPEG4_XLineProperties)
) {
txtrans = ((M_XLineProperties *) ((M_Material2D *) ((M_Appearance *)tr_state->appear)->material)->lineProps)->textureTransform;
}
#endif
gf_sc_texture_set_blend_mode(asp->line_texture, TX_REPLACE);
#if 0
if (asp->line_alpha != FIX_ONE) {
visual_3d_set_material_2d(tr_state->visual, asp->line_color, asp->line_alpha);
gf_sc_texture_set_blend_mode(asp->txh, TX_MODULATE);
} else {
visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, 0);
gf_sc_texture_set_blend_mode(asp->txh, TX_REPLACE);
}
#endif
tr_state->mesh_num_textures = gf_sc_texture_enable(asp->line_texture, txtrans);
if (tr_state->mesh_num_textures) return;
}
if (asp->line_color)
visual_3d_set_material_2d_argb(tr_state->visual, asp->line_color);
}
void visual_3d_draw_2d_with_aspect(Drawable *st, GF_TraverseState *tr_state, DrawAspect2D *asp)
{
StrikeInfo2D *si;
GF_TextureHandler *fill_txh;
fill_txh = visual_3d_setup_texture_2d(tr_state, asp, st->mesh);
if (fill_txh || (GF_COL_A(asp->fill_color)) ) {
if (!st->mesh) return;
if (asp->fill_color)
visual_3d_set_material_2d_argb(tr_state->visual, asp->fill_color);
else if (GF_COL_A(asp->line_color) && !(asp->line_color & 0x00FFFFFF)) {
u32 col = asp->line_color | 0x00FFFFFF;
visual_3d_set_material_2d_argb(tr_state->visual, col);
}
visual_3d_mesh_paint(tr_state, st->mesh);
if (tr_state->mesh_num_textures) {
gf_sc_texture_disable(fill_txh);
tr_state->mesh_num_textures = 0;
}
}
if ((tr_state->visual->type_3d == 4) && !asp->line_texture) return;
if (!asp->pen_props.width || !GF_COL_A(asp->line_color)) return;
si = drawable_get_strikeinfo(tr_state->visual->compositor, st, asp, tr_state->appear, NULL, 0, tr_state);
if (!si) return;
if (!si->mesh_outline) {
si->is_vectorial = asp->line_texture ? GF_TRUE : !tr_state->visual->compositor->raster_outlines;
si->mesh_outline = new_mesh();
#ifdef GPAC_HAS_GLU
if (si->is_vectorial) {
gf_mesh_tesselate_path(si->mesh_outline, si->outline, asp->line_texture ? 2 : 1);
} else
#endif
mesh_get_outline(si->mesh_outline, st->path);
}
visual_3d_set_2d_strike(tr_state, asp);
if (asp->line_texture) tr_state->mesh_num_textures = 1;
if (!si->is_vectorial) {
visual_3d_mesh_strike(tr_state, si->mesh_outline, asp->pen_props.width, asp->line_scale, asp->pen_props.dash);
} else {
visual_3d_mesh_paint(tr_state, si->mesh_outline);
}
if (asp->line_texture) {
gf_sc_texture_disable(asp->line_texture);
tr_state->mesh_num_textures = 0;
}
}
#ifndef GPAC_DISABLE_VRML
void visual_3d_draw_2d(Drawable *st, GF_TraverseState *tr_state)
{
DrawAspect2D asp;
memset(&asp, 0, sizeof(DrawAspect2D));
drawable_get_aspect_2d_mpeg4(st->node, &asp, tr_state);
visual_3d_draw_2d_with_aspect(st, tr_state, &asp);
}
#endif
void visual_3d_draw_from_context(DrawableContext *ctx, GF_TraverseState *tr_state)
{
GF_Rect rc;
gf_path_get_bounds(ctx->drawable->path, &rc);
visual_3d_draw_2d_with_aspect(ctx->drawable, tr_state, &ctx->aspect);
drawable_check_focus_highlight(ctx->drawable->node, tr_state, &rc);
}
static GFINLINE Bool visual_3d_setup_material(GF_TraverseState *tr_state, u32 mesh_type, Fixed *diffuse_alpha)
{
#ifndef GPAC_DISABLE_VRML
GF_Node *__mat;
#endif
SFColor def;
def.red = def.green = def.blue = FIX_ONE;
if (diffuse_alpha) *diffuse_alpha = FIX_ONE;
if (!tr_state->appear) {
visual_3d_set_material_2d(tr_state->visual, def, FIX_ONE);
return 1;
}
#ifndef GPAC_DISABLE_VRML
#ifndef GPAC_DISABLE_X3D
if (gf_node_get_tag(tr_state->appear)==TAG_X3D_Appearance) {
X_FillProperties *fp = (X_FillProperties *) ((X_Appearance*)tr_state->appear)->fillProperties;
if (fp && !fp->filled) return 0;
}
#endif
__mat = ((M_Appearance *)tr_state->appear)->material;
if (!__mat) {
visual_3d_set_material_2d(tr_state->visual, def, FIX_ONE);
return 1;
}
switch (gf_node_get_tag((GF_Node *)__mat)) {
case TAG_MPEG4_Material:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_Material:
#endif
{
SFColor diff, spec, emi;
Fixed diff_a, spec_a, emi_a;
Fixed vec[4];
Bool has_alpha;
u32 flag = V3D_STATE_LIGHT ;
M_Material *mat = (M_Material *)__mat;
diff = mat->diffuseColor;
diff_a = FIX_ONE - mat->transparency;
if (mesh_type || !tr_state->camera->is_3D) {
if (tr_state->camera->is_3D) diff = mat->emissiveColor;
if (!tr_state->color_mat.identity) gf_cmx_apply_fixed(&tr_state->color_mat, &diff_a, &diff.red, &diff.green, &diff.blue);
visual_3d_set_material_2d(tr_state->visual, diff, diff_a);
return 1;
}
spec = mat->specularColor;
emi = mat->emissiveColor;
spec_a = emi_a = FIX_ONE - mat->transparency;
if (!tr_state->color_mat.identity) {
gf_cmx_apply_fixed(&tr_state->color_mat, &diff_a, &diff.red, &diff.green, &diff.blue);
gf_cmx_apply_fixed(&tr_state->color_mat, &spec_a, &spec.red, &spec.green, &spec.blue);
gf_cmx_apply_fixed(&tr_state->color_mat, &emi_a, &emi.red, &emi.green, &emi.blue);
if ((diff_a+FIX_EPSILON<FIX_ONE) || (spec_a+FIX_EPSILON<FIX_ONE) || (emi_a+FIX_EPSILON<FIX_ONE )) {
has_alpha = 1;
} else {
has_alpha = 0;
}
} else {
has_alpha = (mat->transparency>FIX_EPSILON) ? 1 : 0;
if (mat->transparency+FIX_EPSILON>=FIX_ONE) return 0;
}
visual_3d_enable_antialias(tr_state->visual, !has_alpha);
if (has_alpha) {
flag |= V3D_STATE_BLEND;
tr_state->mesh_is_transparent = 1;
}
visual_3d_set_state(tr_state->visual, flag, 1);
vec[0] = gf_mulfix(diff.red, mat->ambientIntensity);
vec[1] = gf_mulfix(diff.green, mat->ambientIntensity);
vec[2] = gf_mulfix(diff.blue, mat->ambientIntensity);
vec[3] = diff_a;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_AMBIENT, vec);
vec[0] = diff.red;
vec[1] = diff.green;
vec[2] = diff.blue;
vec[3] = diff_a;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_DIFFUSE, vec);
vec[0] = spec.red;
vec[1] = spec.green;
vec[2] = spec.blue;
vec[3] = spec_a;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_SPECULAR, vec);
vec[0] = emi.red;
vec[1] = emi.green;
vec[2] = emi.blue;
vec[3] = emi_a;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_EMISSIVE, vec);
visual_3d_set_shininess(tr_state->visual, mat->shininess);
if (diffuse_alpha) *diffuse_alpha = diff_a;
}
break;
case TAG_MPEG4_Material2D:
{
SFColor emi;
Fixed emi_a;
M_Material2D *mat = (M_Material2D *)__mat;
emi = mat->emissiveColor;
emi_a = FIX_ONE - mat->transparency;
if (!tr_state->color_mat.identity) gf_cmx_apply_fixed(&tr_state->color_mat, &emi_a, &emi.red, &emi.green, &emi.blue);
if (emi_a<FIX_EPSILON) return 0;
else if (emi_a+FIX_EPSILON<FIX_ONE) visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, 1);
if (!mat->filled) {
if (mat->transparency) {
emi.red = emi.green = emi.blue = FIX_ONE;
} else {
GF_TextureHandler *txh = gf_sc_texture_get_handler(((M_Appearance *)tr_state->appear)->texture);
if (txh) {
gf_sc_texture_set_blend_mode(txh, TX_REPLACE);
visual_3d_set_state(tr_state->visual, V3D_STATE_COLOR, 0);
visual_3d_set_state(tr_state->visual, V3D_STATE_LIGHT, 1);
return 1;
}
}
}
visual_3d_set_state(tr_state->visual, V3D_STATE_LIGHT | V3D_STATE_COLOR, 0);
visual_3d_set_material_2d(tr_state->visual, emi, emi_a);
}
break;
default:
break;
}
return 1;
#else
return 0;
#endif
}
Bool visual_3d_setup_texture(GF_TraverseState *tr_state, Fixed diffuse_alpha)
{
#ifndef GPAC_DISABLE_VRML
GF_TextureHandler *txh;
tr_state->mesh_num_textures = 0;
if (!tr_state->appear) return 0;
gf_node_dirty_reset(tr_state->appear, 0);
txh = gf_sc_texture_get_handler(((M_Appearance *)tr_state->appear)->texture);
if (txh) {
gf_sc_texture_set_blend_mode(txh, gf_sc_texture_is_transparent(txh) ? TX_MODULATE : TX_REPLACE);
tr_state->mesh_num_textures = gf_sc_texture_enable(txh, ((M_Appearance *)tr_state->appear)->textureTransform);
if (tr_state->mesh_num_textures) {
Fixed v[4];
switch (txh->pixelformat) {
case GF_PIXEL_RGB_24:
if (tr_state->visual->has_material_2d) {
SFColor c;
c.red = c.green = c.blue = FIX_ONE;
visual_3d_set_material_2d(tr_state->visual, c, diffuse_alpha);
} else {
v[0] = v[1] = v[2] = FIX_ONE;
v[3] = diffuse_alpha;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_DIFFUSE, v);
}
break;
case GF_PIXEL_RGBA:
if (!tr_state->visual->has_material_2d) {
v[0] = v[1] = v[2] = v[3] = FIX_ONE;
visual_3d_set_material(tr_state->visual, V3D_MATERIAL_DIFFUSE, v);
}
tr_state->mesh_is_transparent = 1;
break;
}
}
return tr_state->mesh_num_textures;
}
#endif
return 0;
}
void visual_3d_disable_texture(GF_TraverseState *tr_state)
{
if (tr_state->mesh_num_textures) {
#ifndef GPAC_DISABLE_VRML
gf_sc_texture_disable(gf_sc_texture_get_handler( ((M_Appearance *)tr_state->appear)->texture) );
#endif
tr_state->mesh_num_textures = 0;
}
}
Bool visual_3d_setup_appearance(GF_TraverseState *tr_state)
{
Fixed diff_a;
if (!visual_3d_setup_material(tr_state, 0, &diff_a)) return 0;
visual_3d_setup_texture(tr_state, diff_a);
return 1;
}
void visual_3d_draw(GF_TraverseState *tr_state, GF_Mesh *mesh)
{
if (mesh->mesh_type) {
if (visual_3d_setup_material(tr_state, mesh->mesh_type, NULL)) {
visual_3d_mesh_paint(tr_state, mesh);
}
} else if (visual_3d_setup_appearance(tr_state)) {
visual_3d_mesh_paint(tr_state, mesh);
visual_3d_disable_texture(tr_state);
#if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_DISABLE_X3D) && !defined(GPAC_USE_GLES2)
if (tr_state->appear && gf_node_get_tag(tr_state->appear)==TAG_X3D_Appearance) {
X_Appearance *ap = (X_Appearance *)tr_state->appear;
X_FillProperties *fp = ap->fillProperties ? (X_FillProperties *) ap->fillProperties : NULL;
if (fp && fp->hatched) visual_3d_mesh_hatch(tr_state, mesh, fp->hatchStyle, fp->hatchColor);
}
#endif
}
}
void visual_3d_projection_matrix_modified(GF_VisualManager *visual)
{
visual->needs_projection_matrix_reload = 1;
}
void visual_3d_enable_headlight(GF_VisualManager *visual, Bool bOn, GF_Camera *cam)
{
SFVec3f dir;
SFColor col;
if (!bOn) return;
if (visual->has_inactive_lights || visual->num_lights) return;
col.blue = col.red = col.green = FIX_ONE;
dir.x = dir.y = 0;
dir.z = -FIX_ONE;
visual_3d_add_directional_light(visual, 0, col, FIX_ONE, dir, NULL);
}
void visual_3d_set_material_2d(GF_VisualManager *visual, SFColor col, Fixed alpha)
{
visual->has_material_2d = alpha ? 1 : 0;
visual->has_material=0;
if (visual->has_material_2d) {
visual->mat_2d.red = col.red;
visual->mat_2d.green = col.green;
visual->mat_2d.blue = col.blue;
visual->mat_2d.alpha = alpha;
}
}
void visual_3d_set_material_2d_argb(GF_VisualManager *visual, u32 col)
{
u32 a = GF_COL_A(col);
visual->has_material_2d = a ? 1 : 0;
visual->has_material=0;
if (visual->has_material_2d) {
visual->mat_2d.red = INT2FIX( GF_COL_R(col) ) / 255;
visual->mat_2d.green = INT2FIX( GF_COL_G(col) ) / 255;
visual->mat_2d.blue = INT2FIX( GF_COL_B(col) ) / 255;
visual->mat_2d.alpha = INT2FIX( a ) / 255;;
}
}
void visual_3d_set_clipper_2d(GF_VisualManager *visual, GF_Rect clip, GF_Matrix *mx_at_clipper)
{
if (mx_at_clipper)
gf_mx_apply_rect(mx_at_clipper, &clip);
visual->clipper_2d = gf_rect_pixelize(&clip);
visual->has_clipper_2d = GF_TRUE;
}
void visual_3d_reset_clipper_2d(GF_VisualManager *visual)
{
visual->has_clipper_2d = GF_FALSE;
}
void visual_3d_set_clip_plane(GF_VisualManager *visual, GF_Plane p, GF_Matrix *mx_at_clipper, Bool is_2d_clip)
{
if (visual->num_clips==GF_MAX_GL_CLIPS) return;
gf_vec_norm(&p.normal);
visual->clippers[visual->num_clips].p = p;
visual->clippers[visual->num_clips].is_2d_clip = is_2d_clip;
visual->clippers[visual->num_clips].mx_clipper = mx_at_clipper;
visual->num_clips++;
}
void visual_3d_reset_clip_plane(GF_VisualManager *visual)
{
if (!visual->num_clips) return;
visual->num_clips -= 1;
}
void visual_3d_set_material(GF_VisualManager *visual, u32 material_type, Fixed *rgba)
{
visual->materials[material_type].red = rgba[0];
visual->materials[material_type].green = rgba[1];
visual->materials[material_type].blue = rgba[2];
visual->materials[material_type].alpha = rgba[3];
visual->has_material = 1;
visual->has_material_2d=0;
}
void visual_3d_set_shininess(GF_VisualManager *visual, Fixed shininess)
{
visual->shininess = shininess;
}
void visual_3d_set_state(GF_VisualManager *visual, u32 flag_mask, Bool setOn)
{
if (flag_mask & V3D_STATE_LIGHT) visual->state_light_on = setOn;
if (flag_mask & V3D_STATE_BLEND) visual->state_blend_on = setOn;
if (flag_mask & V3D_STATE_COLOR) visual->state_color_on = setOn;
}
void visual_3d_set_texture_matrix(GF_VisualManager *visual, GF_Matrix *mx)
{
visual->has_tx_matrix = mx ? 1 : 0;
if (mx) gf_mx_copy(visual->tx_matrix, *mx);
}
void visual_3d_has_inactive_light(GF_VisualManager *visual)
{
visual->has_inactive_lights = GF_TRUE;
}
Bool visual_3d_add_point_light(GF_VisualManager *visual, Fixed ambientIntensity, SFVec3f attenuation, SFColor color, Fixed intensity, SFVec3f location, GF_Matrix *light_mx)
{
if (visual->num_lights==visual->max_lights) return 0;
visual->lights[visual->num_lights].type = 2;
visual->lights[visual->num_lights].ambientIntensity = ambientIntensity;
visual->lights[visual->num_lights].attenuation = attenuation;
visual->lights[visual->num_lights].color = color;
visual->lights[visual->num_lights].intensity = intensity;
visual->lights[visual->num_lights].position = location;
memcpy(&visual->lights[visual->num_lights].light_mx, light_mx, sizeof(GF_Matrix) );
visual->num_lights++;
return 1;
}
Bool visual_3d_add_spot_light(GF_VisualManager *visual, Fixed ambientIntensity, SFVec3f attenuation, Fixed beamWidth,
SFColor color, Fixed cutOffAngle, SFVec3f direction, Fixed intensity, SFVec3f location, GF_Matrix *light_mx)
{
if (visual->num_lights==visual->max_lights) return 0;
visual->lights[visual->num_lights].type = 1;
visual->lights[visual->num_lights].ambientIntensity = ambientIntensity;
visual->lights[visual->num_lights].attenuation = attenuation;
visual->lights[visual->num_lights].beamWidth = beamWidth;
visual->lights[visual->num_lights].cutOffAngle = cutOffAngle;
visual->lights[visual->num_lights].color = color;
visual->lights[visual->num_lights].direction = direction;
visual->lights[visual->num_lights].intensity = intensity;
visual->lights[visual->num_lights].position = location;
memcpy(&visual->lights[visual->num_lights].light_mx, light_mx, sizeof(GF_Matrix) );
visual->num_lights++;
return 1;
}
Bool visual_3d_add_directional_light(GF_VisualManager *visual, Fixed ambientIntensity, SFColor color, Fixed intensity, SFVec3f direction, GF_Matrix *light_mx)
{
if (visual->num_lights==visual->max_lights) return 0;
visual->lights[visual->num_lights].type = 0;
visual->lights[visual->num_lights].ambientIntensity = ambientIntensity;
visual->lights[visual->num_lights].color = color;
visual->lights[visual->num_lights].intensity = intensity;
visual->lights[visual->num_lights].direction = direction;
if (light_mx) {
memcpy(&visual->lights[visual->num_lights].light_mx, light_mx, sizeof(GF_Matrix) );
} else {
gf_mx_init(visual->lights[visual->num_lights].light_mx);
visual->lights[visual->num_lights].type = 3;
visual->lights[visual->num_lights].direction.x = 0;
visual->lights[visual->num_lights].direction.y = 0;
visual->lights[visual->num_lights].direction.z = -FIX_ONE;
}
visual->num_lights++;
return 1;
}
void visual_3d_remove_last_light(GF_VisualManager *visual)
{
if (visual->num_lights) {
visual->num_lights--;
}
}
void visual_3d_clear_all_lights(GF_VisualManager *visual)
{
visual->num_lights = 0;
visual->has_inactive_lights = GF_FALSE;
}
void visual_3d_set_fog(GF_VisualManager *visual, const char *type, SFColor color, Fixed density, Fixed visibility)
{
visual->has_fog = GF_TRUE;
if (!type || !stricmp(type, "LINEAR")) visual->fog_type = 0;
else if (!stricmp(type, "EXPONENTIAL")) visual->fog_type = 1;
else if (!stricmp(type, "EXPONENTIAL2")) visual->fog_type = 2;
visual->fog_color = color;
visual->fog_density = density;
visual->fog_visibility = visibility;
}
#endif