feat: Set faces one or two-sided, conservatively #17

Merged
glen merged 1 commits from faceSides into main 2024-02-12 21:16:21 +00:00
4 changed files with 58 additions and 37 deletions

View File

@ -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.

View File

@ -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',

View File

@ -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:

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