| 1 |
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
|
| 3 | <X3D profile='Immersive' version='3.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-3.0.xsd'> |
| 4 | <head> |
| 5 | <meta name='title' content=' IntegerSequencerPrototype.x3d '/> |
| 6 | <meta name='description' content='This proto, modeled after a ScalarInterpolator, generates an array of integer values based on the input fraction and keys.'/> |
| 7 | <meta name=' warning ' content=' MFInt32 keyValue accessType is listed as initializeOnly/field, since inputOutput cannot be translated to exposedField in VRML97 scripting. '/> |
| 8 | <meta name='creator' content='Don Brutzman, Estuko Lippi, Jeff Weekley, Jane Wu, Matthew Braun'/> |
| 9 | <meta name='created' content='20 August 2001'/> |
| 10 | <meta name='modified' content='21 January 2020'/> |
| 11 | <meta name='reference' content='https://www.web3d.org/technicalinfo/specifications/vrml97/part1/nodesRef.html#ScalarInterpolator'/> |
| 12 | <meta name='subject' content='integer sequencer'/> |
| 13 | <meta name='identifier' content=' https://www.web3d.org/x3d/content/examples/Basic/development/IntegerSequencerPrototype.x3d '/> |
| 14 | <meta name='generator' content='X3D-Edit 3.3, https://www.web3d.org/x3d/tools/X3D-Edit'/> |
| 15 | <meta name='license' content='../license.html'/> |
| 16 | </head> |
| 17 | <Scene> |
| 18 | <WorldInfo title='IntegerSequencerPrototype.x3d'/> |
| 19 | <ProtoDeclare name='IntegerSequencer'> |
| 20 | <ProtoInterface> |
| 21 |
<field name='set_fraction' type='SFFloat' accessType='inputOnly'
appinfo='Regular interpolator-style input, range [0..1]'/> |
| 22 |
<field name='set_key' type='MFFloat' accessType='inputOnly'
appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/> |
| 23 |
<field name='key' type='MFFloat' accessType='inputOutput'
appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/> |
| 24 |
<field name='key_changed' type='MFFloat' accessType='outputOnly'
appinfo='Array sequentially increasing typically [0..1]. Must have the same number of keys as keyValues.'/> |
| 25 |
<field name='set_keyValue' type='MFInt32' accessType='inputOnly'
appinfo='Array of integer values. Must have the same number of keys as keyValues.'/> |
| 26 |
<field name='keyValue' type='MFInt32' accessType='initializeOnly'
appinfo='Array of integer values. Must have the same number of keys as keyValues.'/> |
| 27 |
<field name='keyValue_changed' type='MFInt32' accessType='outputOnly'
appinfo='Array of integer values. Must have the same number of keys as keyValues.'/> |
| 28 |
<field name='value_changed' type='SFInt32' accessType='outputOnly'
appinfo='Regular interpolator-style input'/> |
| 29 |
<field name='previous' type='SFBool' accessType='inputOnly'
appinfo='Utility method'/> |
| 30 |
<field name='next' type='SFBool' accessType='inputOnly'
appinfo='Utility method'/> |
| 31 | </ProtoInterface> |
| 32 | <ProtoBody> |
| 33 | <Group> |
| 34 | <Switch whichChoice='-1'> |
| 35 | |
| 36 | <IS> |
| 37 | <connect nodeField='key' protoField='key'/> |
| 38 | </IS> |
| 39 | </ScalarInterpolator> |
| 40 | </Switch> |
| 41 | <Script DEF='SequencerScript' directOutput='true'> |
| 42 | <!-- Regular interpolator-style input --> |
| 43 |
<field name='set_fraction' type='SFFloat' accessType='inputOnly'
appinfo='range [0..1]'/> |
| 44 |
<field name='set_key' type='MFFloat' accessType='inputOnly'
appinfo='Array sequentially increasing [0..1]. Must have the same number of keys as keyValues.'/> |
| 45 | <field name='keyHolderNode' type='SFNode' accessType='initializeOnly'> |
| 46 | <ScalarInterpolator USE='KeyHolder'/> |
| 47 | </field> |
| 48 |
<field name='key_changed' type='MFFloat' accessType='outputOnly'
appinfo='Array sequentially increasing [0..1]. Must have the same number of keys as keyValues.'/> |
| 49 |
<field name='set_keyValue' type='MFInt32' accessType='inputOnly'
appinfo='Array of integer values. Must have the same number of keys as keyValues.'/> |
| 50 | <field name='keyValue' type='MFInt32' accessType='initializeOnly'/> |
| 51 |
<field name='keyValue_changed' type='MFInt32' accessType='outputOnly'
appinfo='Array of integer values. Must have the same number of keys as keyValues.'/> |
| 52 | <!-- Regular interpolator-style output --> |
| 53 | <field name='value_changed' type='SFInt32' accessType='outputOnly'/> |
| 54 | <!-- Utility methods --> |
| 55 | <field name='previous' type='SFBool' accessType='inputOnly'/> |
| 56 | <field name='next' type='SFBool' accessType='inputOnly'/> |
| 57 |
<field name='traceEnabled' type='SFBool' value='true' accessType='initializeOnly'
appinfo='For development use only not for inclusion in specification implementations.'/> |
| 58 | <!-- Script-specific interfaces, not needed for node definition --> |
| 59 | <field name='previousFraction' type='SFFloat' value='0.0' accessType='initializeOnly'/> |
| 60 | <field name='nextIndex' type='SFInt32' value='0' accessType='initializeOnly'/> |
| 61 | <field name='isValid' type='SFBool' value='true' accessType='initializeOnly'/> |
| 62 | <field name='recheckValidity' type='SFBool' value='false' accessType='initializeOnly'/> |
| 63 | <IS> |
| 64 | <connect nodeField='set_fraction' protoField='set_fraction'/> |
| 65 | <connect nodeField='set_key' protoField='set_key'/> |
| 66 | <connect nodeField='key_changed' protoField='key_changed'/> |
| 67 | <connect nodeField='set_keyValue' protoField='set_keyValue'/> |
| 68 | <connect nodeField='keyValue' protoField='keyValue'/> |
| 69 | <connect nodeField='keyValue_changed' protoField='keyValue_changed'/> |
| 70 | <connect nodeField='value_changed' protoField='value_changed'/> |
| 71 | <connect nodeField='previous' protoField='previous'/> |
| 72 | <connect nodeField='next' protoField='next'/> |
| 73 | </IS> |
<![CDATA[
ecmascript:
var leftToRight;
function initialize()
{
key = keyHolderNode.key;
tracePrint('Initializing a new IntegerSequencer. key.length=' + key.length + '; keyValue.length=' + keyValue.length);
tracePrint('key =' + key);
tracePrint('keyValue =' + keyValue);
validityCheck();
setHalfKeyRange();
// assume we start at first key, going left to right
leftToRight = true;
previousFraction = key[0];
nextIndex = 1; //validityCheck ensures minimum of 2 keys exist
}
function set_fraction(newFraction, timeStamp)
{
if (recheckValidity) validityCheck();
if (!isValid) return; //IntegerSequencer ignored
//Bounds checking
if (newFraction < key[0])
{
tracePrint('*** warning: fraction is less than first key. fraction set to first key ***');
newFraction = key[0];
}
else if (newFraction > key[key.length-1])
{
tracePrint('*** warning: fraction is greater than last key. fraction set to last key ***');
newFraction = key[key.length -1];
}
//Check animation direction
if (newFraction < previousFraction && leftToRight == true)
{
if ((previousFraction - newFraction) > halfKeyRange) //looped around
{
nextIndex = 1;
}
else //just changed direction
{
leftToRight = false;
nextIndex = nextIndex - 1;
}
}
else if (newFraction > previousFraction && leftToRight == false)
{
if ((newFraction - previousFraction) < halfKeyRange) //looped around
{
nextIndex = key.length - 2;
}
else //just changed direction
{
leftToRight = true;
nextIndex = nextIndex + 1;
}
}
else if (newFraction == previousFraction)
{ //no change, so no processing required
return;
}
previousFraction = newFraction;
if (leftToRight) // moving left to right
{
while (newFraction > key[nextIndex]) nextIndex++;
if (newFraction == key[nextIndex])
value_changed = keyValue[nextIndex];
else value_changed = keyValue[nextIndex -1];
tracePrint('forward animation, fraction =' + newFraction);
tracePrint('value_changed eventOut is:' + value_changed);
}
else // moving right to left
{
while (newFraction < key[nextIndex]) nextIndex--;
if (newFraction == key[nextIndex])
value_changed = keyValue[nextIndex];
else value_changed = keyValue[nextIndex + 1];
tracePrint('backward animation, fraction =' + newFraction);
tracePrint('value_changed eventOut is:' + value_changed);
}
}
function set_key(newKey, timeStamp)
{
key = newKey;
keyHolderNode.key = newKey;
setHalfKeyWidth();
recheckValidity = true;
}
function set_keyValue(newKeyValue, timeStamp)
{
keyValue = newKeyValue;
recheckValidity = true;
}
function setHalfKeyRange()
{
halfKeyRange = (key[key.length - 1] - key[0])/2.0;
}
function previous (value, timeStamp)
{
if (value==true) // trigger on true events only
{
leftToRight = true;
nextIndex = nextIndex - 2; // reset to previous
if (nextIndex < 0) nextIndex = nextIndex + key.length;
value_changed = keyValue[nextIndex];
previousFraction = key[nextIndex];
nextIndex++; // setup for next time, leftToRight
if (nextIndex > key.length - 1) nextIndex = 0;
}
}
function next (value, timeStamp)
{
if (value==true) // trigger on true events only
{
leftToRight = true;
value_changed = keyValue[nextIndex];
previousFraction = key[nextIndex];
nextIndex++; // setup for next time,leftToRight
if (nextIndex > key.length - 1) nextIndex = 0;
}
}
function validityCheck()
{
//Check if lengths of key & keyValue arrays match
if (key.length != keyValue.length)
{
alwaysPrint('*** error: key and keyValue arrays must be of the same length. IntegerSequencer ignored ***');
isValid = false;
return;
}
//check to ensure minimum of 2 keys have been specified
if (key.length < 2)
{
alwaysPrint('*** error: must contain at least 2 keys. IntegerSequencer ignored ***');
isValid = false;
return;
}
//Check if key array has values in an non-decreasing order
for (i = 1; i < key.length; i++)
{
tracePrint('i=' + i);
if (key[i] < key [i-1])
{
alwaysPrint('*** error: key array values must be listed in a non-decreasing order. IntegerSequencer ignored ***');
isValid = false;
return;
}
}
isValid = true
recheckValidity = false;
key_changed = key;
keyValue_changed = keyValue;
return;
}
function tracePrint(outputString)
{
if (traceEnabled) Browser.println ('[IntegerSequencer]' + outputString);
}
function alwaysPrint(outputString)
{
Browser.println ('[IntegerSequencer]' + outputString);
}
]]>
|
|
| 75 | </Script> |
| 76 | </Group> |
| 77 | </ProtoBody> |
| 78 | </ProtoDeclare> |
| 79 | <!-- ===============Example============== --> |
| 80 | <Anchor description='IntegerSequencerExample' parameter='"target=_blank"' url=' "IntegerSequencerExample.x3d" "https://savage.nps.edu/Savage/Tools/Animation/IntegerSequencerExample.x3d" "IntegerSequencerExample.wrl" "https://savage.nps.edu/Savage/Tools/Animation/IntegerSequencerExample.wrl" '> |
| 81 | <Shape> |
| 82 | <Text string='"IntegerSequencerPrototype" "defines a prototype" "" "Click text to see example scene" "IntegerSequencerExample"'> |
| 83 | <FontStyle justify='"MIDDLE" "MIDDLE"' size='0.9'/> |
| 84 | </Text> |
| 85 | <Appearance> |
| 86 | <Material diffuseColor='1 1 0.2'/> |
| 87 | </Appearance> |
| 88 | </Shape> |
| 89 | </Anchor> |
| 90 | </Scene> |
| 91 | </X3D> |
Event Graph ROUTE Table with 0 ROUTE connections total, showing X3D event-model relationships for this scene.
Each row shows an event cascade that may occur during a single timestamp interval between frame renderings, as part of the X3D execution model.
|
SequencerScript
Script |
No direct ROUTE connection found for events to/from this node. Contains SFNode field with direct access to another node. |
| line 80
Anchor |
description='IntegerSequencerExample' User-interaction hint for this node. |
<!--
Color-coding legend: X3D terminology
<X3dNode
DEF='idName' field='value'/>
matches XML terminology
<XmlElement
DEF='idName' attribute='value'/>
(Light-blue background: event-based behavior node or statement)
(Grey background inside box: inserted documentation)
(Magenta background: X3D Extensibility)
<ProtoDeclare name='ProtoName'>
<field
name='fieldName'/> </ProtoDeclare>
-->
<!--
For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints.
-->