feat: Set faces one or two-sided, conservatively (#17)
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. Also updates dependencies to their latest versions Reviewed-on: #17 Co-authored-by: Glen Whitney <glen@studioinfinity.org> Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
parent
bb0ef18903
commit
fb1d2a020c
12
README.md
12
README.md
@ -62,3 +62,15 @@ Currently this package exports just two functions:
|
||||
than broken into node names and property values. If there is a need to
|
||||
generate XML syntax output, for example, the code would need to be
|
||||
modified to break the tree down further to be ready for conversion to XML.
|
||||
|
||||
## Conversion notes
|
||||
|
||||
One sort of geometry common to VRML 1 and VRML97 is the IndexedFaceSet. These
|
||||
often used to render solids. Indeed, the default in VRML97 is to assume they
|
||||
do represent a solid, with the normals pointing outward. Unusual visual effects
|
||||
ensue if the normals are not properly directed (basically, you see through the
|
||||
"front" of the solid and see the "backs" of the faces on the opposite side).
|
||||
As a result, unless the input VRML 1 explicitly includes an explicit
|
||||
vertexOrdering of CLOCKWISE or COUNTERCLOCKWISE, the default solid treatment
|
||||
will be turned off in the VRML97 output, meaning that all faces will be
|
||||
rendered opaque in both directions.
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
name: 'vrml1to97',
|
||||
version: '0.2.2',
|
||||
version: '0.2.3',
|
||||
description: 'JavaScript converter from VRML 1 to VRML97',
|
||||
scripts: {
|
||||
test: 'echo "Error: no test specified" && exit 1',
|
||||
@ -40,11 +40,11 @@
|
||||
},
|
||||
type: 'module',
|
||||
devDependencies: {
|
||||
'@danielx/civet': '^0.6.38',
|
||||
'@types/moo': '^0.5.6',
|
||||
'@danielx/civet': '^0.6.71',
|
||||
'@types/moo': '^0.5.9',
|
||||
'http-server': '^14.1.1',
|
||||
json5: '^2.2.3',
|
||||
typescript: '^5.2.2',
|
||||
typescript: '^5.3.3',
|
||||
},
|
||||
dependencies: {
|
||||
moo: '^0.5.2',
|
||||
|
@ -11,11 +11,11 @@ dependencies:
|
||||
|
||||
devDependencies:
|
||||
'@danielx/civet':
|
||||
specifier: ^0.6.38
|
||||
version: 0.6.38(typescript@5.2.2)
|
||||
specifier: ^0.6.71
|
||||
version: 0.6.71(typescript@5.3.3)
|
||||
'@types/moo':
|
||||
specifier: ^0.5.6
|
||||
version: 0.5.6
|
||||
specifier: ^0.5.9
|
||||
version: 0.5.9
|
||||
http-server:
|
||||
specifier: ^14.1.1
|
||||
version: 14.1.1
|
||||
@ -23,8 +23,8 @@ devDependencies:
|
||||
specifier: ^2.2.3
|
||||
version: 2.2.3
|
||||
typescript:
|
||||
specifier: ^5.2.2
|
||||
version: 5.2.2
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3
|
||||
|
||||
packages:
|
||||
|
||||
@ -35,8 +35,8 @@ packages:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
dev: true
|
||||
|
||||
/@danielx/civet@0.6.38(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-R63YGIfvV4DQianNPUfMfBX60ozlv5htnRXI1wK3Pg6+d4NZ2V3RifFRH0NkmXXoFkRcULzJ+9BzVeI2/yX+yA==}
|
||||
/@danielx/civet@0.6.71(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-piOoHtJARe6YqRiXN02Ryb+nLU9JwU8TQLknvPwmlaNm6krdKN+X9dM+C9D4LRoAnAySC2wVshR0wf7YDIUV1Q==}
|
||||
engines: {node: '>=19 || ^18.6.0 || ^16.17.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@ -44,8 +44,8 @@ packages:
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@typescript/vfs': 1.5.0
|
||||
typescript: 5.2.2
|
||||
unplugin: 1.4.0
|
||||
typescript: 5.3.3
|
||||
unplugin: 1.7.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -66,8 +66,8 @@ packages:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@types/moo@0.5.6:
|
||||
resolution: {integrity: sha512-Q60hZhulhl2Ox4LjbJvhH+HzsKrwzLPjEB8dZw0fK1MH2HyOLe6LDou68yTfsWasxGv7DPZe5VNM5vgpzOa2nw==}
|
||||
/@types/moo@0.5.9:
|
||||
resolution: {integrity: sha512-ZsFVecFi66jGQ6L41TonEaBhsIVeVftTz6iQKWTctzacHhzYHWvv9S0IyAJi4BhN7vb9qCQ3+kpStP2vbZqmDg==}
|
||||
dev: true
|
||||
|
||||
/@typescript/vfs@1.5.0:
|
||||
@ -78,8 +78,8 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/acorn@8.10.0:
|
||||
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
|
||||
/acorn@8.11.3:
|
||||
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@ -139,8 +139,8 @@ packages:
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
|
||||
/chokidar@3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
/chokidar@3.6.0:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
@ -462,8 +462,8 @@ packages:
|
||||
is-number: 7.0.0
|
||||
dev: true
|
||||
|
||||
/typescript@5.2.2:
|
||||
resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
|
||||
/typescript@5.3.3:
|
||||
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@ -475,13 +475,13 @@ packages:
|
||||
qs: 6.11.2
|
||||
dev: true
|
||||
|
||||
/unplugin@1.4.0:
|
||||
resolution: {integrity: sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==}
|
||||
/unplugin@1.7.1:
|
||||
resolution: {integrity: sha512-JqzORDAPxxs8ErLV4x+LL7bk5pk3YlcWqpSNsIkAZj972KzFZLClc/ekppahKkOczGkwIG6ElFgdOgOlK4tXZw==}
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
chokidar: 3.5.3
|
||||
acorn: 8.11.3
|
||||
chokidar: 3.6.0
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.5.0
|
||||
webpack-virtual-modules: 0.6.1
|
||||
dev: true
|
||||
|
||||
/url-join@4.0.1:
|
||||
@ -493,8 +493,8 @@ packages:
|
||||
engines: {node: '>=10.13.0'}
|
||||
dev: true
|
||||
|
||||
/webpack-virtual-modules@0.5.0:
|
||||
resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
|
||||
/webpack-virtual-modules@0.6.1:
|
||||
resolution: {integrity: sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==}
|
||||
dev: true
|
||||
|
||||
/whatwg-encoding@2.0.0:
|
||||
|
@ -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,7 +242,7 @@ 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`
|
||||
else `\nUNKNOWN TYPE ${t.type}\n\n`
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user