feat: Set faces one or two-sided, conservatively

Set VRML97 translation of IndexedFaceSets to specify `solid false`
  unless the faces were explicitly indicated to have CLOCKWISE or
  COUNTERCLOCKWISE vertex ordering. This is conservative, but otherwise
  shapes may be "see-through" in undesirable ways, if the original
  VRML 1 vertices are not ordered consistently with the VRML97 default.

  Also fixes a typo/bug in picking up numerical values of parameters,
  and ensures that fields in the output VRML97 are always separated by
  at least a space, comma, or parenthesis.
This commit is contained in:
Glen Whitney 2024-02-12 13:10:49 -08:00
parent bb0ef18903
commit 92be417845
4 changed files with 58 additions and 37 deletions

View file

@ -67,7 +67,7 @@ function findNumbersAtTopLevel(
{type: 'cbrace'} depth -= 1
{type: 'word'} if depth === 1 and tok.value in fields
selector = tok.value
{tye: 'number'} if selecting then fields[selecting] = tok.value
{type: 'number'} if selecting then fields[selecting] = tok.value
{type: 'obrace'} depth += 1
selecting = selector
@ -105,7 +105,9 @@ function parse(stream: Lexer, tree: Tree = {}): Tree
${renderList newKids} ] }\n`, tree
'ShapeHints'
subTree := parse stream
if 'vertexOrdering' in subTree then tree.ccw = ['true']
if 'vertexOrdering' in subTree
tree.ccw = [
subTree.vertexOrdering[0] is 'ccw' ? 'true' : 'false']
if 'creaseAngle' in subTree
tree.creaseAngle = subTree.creaseAngle
'Coordinate3'
@ -153,8 +155,9 @@ function parse(stream: Lexer, tree: Tree = {}): Tree
...tree.TextureCoordinate, " }\n"
if isFaces and 'creaseAngle' in tree
params.push `creaseAngle ${tree.creaseAngle[0]}`
if isFaces and 'ccw' in tree
params.push `ccw true`
if isFaces
if 'ccw' in tree then params.push `ccw ${tree.ccw[0]}`
else params.push 'solid false'
params.push ...contents
addShape held.value, params, tree
/Light$/
@ -166,6 +169,9 @@ function parse(stream: Lexer, tree: Tree = {}): Tree
{ht: 'word', hv: 'vertexOrdering', nt: 'word', nv: 'COUNTERCLOCKWISE'}
tree.vertexOrdering = ['ccw']
held = filtered stream
{ht: 'word', hv: 'vertexOrdering', nt: 'word', nv: 'CLOCKWISE'}
tree.vertexOrdering = ['cw']
held = filtered stream
{ht: 'word', hv: 'creaseAngle', nt: 'number'}
tree.creaseAngle = [ next.value ]
held = filtered stream
@ -236,13 +242,13 @@ function render(t: string | Tree): string
if 'type' in t and 'value' in t
val := renderList t.value
return switch t.type[0]
/string|number|word/ ` ${val}`
/string|number|word/ val
/comma|oparen|cparen/ val
/obrace|cbrace|obracket|cbracket/ ` ${val}\n`
/obrace|cbrace|obracket|cbracket/ `${val}\n`
else `\nUNKNOWN TYPE ${t.type}\n\n`
result .= ''
for prop in t
result += `${prop} {\n ${renderList t[prop]} }\n`
result += `${prop} {\n ${renderList t[prop]} }\n`
return result
function renderList(l: (string | Tree)[]): string
@ -251,7 +257,10 @@ function renderList(l: (string | Tree)[]): string
commaNewlineOnce .= false
commaTriggersNewline .= false
for each item of l
return.value += render item
next := render item
if return.value and not ',()'.includes next[0]
return.value += ' '
return.value += next
switch item
{type: ['word'], value: ['point']}
commaTriggersNewline = true