#VRML_SIM R2022b utf8
# license: Copyright Cyberbotics Ltd. Licensed for use only with Webots.
# license url: https://cyberbotics.com/webots_assets_license
# A box object implemented at the Solid-node level.
# The box has similar properties as the VRML Box node in term of axis and fields.
# The UV-mapping is defined in a metric way (the textures are not deformed - the reference is the longest edge).
# template language: javascript

PROTO SolidBox [
  field SFVec3f    translation           0 0 0
  field SFRotation rotation              0 0 1 0
  field SFString   name                  "box"
  field SFVec3f    size                  2 2 2                                                                                                         # Defines the size of the box.                                                                                                             # Defines the number of polygons used to represent the box and so its resolution.
  field SFString   contactMaterial       "default"                                                                                                     # Is `Solid.contactMaterial`.
  field SFNode     appearance            PBRAppearance { baseColorMap ImageTexture { url [ "webots://projects/default/worlds/textures/tagged_wall.jpg" ] } metalness 0 roughness 0.5 }  # Defines the appearance of the box.
  field SFNode     physics               NULL                                                                                                          # Is `Solid.physics`.
  field SFBool     enableBoundingObject  TRUE                                                                                                          # Defines whether the solid should have a bounding object.
  field SFBool     castShadows           TRUE                                                                                                          # Defines whether this object should cast shadows.
]
{
  %<
    let size = fields.size.value;
    if (size.x <= 0 || size.y <= 0 || size.z <= 0) {
      size = fields.size.defaultValue;
      console.error('\'size\' must contain positive values. Value reset to (' + size.x + ', ' + size.y + ', ' + size.z + ').');
    }

    // attempt to create quads as square as possible
    // subdivision is applied only on the longest egde
    let maxEdge = Math.max(Math.max(size.x, size.y), size.z);
    let ratio = {x: size.x / maxEdge, y: size.y / maxEdge, z: size.z / maxEdge};

    const halfSize = {x: size.x * 0.5, y: size.y * 0.5, z: size.z * 0.5};

    const quads = [
      // quadLeft
      [
        {x: -halfSize.x, y: halfSize.y, z:  halfSize.z, u: ratio.x, v: ratio.z }, // vertex A
        {x:  halfSize.x, y: halfSize.y, z:  halfSize.z, u: 0,       v: ratio.z }, // vertex B
        {x:  halfSize.x, y: halfSize.y, z: -halfSize.z, u: 0,       v: 0       }, // ...
        {x: -halfSize.x, y: halfSize.y, z: -halfSize.z, u: ratio.x, v: 0       }
      ],
      // quadRight
      [
        {x: -halfSize.x, y: -halfSize.y, z: -halfSize.z, u: 0,       v: 0       },
        {x:  halfSize.x, y: -halfSize.y, z: -halfSize.z, u: ratio.x, v: 0       },
        {x:  halfSize.x, y: -halfSize.y, z:  halfSize.z, u: ratio.x, v: ratio.z },
        {x: -halfSize.x, y: -halfSize.y, z:  halfSize.z, u: 0,       v: ratio.z }
      ],
      // quadTop
      [
        {x: -halfSize.x, y: -halfSize.y, z: halfSize.z, u: 0,       v: ratio.x },
        {x:  halfSize.x, y: -halfSize.y, z: halfSize.z, u: 0,       v: 0       },
        {x:  halfSize.x, y:  halfSize.y, z: halfSize.z, u: ratio.y, v: 0       },
        {x: -halfSize.x, y:  halfSize.y, z: halfSize.z, u: ratio.y, v: ratio.x }
      ],
      // quadBottom
      [
        {x:  halfSize.x, y: -halfSize.y, z: -halfSize.z, u: 0,       v: ratio.x },
        {x: -halfSize.x, y: -halfSize.y, z: -halfSize.z, u: 0,       v: 0       },
        {x: -halfSize.x, y:  halfSize.y, z: -halfSize.z, u: ratio.y, v: 0       },
        {x:  halfSize.x, y:  halfSize.y, z: -halfSize.z, u: ratio.y, v: ratio.x }
      ],
      // quadBack 
      [
        {x: -halfSize.x, y: -halfSize.y, z: -halfSize.z, u: ratio.y, v: 0       },
        {x: -halfSize.x, y: -halfSize.y, z:  halfSize.z, u: ratio.y, v: ratio.z },
        {x: -halfSize.x, y:  halfSize.y, z:  halfSize.z, u: 0,       v: ratio.z },
        {x: -halfSize.x, y:  halfSize.y, z: -halfSize.z, u: 0,       v: 0       }
      ],
      // quadFront
      [
        {x: halfSize.x, y: -halfSize.y, z:  halfSize.z, u: 0,       v: ratio.z },
        {x: halfSize.x, y: -halfSize.y, z: -halfSize.z, u: 0,       v: 0       },
        {x: halfSize.x, y:  halfSize.y, z: -halfSize.z, u: ratio.y, v: 0       },
        {x: halfSize.x, y:  halfSize.y, z:  halfSize.z, u: ratio.y, v: ratio.z }
      ]
    ];

    let quad;
  >%
  Solid {
    translation IS translation
    rotation IS rotation
    children [
      Shape {
        appearance IS appearance
        geometry IndexedFaceSet {
          coord Coordinate {
            point [
              %<
                for (let i = 0; i < quads.length; ++i) {
                  quad = quads[i];
              >%
                %<= quad[0].x >% %<= quad[0].y >% %<= quad[0].z >%
                %<= quad[1].x >% %<= quad[1].y >% %<= quad[1].z >%
                %<= quad[2].x >% %<= quad[2].y >% %<= quad[2].z >%
                %<= quad[3].x >% %<= quad[3].y >% %<= quad[3].z >%
              %< } >%
            ]
          }
          texCoord TextureCoordinate {
            point [
              %<
                for (let i = 0; i < quads.length; ++i) {
                  quad = quads[i];
              >%
                %<= quad[0].u >% %<= quad[0].v >%
                %<= quad[1].u >% %<= quad[1].v >%
                %<= quad[2].u >% %<= quad[2].v >%
                %<= quad[3].u >% %<= quad[3].v >%
              %< } >%
            ]
          }
          coordIndex [
          %<
            let offset;
            for (let i = 0; i < quads.length; ++i) {
              quad = quads[i];
              offset = 4 * i;
          >%
              %<= offset >% %<= offset + 1 >% %<= offset + 2 >% %<= offset + 3 >% -1
            %< } >%
          ]
          creaseAngle 1.5
        }
        castShadows IS castShadows
      }
    ]
    name IS name
    model "box"
    contactMaterial IS contactMaterial
    %< if (fields.enableBoundingObject.value) { >%
    boundingObject Box {
      size %<= size.x >% %<= size.y >% %<= size.z >%
    }
    %< } >%
    physics IS physics
  }
}