root/src/compositor/mpeg4_timesensor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. timesensor_destroy
  2. timesensor_deactivate
  3. timesensor_update_time
  4. compositor_init_timesensor
  5. compositor_timesensor_modified

/*
 *                      GPAC - Multimedia Framework C SDK
 *
 *                      Authors: Jean Le Feuvre
 *                      Copyright (c) Telecom ParisTech 2000-2012
 *                                      All rights reserved
 *
 *  This file is part of GPAC / Scene Compositor sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "nodes_stacks.h"

#include <gpac/nodes_mpeg4.h>
#include <gpac/nodes_x3d.h>


#ifndef GPAC_DISABLE_VRML

typedef struct
{
        GF_TimeNode time_handle;
        Bool store_info;
        Double start_time, cycle_interval;
        u32 num_cycles;
        GF_Compositor *compositor;
#ifndef GPAC_DISABLE_X3D
        Bool is_x3d;
#endif
} TimeSensorStack;

static void timesensor_destroy(GF_Node *ts, void *rs, Bool is_destroy)
{
        if (is_destroy) {
                TimeSensorStack *st = (TimeSensorStack *)gf_node_get_private(ts);
                if (st->time_handle.is_registered) {
                        gf_sc_unregister_time_node(st->compositor, &st->time_handle);
                }
                gf_free(st);
        }
}


static
void timesensor_deactivate(TimeSensorStack *stack, M_TimeSensor *ts)
{
        ts->isActive = 0;
        gf_node_event_out((GF_Node *) ts, 7);//"isActive"
        assert(stack->time_handle.is_registered);
        stack->time_handle.needs_unregister = 1;
        stack->num_cycles = 0;
}

static
void timesensor_update_time(GF_TimeNode *st)
{
        Double currentTime, cycleTime;
        Fixed newFraction;
        u32 inc;
        M_TimeSensor *TS = (M_TimeSensor *)st->udta;
        TimeSensorStack *stack = (TimeSensorStack *)gf_node_get_private(st->udta);

        if (! TS->enabled) {
                if (TS->isActive) {
                        TS->cycleTime = gf_node_get_scene_time(st->udta);
                        gf_node_event_out(st->udta, 5);//"cycleTime"
                        timesensor_deactivate(stack, TS);
                }
                return;
        }

        if (stack->store_info) {
                stack->store_info = 0;
                stack->start_time = TS->startTime;
                stack->cycle_interval = TS->cycleInterval;
        }

        currentTime = gf_node_get_scene_time(st->udta);
        if (!TS->isActive) {
                if (currentTime < stack->start_time) return;
                /*special case: if we're greater than both start and stop time don't activate*/
                if (!TS->isActive && (TS->stopTime > stack->start_time) && (currentTime >= TS->stopTime)) {
                        stack->time_handle.needs_unregister = 1;
                        return;
                }
#ifndef GPAC_DISABLE_X3D
                if (stack->is_x3d && !TS->loop) {
                        if (!stack->start_time) return;
                        if (currentTime >= TS->startTime+stack->cycle_interval) return;
                }
#endif
        }

        cycleTime = currentTime - stack->start_time - stack->num_cycles * stack->cycle_interval;
        newFraction = FLT2FIX ( fmod(cycleTime, stack->cycle_interval) / stack->cycle_interval );

        if (TS->isActive) {
                TS->time = currentTime;
                gf_node_event_out(st->udta, 8);//"time"

                /*VRML:
                        "f = fmod( (now - startTime) , cycleInterval) / cycleInterval
                        if (f == 0.0 && now > startTime) fraction_changed = 1.0
                        else fraction_changed = f"
                */
                if (!newFraction && (currentTime > stack->start_time ) ) newFraction = FIX_ONE;

                /*check for deactivation - if so generate a fraction_changed AS IF NOW WAS EXACTLY STOPTIME*/
                if ((TS->stopTime > stack->start_time) && (currentTime >= TS->stopTime) ) {
                        cycleTime = TS->stopTime - stack->start_time - stack->num_cycles * stack->cycle_interval;
                        TS->fraction_changed = FLT2FIX( fmod(cycleTime, stack->cycle_interval) / stack->cycle_interval );
                        /*cf above*/
                        if (TS->fraction_changed < FIX_EPSILON) TS->fraction_changed = FIX_ONE;
                        gf_node_event_out(st->udta, 6);//"fraction_changed"
                        timesensor_deactivate(stack, TS);
                        return;
                }
                if (! TS->loop) {
                        if (cycleTime >= stack->cycle_interval) {
                                TS->fraction_changed = FIX_ONE;
                                gf_node_event_out(st->udta, 6);//"fraction_changed"
                                timesensor_deactivate(stack, TS);
                                return;
                        }
                }
                if (newFraction != TS->fraction_changed) {
                        TS->fraction_changed = newFraction;
                        gf_node_event_out(st->udta, 6);//"fraction_changed"
                }
        }

        /*we're (about to be) active: VRML:
        "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
        equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active      */

        if (!TS->isActive) {
                st->needs_unregister = 0;
                TS->isActive = 1;
                gf_node_event_out(st->udta, 7); //"isActive"
                TS->cycleTime = currentTime;
                gf_node_event_out(st->udta, 5);//"cycleTime"
                TS->fraction_changed = newFraction;
                gf_node_event_out(st->udta, 6);//"fraction_changed"
        }

        //compute cycle time
        if (TS->loop && (cycleTime >= stack->cycle_interval) ) {
                inc = 1 + (u32) ( (cycleTime - stack->cycle_interval ) / stack->cycle_interval );
                stack->num_cycles += inc;
                cycleTime -= inc*stack->cycle_interval;
                TS->cycleTime = currentTime - cycleTime;
                gf_node_event_out(st->udta, 5);//"cycleTime"
        }
}

void compositor_init_timesensor(GF_Compositor *compositor, GF_Node *node)
{
        TimeSensorStack *st;
        GF_SAFEALLOC(st, TimeSensorStack);
        if (!st) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate time  sensor 2d stack\n"));
                return;
        }
        st->time_handle.UpdateTimeNode = timesensor_update_time;
        st->time_handle.udta = node;
        st->store_info = 1;
        st->compositor = compositor;
#ifndef GPAC_DISABLE_X3D
        st->is_x3d = (gf_node_get_tag(node)==TAG_X3D_TimeSensor) ? 1 : 0;
#endif
        gf_node_set_private(node, st);
        gf_node_set_callback_function(node, timesensor_destroy);
        /*time sensor needs to be run only if def'ed, otherwise it doesn't impact scene*/
        //if (gf_node_get_id(node))
        gf_sc_register_time_node(compositor, &st->time_handle);
}


void compositor_timesensor_modified(GF_Node *t)
{
        M_TimeSensor *ts = (M_TimeSensor *)t;
        TimeSensorStack *stack = (TimeSensorStack *) gf_node_get_private(t);
        if (!stack) return;

        if (ts->isActive) timesensor_update_time(&stack->time_handle);

        if (!ts->isActive) stack->store_info = 1;

        if (ts->enabled) {
                stack->time_handle.needs_unregister = 0;
                if (!stack->time_handle.is_registered) {
                        gf_sc_register_time_node(stack->compositor, &stack->time_handle);
                }
        }
}

#endif /*GPAC_DISABLE_VRML*/

/* [<][>][^][v][top][bottom][index][help] */