X3D Model Documentation: MaterialChoicePrototype.x3d

  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='titlecontent='MaterialChoicePrototype.x3d'/>
  6            <meta name='descriptioncontent='Prototype definition for toggle-able Material node that can choose among an array of material nodes, and is switchable at run time. This prototype also demonstrates why it is important that only the first node in a ProtoBody can render: so that it can serve as a special node type (such as Material).'/>
  7            <meta name='creatorcontent='Don Brutzman and MV4205 class'/>
  8            <meta name='createdcontent='29 April 2004'/>
  9            <meta name='modifiedcontent='28 November 2019'/>
 10            <meta name='referencecontent='MaterialChoiceExample.x3d'/>
 11            <meta name='identifiercontent='https://savage.nps.edu/Savage/Tools/Animation/MaterialChoicePrototype.x3d'/>
 12            <meta name='generatorcontent='X3D-Edit 3.2, https://savage.nps.edu/X3D-Edit'/>
 13            <meta name='licensecontent='../../license.html'/>
 14       </head>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top Index for DEF nodes: MaterialAnimationScript, ViewedMaterialNode

Index for ProtoDeclare definition: MaterialChoice
-->
 15       <Scene>
 16            <WorldInfo title='MaterialChoicePrototype.x3d'/>
 17            <ProtoDeclare name='MaterialChoiceappinfo='MaterialChoice selects one of several different Material values'>
 18                 <ProtoInterface>
 19                      <field name='set_indextype='SFInt32accessType='inputOnly'/>
 20                      <field name='indextype='SFInt32value='0accessType='initializeOnly'
                     appinfo='which Material node is chosen, with array index starting at 0'/>
 21                      <field name='index_changedtype='SFInt32accessType='outputOnly'/>
 22                      <field name='set_fractiontype='SFFloataccessType='inputOnly'/>
 23                      <field name='fractiontype='SFFloatvalue='0accessType='initializeOnly'
                     appinfo='fraction to interpolate between current and next Material node (if any) across all field values.'/>
 24                      <field name='nexttype='SFBoolaccessType='inputOnly'
                     appinfo='Trigger next Material node'/>
 25                      <field name='previoustype='SFBoolaccessType='inputOnly'
                     appinfo='Trigger previous Material node'/>
 26                      <field name='materialstype='MFNodeaccessType='initializeOnly'
                     appinfo='array of available Material nodes defaults to zeroth Material'>
 27                           <!-- no default initialization node since it crashes Xj3D -->
 28                      </field>
 29                      <field name='appendMaterialtype='SFNodeaccessType='inputOnly'
                     appinfo='append another Material node to materials array'/>
 30                      <field name='deleteMaterialtype='SFInt32accessType='inputOnly'
                     appinfo='delete Material node indicated by input index value'/>
 31                      <field name='deleteAllMaterialstype='SFBoolaccessType='inputOnly'
                     appinfo='deletes all Material nodes resets scene to default Material values defined in X3D Specification'/>
 32                 </ProtoInterface>
 33                 <ProtoBody>
 34                      <!-- first node is node type for this prototype, other nodes are active but do not render -->
 35 
                    <!-- Material ViewedMaterialNode is a DEF node that has 1 USE node: USE_1 -->
                    <Material DEF='ViewedMaterialNode'/>
 36                      <Script DEF='MaterialAnimationScriptdirectOutput='true'>
 37                           <field name='traceEnabledtype='SFBoolvalue='falseaccessType='initializeOnly'/>
 38                           <field name='set_indextype='SFInt32accessType='inputOnly'/>
 39                           <field name='indextype='SFInt32accessType='initializeOnly'/>
 40                           <field name='index_changedtype='SFInt32accessType='outputOnly'/>
 41                           <field name='set_fractiontype='SFFloataccessType='inputOnly'/>
 42                           <field name='fractiontype='SFFloataccessType='initializeOnly'/>
 43                           <field name='nexttype='SFBoolaccessType='inputOnly'/>
 44                           <field name='previoustype='SFBoolaccessType='inputOnly'/>
 45                           <field name='viewedMaterialtype='SFNodeaccessType='initializeOnly'>
 46                                <Material USE='ViewedMaterialNode'/>
 47                           </field>
 48                           <field name='defaultMaterialtype='SFNodeaccessType='initializeOnly'>
 49                                <Material/>
 50                           </field>
 51                           <field name='materialstype='MFNodeaccessType='initializeOnly'/>
 52                           <field name='appendMaterialtype='SFNodeaccessType='inputOnly'
                          appinfo='append another Material node to materials array'/>
 53                           <field name='deleteMaterialtype='SFInt32accessType='inputOnly'
                          appinfo='delete Material node indicated by input index value'/>
 54                           <field name='deleteAllMaterialstype='SFBoolaccessType='inputOnly'
                          appinfo='deletes all Material nodes resets scene to default Material values defined in X3D Specification'/>
 55                           <field name='priorBadIndextype='SFInt32value='-1accessType='initializeOnly'/>
 56                           <IS>
 57                                <connect nodeField='set_indexprotoField='set_index'/>
 58                                <connect nodeField='indexprotoField='index'/>
 59                                <connect nodeField='index_changedprotoField='index_changed'/>
 60                                <connect nodeField='set_fractionprotoField='set_fraction'/>
 61                                <connect nodeField='fractionprotoField='fraction'/>
 62                                <connect nodeField='nextprotoField='next'/>
 63                                <connect nodeField='previousprotoField='previous'/>
 64                                <connect nodeField='materialsprotoField='materials'/>
 65                                <connect nodeField='appendMaterialprotoField='appendMaterial'/>
 66                                <connect nodeField='deleteMaterialprotoField='deleteMaterial'/>
 67                                <connect nodeField='deleteAllMaterialsprotoField='deleteAllMaterials'/>
 68                           </IS>
  <![CDATA[
          
ecmascript:

function initialize ()
{
   tracePrint ('initialize() begin...');
   if (materials[index] != null)
   {
	viewedMaterial.diffuseColor     = materials[index].diffuseColor;
	viewedMaterial.emissiveColor    = materials[index].emissiveColor;
	viewedMaterial.specularColor    = materials[index].specularColor;
	viewedMaterial.shininess        = materials[index].shininess;
	viewedMaterial.ambientIntensity = materials[index].ambientIntensity;
	viewedMaterial.transparency     = materials[index].transparency;
	interpolateMaterialValues();
   }
   else alwaysPrint ('warning: no initialization Material node provided for materials[' + index + ']'
                    + ', materials.length=' + materials.length);

   tracePrint ('initialize() complete');
}

function set_index (value, timestamp)
{
   if (value == index) return;
   else if ((value >= 0) && (value < materials.length))
   {
	index = value;
	viewedMaterial.diffuseColor     = materials[index].diffuseColor;
	viewedMaterial.emissiveColor    = materials[index].emissiveColor;
	viewedMaterial.specularColor    = materials[index].specularColor;
	viewedMaterial.shininess        = materials[index].shininess;
	viewedMaterial.ambientIntensity = materials[index].ambientIntensity;
	viewedMaterial.transparency     = materials[index].transparency;
	interpolateMaterialValues();
	index_changed = value; // chain input event to output event
	tracePrint ('set_index(' + value + ') complete');
   }
   else if (value == -1)
   {
	tracePrint ('set_index(' + value + ') out of range, use default Material values');
	index = value;
	viewedMaterial.diffuseColor     = defaultMaterial.diffuseColor;
	viewedMaterial.emissiveColor    = defaultMaterial.emissiveColor;
	viewedMaterial.specularColor    = defaultMaterial.specularColor;
	viewedMaterial.shininess        = defaultMaterial.shininess;
	viewedMaterial.ambientIntensity = defaultMaterial.ambientIntensity;
	viewedMaterial.transparency     = defaultMaterial.transparency;
	index_changed = value; // chain input event to output event
   }
   else if (priorBadIndex != value)
   {
	alwaysPrint ('set_index(' + value + ') out of range (only '
		+ materials.length + ' Material nodes)');
	priorBadIndex = value;
   }
}

function set_fraction(value, timestamp)
{
	tracePrint ('set_fraction(' + value + ')');
	if (fraction != value) // only update if value is changed
	{
		fraction = value;
		interpolateMaterialValues();
	}
}

function interpolateMaterialValues()
{
	f = fraction % 1;  // nonzero remainder (modulo 1) within range [0..1]
	tracePrint ('interpolateMaterialValues(index=' + index + ', fraction=' + fraction +  ', f=' + f + ')');
	// reset Material index if fraction is above 1
	if (Math.floor(fraction) >= 1)
	{
		index = Math.floor(fraction);
		tracePrint ('index=' + index + ' (reset from fraction)');
	}
	fraction = f;  // no need to retain integral part of fraction once index is set correspondingly
	// check OK to proceed
	if (index <  0) return;				// avoid index underflow
	if (index >= materials.length - 1) return;	// avoid index overflow
	if (f == 0.0) return; 				// avoid zero interpolation
	viewedMaterial.diffuseColor.r     = materials[index].diffuseColor.r +
		f * (materials[index+1].diffuseColor.r - materials[index].diffuseColor.r);
	viewedMaterial.diffuseColor.g     = materials[index].diffuseColor.g +
		f * (materials[index+1].diffuseColor.g - materials[index].diffuseColor.g);
	viewedMaterial.diffuseColor.b     = materials[index].diffuseColor.r +
		f * (materials[index+1].diffuseColor.b - materials[index].diffuseColor.b);
	tracePrint ('viewedMaterial.diffuseColor=' + viewedMaterial.diffuseColor);

	viewedMaterial.emissiveColor.r    = materials[index].emissiveColor.r +
		f * (materials[index+1].emissiveColor.r - materials[index].emissiveColor.r);
	viewedMaterial.emissiveColor.g    = materials[index].emissiveColor.r +
		f * (materials[index+1].emissiveColor.g - materials[index].emissiveColor.g);
	viewedMaterial.emissiveColor.b    = materials[index].emissiveColor.b +
		f * (materials[index+1].emissiveColor.b - materials[index].emissiveColor.b);

	viewedMaterial.specularColor.r    = materials[index].specularColor.r +
		f * (materials[index+1].specularColor.r - materials[index].specularColor.r);
	viewedMaterial.specularColor.g    = materials[index].specularColor.g +
		f * (materials[index+1].specularColor.g - materials[index].specularColor.g);
	viewedMaterial.specularColor.b    = materials[index].specularColor.b +
		f * (materials[index+1].specularColor.b - materials[index].specularColor.b);

	viewedMaterial.shininess        = materials[index].shininess +
		f * (materials[index+1].shininess - materials[index].shininess);
	viewedMaterial.ambientIntensity = materials[index].ambientIntensity +
		f * (materials[index+1].ambientIntensity - materials[index].ambientIntensity);
	viewedMaterial.transparency     = materials[index].transparency +
		f * (materials[index+1].transparency - materials[index].transparency);
}

function next(trigger)
{
	tracePrint ('next(' + trigger + ')');
	if ((trigger == true) && (materials.length > 0))
	{
		value = index + 1;
		if (value >= materials.length) value = 0;
		set_index (value); // update Material, test, etc.
	}
}

function previous(trigger)
{
	tracePrint ('previous(' + trigger + ')');
	if ((trigger == true) && (materials.length > 0))
	{
		value = index - 1;
		if (value < 0) value = materials.length - 1;
		set_index (value); // update Material, test, etc.
	}
}

function appendMaterial(newMaterial)
{
	tracePrint ('appendMaterial(' + newMaterial + ')');
	newMaterialCopy = new SFNode ('Material {}');
	tracePrint ('newMaterial.diffuseColor=' + newMaterial.diffuseColor);
	newMaterialCopy.diffuseColor     = newMaterial.diffuseColor;
	newMaterialCopy.emissiveColor    = newMaterial.emissiveColor;
	newMaterialCopy.specularColor    = newMaterial.specularColor;
	newMaterialCopy.shininess        = newMaterial.shininess;
	newMaterialCopy.ambientIntensity = newMaterial.ambientIntensity;
	newMaterialCopy.transparency     = newMaterial.transparency;
	materials[materials.length]      = newMaterialCopy;
	set_index (materials.length-1); // update Material, test, etc.
}

function deleteAllMaterials(trigger)
{
	if ((trigger == true) && (materials.length > 0))
	{
		materials.length = 0; // deletes all objects in materials MFNode array
		index = 0; // must be different to trigger node reset by set_index()
		set_index (-1);
		tracePrint ('deleteAllMaterials() materials.length=' + materials.length);
	}
}

function deleteMaterial(materialIndex)
{
	if ((materialIndex >= materials.length) || materialIndex < 0)
		alwaysPrint ('deleteMaterial(materialIndex=' + materialIndex + ') out of range, materials.length=' +  materials.length);
	else
	{
		for (i = materialIndex; i <= materials.length - 2; i++)
		{
			materials[i] = materials[i+1];
		}
		materials.length = materials.length - 1;
		if ((index == 0) && (materialIndex == 0) && (materials.length > 0))
		{
			index = -1; // allow reset back to 0
			set_index (0);
		}
		else if (index >= materialIndex) set_index (index-1); // decrement to remain same
		tracePrint ('deleteMaterial(materialIndex=' + materialIndex + ') complete,  materials.length=' + materials.length);
	}
}

function tracePrint(outputString)
{
	if (traceEnabled) Browser.println ('[MaterialChoice] ' + outputString);
}
function alwaysPrint(outputString)
{
	Browser.println ('[MaterialChoice] ' + outputString);
}

        
]]>
 70                      </Script>
 71                 </ProtoBody>
 72            </ProtoDeclare>
 73            <!-- ==================== -->
 74            <Anchor description='MaterialChoiceExample'   url=' "MaterialChoiceExample.x3d" "https://savage.nps.edu/Savage/Tools/Animation/MaterialChoiceExample.x3d" "MaterialChoiceExample.wrl" "https://savage.nps.edu/Savage/Tools/Animation/MaterialChoiceExample.wrl" '>
 75                 <Shape>
 76                      <Text string='"MaterialChoicePrototype" "defines a prototype" "" "Click text to see example scene" "MaterialChoiceExample"'>
 77                           <FontStyle justify='"MIDDLE" "MIDDLE"size='0.9'/>
 78                      </Text>
 79                      <Appearance>
 80                           <Material diffuseColor='1 1 0.2'/>
 81                      </Appearance>
 82                 </Shape>
 83            </Anchor>
 84       </Scene>
 85  </X3D>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top Index for DEF nodes: MaterialAnimationScript, ViewedMaterialNode

Index for ProtoDeclare definition: MaterialChoice
-->
X3D Tooltips element index: Anchor, Appearance, connect, field, FontStyle, head, IS, Material, meta, ProtoBody, ProtoDeclare, ProtoInterface, Scene, Script, Shape, Text, WorldInfo, X3D, plus documentation for accessType definitions, type definitions, XML data types, and field types

-->
<!-- Online at
https://savage.nps.edu/Savage/Tools/Animation/MaterialChoicePrototypeIndex.html -->
<!-- Version control at
https://gitlab.nps.edu/Savage/Savage/Tools/Animation/MaterialChoicePrototype.x3d -->

<!-- Color-coding legend: X3D terminology <X3dNode  DEF='idNamefield='value'/> matches XML terminology <XmlElement  DEF='idNameattribute='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> -->

to top <!-- For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints. -->