<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.3//EN" "https://www.web3d.org/specifications/x3d-3.3.dtd">
<X3D profile='Immersive' version='3.3' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-3.3.xsd'>
  <head>
    <meta content='MaterialModulator.x3d' name='title'/>
    <meta content='Mimic a Material node and modulate the diffuseColor field as an animation effect, provided as a prototype for reusability.' name='description'/>
    <meta content='Learning suggestion for authors: try changing the modulation script so that it goes from [0 ... 1] and then [1 ... 0] alternating, rather than abruptly shifting from 1 immediately back to 0.' name='hint'/>
    <meta content='Don Brutzman' name='creator'/>
    <meta content='10 March 2008' name='created'/>
    <meta content='15 July 2025' name='modified'/>
    <meta content='X3D prototype requiring Script inputOutput fields' name='subject'/>
    <meta content='MaterialModulator.png' name='Image'/>
    <meta content='https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter14Prototypes/MaterialModulator.x3d' name='identifier'/>
    <meta content='X3D-Edit 3.3, https://www.web3d.org/x3d/tools/X3D-Edit' name='generator'/>
    <meta content='../license.html' name='license'/>
  </head>
  <Scene>
    <WorldInfo title='MaterialModulator.x3d'/>
    <ProtoDeclare appinfo='mimic a Material node and modulate the diffuseColor field as an animation effect' documentation='https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter14Prototypes/MaterialModulatorIndex.html' name='MaterialModulator'>
      <ProtoInterface>
        <field accessType='inputOutput' appinfo='default value true' name='enabled' type='SFBool' value='true'/>
        <field accessType='inputOutput' appinfo='default value 0.8 0.8 0.8' name='diffuseColor' type='SFColor' value='0.8 0.8 0.8'/>
        <field accessType='inputOutput' appinfo='default value 0 0 0' name='emissiveColor' type='SFColor' value='0 0 0'/>
        <field accessType='inputOutput' appinfo='default value 0 0 0' name='specularColor' type='SFColor' value='0 0 0'/>
        <field accessType='inputOutput' appinfo='default value 0.0' name='transparency' type='SFFloat' value='0.0'/>
        <field accessType='inputOutput' appinfo='default value 0.2' name='shininess' type='SFFloat' value='0.2'/>
        <field accessType='inputOutput' appinfo='default value 0.2' name='ambientIntensity' type='SFFloat' value='0.2'/>
      </ProtoInterface>
      <ProtoBody>
        <Material DEF='MaterialNode'>
          <IS>
            <connect nodeField='diffuseColor' protoField='diffuseColor'/>
            <connect nodeField='emissiveColor' protoField='emissiveColor'/>
            <connect nodeField='specularColor' protoField='specularColor'/>
            <connect nodeField='transparency' protoField='transparency'/>
            <connect nodeField='shininess' protoField='shininess'/>
            <connect nodeField='ambientIntensity' protoField='ambientIntensity'/>
          </IS>
        </Material>
        <!-- Only first node (the node type) is renderable, others are along for the ride -->
        <Script DEF='MaterialModulatorScript'>
          <field accessType='inputOutput' name='enabled' type='SFBool'/>
          <field accessType='inputOutput' name='diffuseColor' type='SFColor'/>
          <field accessType='outputOnly' name='newColor' type='SFColor'/>
          <field accessType='inputOnly' name='clockTrigger' type='SFTime'/>
          <IS>
            <connect nodeField='enabled' protoField='enabled'/>
            <connect nodeField='diffuseColor' protoField='diffuseColor'/>
          </IS>
          <![CDATA[
ecmascript:
function initialize ()
{
    newColor     = diffuseColor; // start with original color
//  diffuseColor = diffuseColor; // retain original color, silence warning
}
function clockTrigger (timeValue)
{
    if (!enabled) return;
    red   = newColor.r;
    green = newColor.g;
    blue  = newColor.b;
    
    // note different modulation rates for each color component, % is modulus operator
    newColor = new SFColor ((red + 0.02) % 1, (green + 0.03) % 1, (blue + 0.04) % 1);
    if (enabled)
    {
            Browser.println ('diffuseColor=(' + red +',' + green + ',' + blue + ') newColor=' + newColor.toString());
    }
}
function set_enabled (newValue)
{
	enabled = newValue;
}
function set_diffuseColor (newValue)
{
    newColor = newValue;
}
]]>
        </Script>
        <!-- Clock tickles Script to wake up and compute a new value -->
        <ROUTE fromField='newColor' fromNode='MaterialModulatorScript' toField='diffuseColor' toNode='MaterialNode'/>
        <TimeSensor DEF='ModulationClock' cycleInterval='0.1' loop='true'>
          <IS>
            <connect nodeField='enabled' protoField='enabled'/>
          </IS>
        </TimeSensor>
        <ROUTE fromField='cycleTime' fromNode='ModulationClock' toField='clockTrigger' toNode='MaterialModulatorScript'/>
      </ProtoBody>
    </ProtoDeclare>
    <!-- Rendered geometry for the ProtoInstance now follows prototype declaration -->
    <Transform translation='0 1 0'>
      <Shape>
        <Sphere/>
        <Appearance>
          <ProtoInstance DEF='MaterialModulatorInstance' containerField='material' name='MaterialModulator'>
            <fieldValue name='enabled' value='true'/>
            <fieldValue name='diffuseColor' value='0.5 0.1 0.1'/>
            <!-- fieldValue declarations for other Material attributes can appear here -->
          </ProtoInstance>
        </Appearance>
      </Shape>
    </Transform>
    <!-- Selectable Text design pattern has transparent Box and TouchSensor description as a tooltip -->
    <Transform translation='0 -2 0'>
      <Shape>
        <Text string='"enable/disable" "MaterialModulator"'>
          <FontStyle family='"SANS"' justify='"MIDDLE" "MIDDLE"' style='BOLD'/>
        </Text>
        <Appearance>
          <Material diffuseColor='0.9 0.9 0.9'/>
        </Appearance>
      </Shape>
      <Shape>
        <Box size='8 2 .001'/>
        <Appearance>
          <Material transparency='1'/>
        </Appearance>
      </Shape>
      <!-- Toggle text to enable/disable MaterialModulator -->
      <TouchSensor DEF='TouchTextInterface' description='Select to enable/disable MaterialModulator'/>
      <BooleanToggle DEF='EventToggler'/>
      <ROUTE fromField='isActive' fromNode='TouchTextInterface' toField='set_boolean' toNode='EventToggler'/>
      <ROUTE fromField='toggle' fromNode='EventToggler' toField='enabled' toNode='MaterialModulatorInstance'/>
    </Transform>
  </Scene>
</X3D>