forked from unconed/mathbox
/
index.coffee
164 lines (123 loc) · 4.13 KB
/
index.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Global constructor
mathBox = (options) ->
three = THREE.Bootstrap options
if !three.fallback
three.install 'time' if !three.Time
three.install ['mathbox', 'splash'] if !three.MathBox
three.mathbox ? three
# Just because
window.π = Math.PI
window.τ = π * 2
window.e = Math.E
# Namespace
window.MathBox = exports
window.mathBox = exports.mathBox = mathBox
# Load context and export namespace
exports.Context = Context = require './context'
exports.version = Context.Version
exports[k] = v for k, v of Context.Namespace
# Splash screen plugin
require './splash'
# Threestrap plugin
THREE.Bootstrap.registerPlugin 'mathbox',
defaults:
init: true
warmup: 2
inspect: true
splash: true
listen: ['ready', 'pre', 'update', 'post', 'resize'],
# Install meta-API
install: (three) ->
inited = false
@first = true
three.MathBox =
# Init the mathbox context
init: (options) =>
return if inited
inited = true
scene = options?.scene || @options.scene || three.scene
camera = options?.camera || @options.camera || three.camera
@context = new Context three.renderer, scene, camera
# Enable handy destructuring
@context.api.three = three.three = three
@context.api.mathbox = three.mathbox = @context.api
# v1 compatibility
@context.api.start = () -> three.Loop.start()
@context.api.stop = () -> three.Loop.stop()
# Initialize and set initial size
@context.init()
@context.resize three.Size
# Set warmup mode and track pending objects
@context.setWarmup @options.warmup
@pending = 0
@warm = !@options.warmup
console.log 'MathBox²', MathBox.version
three.trigger {type: 'mathbox/init', version: MathBox.version, context: @context}
# Destroy the mathbox context
destroy: () =>
return if !inited
inited = false
three.trigger {type: 'mathbox/destroy', context: @context}
@context.destroy()
delete three.mathbox
delete @context.api.three
delete @context
object: () => @context?.scene.root
uninstall: (three) ->
three.MathBox.destroy()
delete three.MathBox
# Ready event: right before mathbox() / THREE.bootstrap() returns
ready: (event, three) ->
if @options.init
three.MathBox.init()
setTimeout () =>
@inspect three if @options.inspect
# Log scene for inspection
inspect: (three) ->
@context.api.inspect()
@info three if !@options.warmup
info: (three) ->
fmt = (x) ->
out = []
while x >= 1000
out.unshift ("000" + (x % 1000)).slice(-3)
x = Math.floor(x / 1000)
out.unshift x
out.join ','
info = three.renderer.info.render
console.log('Geometry ',
fmt(info.faces) + ' faces ',
fmt(info.vertices) + ' vertices ',
fmt(info.calls) + ' draw calls ');
# Hook up context events
resize: (event, three) ->
@context?.resize three.Size
pre: (event, three) ->
@context?.pre(three.Time)
update: (event, three) ->
@context?.update()
if (camera = @context?.camera) and
camera != three.camera
three.camera = camera
three.Time.set {speed: @context.speed}
@progress @context.getPending(), three
# Call render here instead of on:render because it renders off screen material
# that needs to be available for rendering the actual frame.
@context?.render()
post: (event, three) ->
@context?.post()
# Warmup progress changed
progress: (remain, three) ->
return unless remain or @pending
# Latch max value until queue is emptied to get a total
pending = Math.max remain + @options.warmup, @pending
# Send events for external progress reporting
current = pending - remain
total = pending
three.trigger {type: 'mathbox/progress', current: pending - remain, total: pending}
pending = 0 if remain == 0
@pending = pending
# Report once when loaded
if current == total and !@warm
@warm = true
@info three if @options.inspect