-
Notifications
You must be signed in to change notification settings - Fork 2
/
worker-core.coffee
146 lines (136 loc) · 4.12 KB
/
worker-core.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
###
#
# This worker file needs to be concatenated with TubeGenerator and gl-matrix.
# Type "cake worker" to ask the cakefile to do all this work.
#
# Here's our little JSON-based communication protocol. Eveything in the left column
# is an object property except 'type', which tells you which direction(s) the message
# should travel in.
#
# ---------------------------
# command: 'download-spines'
# type: client -> worker
# url: <STRING>
# ---------------------------
# command: 'spine-data'
# type: worker -> client
# data: <ArrayBuffer>
# scale: <float>
# ---------------------------
# command: 'tessellate-link'
# type: client -> worker
# id: <anything>
# link: <Array of RANGE>
# where RANGE = [INTEGER, INTEGER]
# ---------------------------
# command: 'mesh-link'
# type: worker -> client
# id: <anything>
# meshes: <Array of MESH>
# where MESH =
# tube: <Float32Array>
# wireframe: <Uint16Array>
# triangles: <Uint16Array>
# ---------------------------
# command: 'debug-message'
# type: worker -> client
# text: <anything>
# ---------------------------
#
###
tubeGen = null
initialized = null
spines = null
@onmessage = (e) ->
initialize() if not initialized?
msg = e.data
switch msg.command
when 'download-spines'
rawdata = download msg.url
spines = new Float32Array rawdata
response =
command: 'spine-data'
data: rawdata
scale: tubeGen.scale
@postMessage response
when 'tessellate-link'
meshes = (tessellate knot for knot in msg.link)
response =
command: 'mesh-link'
id: msg.id
meshes: meshes
@postMessage response
initialize = ->
tubeGen = new TubeGenerator
tubeGen.polygonSides = 10
tubeGen.bézierSlices = 3
tubeGen.tangentSmoothness = 3
initialized = true
download = (url) ->
xhr = new XMLHttpRequest()
xhr.open "GET", url, false
xhr.overrideMimeType "text/plain; charset=x-user-defined"
hasResponseType = "responseType" of xhr
xhr.responseType = "arraybuffer" if hasResponseType
xhr.send null
return null if xhr.status isnt 200
if hasResponseType then xhr.response else xhr.mozResponseArrayBuffer
tessellate = (component) ->
# Perform Bézier interpolation
byteOffset = component[0] * 3 * 4
numFloats = component[1] * 3
segmentData = spines.subarray(component[0] * 3, component[0] * 3 + component[1] * 3)
centerline = tubeGen.getKnotPath(segmentData)
# Create a positions buffer for a swept octagon
rawBuffer = tubeGen.generateTube(centerline)
tube = rawBuffer
# Create the index buffer for the tube wireframe
# TODO This can be re-used from one knot to another
polygonCount = centerline.length / 3 - 1
sides = tubeGen.polygonSides
lineCount = polygonCount * sides * 2
rawBuffer = new Uint16Array(lineCount * 2)
[i, ptr] = [0, 0]
while i < polygonCount * (sides+1)
j = 0
while j < sides
sweepEdge = rawBuffer.subarray(ptr+2, ptr+4)
sweepEdge[0] = i+j
sweepEdge[1] = i+j+sides+1
[ptr, j] = [ptr+2, j+1]
i += sides+1
i = 0
while i < polygonCount * (sides+1)
j = 0
while j < sides
polygonEdge = rawBuffer.subarray(ptr+0, ptr+2)
polygonEdge[0] = i+j
polygonEdge[1] = i+j+1
[ptr, j] = [ptr+2, j+1]
i += sides+1
wireframe = rawBuffer
# Create the index buffer for the solid tube
# TODO This can be be re-used from one knot to another
faceCount = centerline.length/3 * sides * 2
rawBuffer = new Uint16Array(faceCount * 3)
[i, ptr, v] = [0, 0, 0]
while ++i < centerline.length/3
j = -1
while ++j < sides
next = (j + 1) % sides
tri = rawBuffer.subarray(ptr+0, ptr+3)
tri[0] = v+next+sides+1
tri[1] = v+next
tri[2] = v+j
tri = rawBuffer.subarray(ptr+3, ptr+6)
tri[0] = v+j
tri[1] = v+j+sides+1
tri[2] = v+next+sides+1
ptr += 6
v += sides+1
triangles = rawBuffer
# Return metadata
mesh =
tube: tube
wireframe: wireframe
triangles: triangles