jax 0.0.0.5 → 0.0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +26 -1
- data/Rakefile +3 -1
- data/builtin/shaders/picking/common.ejs +2 -0
- data/builtin/shaders/picking/fragment.ejs +4 -0
- data/builtin/shaders/picking/material.js +14 -0
- data/builtin/shaders/picking/vertex.ejs +24 -0
- data/lib/jax/generators/app/templates/public/javascripts/jax.js +289 -681
- data/lib/jax/generators/app/templates/spec/javascripts/support/spec_layout.html.erb +55 -2
- data/lib/jax/generators/shader/templates/common.ejs.tt +2 -2
- data/lib/jax/packager/sprockets_template.rb +1 -4
- data/lib/jax/routes.rb +3 -0
- data/lib/jax/version.rb +1 -1
- data/spec/example_app/app/controllers/noise_controller.js +37 -5
- data/spec/example_app/app/controllers/picking_controller.js +32 -0
- data/spec/example_app/app/helpers/picking_helper.js +3 -0
- data/spec/example_app/app/models/blob.js +38 -0
- data/spec/example_app/app/resources/blobs/default.yml +2 -0
- data/spec/example_app/app/resources/materials/blob.yml +2 -2
- data/spec/example_app/app/shaders/blob/common.ejs +8 -13
- data/spec/example_app/app/shaders/blob/fragment.ejs +1 -1
- data/spec/example_app/app/shaders/blob/material.js +15 -12
- data/spec/example_app/app/shaders/blob/vertex.ejs +33 -8
- data/spec/example_app/app/views/picking/index.js +4 -0
- data/spec/example_app/config/routes.rb +1 -0
- data/spec/example_app/spec/javascripts/controllers/picking_controller_spec.js +11 -0
- data/spec/example_app/spec/javascripts/helpers/picking_helper_spec.js +12 -0
- data/spec/example_app/spec/javascripts/models/blob_spec.js +11 -0
- data/spec/example_app/spec/javascripts/support/spec_layout.html.erb +40 -2
- data/spec/javascripts/jax/model_spec.js +10 -0
- data/spec/javascripts/jax/world_spec.js +74 -1
- data/spec/javascripts/shaders/preprocessor_spec.js +35 -0
- data/src/constants.yml +1 -1
- data/src/jax.js +30 -8
- data/src/jax/anim_frame.js +6 -2
- data/src/jax/builtin/meshes/cube.js +22 -1
- data/src/jax/builtin/meshes/plane.js +27 -0
- data/src/jax/builtin/meshes/quad.js +7 -1
- data/src/jax/builtin/meshes/sphere.js +20 -1
- data/src/jax/builtin/meshes/teapot.js +10 -0
- data/src/jax/builtin/meshes/torus.js +18 -0
- data/src/jax/compatibility.js +165 -2
- data/src/jax/context.js +176 -9
- data/src/jax/core.js +6 -3
- data/src/jax/core/math.js +18 -3
- data/src/jax/core/matrix_stack.js +4 -3
- data/src/jax/core/util.js +15 -0
- data/src/jax/events.js +67 -12
- data/src/jax/geometry.js +5 -1
- data/src/jax/geometry/plane.js +59 -5
- data/src/jax/{controller.js → mvc/controller.js} +38 -0
- data/src/jax/mvc/helper.js +35 -0
- data/src/jax/mvc/model.js +301 -0
- data/src/jax/{route_set.js → mvc/route_set.js} +0 -0
- data/src/jax/{view.js → mvc/view.js} +6 -0
- data/src/jax/{view_manager.js → mvc/view_manager.js} +1 -0
- data/src/jax/noise.js +13 -0
- data/src/jax/prototype/class.js +3 -0
- data/src/jax/prototype/extensions.js +26 -8
- data/src/jax/webgl/camera.js +6 -6
- data/src/jax/webgl/core/framebuffer.js +4 -4
- data/src/jax/webgl/material.js +16 -0
- data/src/jax/webgl/mesh.js +19 -4
- data/src/jax/webgl/scene/light_manager.js +8 -0
- data/src/jax/webgl/scene/light_source.js +3 -3
- data/src/jax/webgl/shader.js +4 -2
- data/src/jax/webgl/shader_chain.js +1 -0
- data/src/jax/webgl/world.js +157 -6
- data/vendor/glmatrix/glMatrix.js +365 -408
- metadata +32 -10
- data/src/jax/helper.js +0 -8
- data/src/jax/model.js +0 -163
File without changes
|
data/src/jax/noise.js
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
/**
|
2
|
+
* class Jax.Noise
|
3
|
+
* Constructs several textures to be used in vertex shaders involving Perlin noise.
|
4
|
+
*
|
5
|
+
* Example:
|
6
|
+
*
|
7
|
+
* var noise = new Jax.Noise();
|
8
|
+
* var program = new Jax.Shader.Program({...});
|
9
|
+
* program.manifest.set('perm', noise.perm);
|
10
|
+
* program.manifest.set('simplex', noise.simplex);
|
11
|
+
* program.manifest.set('grad', noise.grad);
|
12
|
+
*
|
13
|
+
**/
|
1
14
|
Jax.Noise = (function() {
|
2
15
|
var perm/*[256]*/ = [151,160,137,91,90,15,
|
3
16
|
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
data/src/jax/prototype/class.js
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
/* My own custom extensions to Prototype */
|
2
|
-
|
3
1
|
//= require "class"
|
4
2
|
|
5
3
|
(function() {
|
@@ -112,12 +110,32 @@
|
|
112
110
|
return klass;
|
113
111
|
};
|
114
112
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
/**
|
114
|
+
* Jax.Class.delegate() -> undefined
|
115
|
+
*
|
116
|
+
* This is a class method of all Jax classes.
|
117
|
+
*
|
118
|
+
* Delegates one or more methods into properties of the class. For instance,
|
119
|
+
* the following:
|
120
|
+
*
|
121
|
+
* MyClass.delegate("sayHello").into("person");
|
122
|
+
*
|
123
|
+
* will create a +sayHello+ method in the +MyClass+ class that internally calls
|
124
|
+
*
|
125
|
+
* this.person.sayHello(...)
|
126
|
+
*
|
127
|
+
* and returns the results.
|
128
|
+
*
|
129
|
+
* There are several other variants:
|
130
|
+
*
|
131
|
+
* klass.delegate(/regular expression/).into("property_name");
|
132
|
+
* // delegates any method name in +property_name+ that matches the expression
|
133
|
+
*
|
134
|
+
* klass.delegate("one", "two").into("property_name");
|
135
|
+
* // delegates both 'one' and 'two' methods into +property_name+
|
136
|
+
*
|
137
|
+
*
|
138
|
+
**/
|
121
139
|
Jax.Class.Methods.delegate = function() {
|
122
140
|
return new Delegator(this, arguments);
|
123
141
|
};
|
data/src/jax/webgl/camera.js
CHANGED
@@ -361,12 +361,12 @@ Jax.Camera = (function() {
|
|
361
361
|
},
|
362
362
|
|
363
363
|
/**
|
364
|
-
* Jax.Camera#
|
364
|
+
* Jax.Camera#getTransformationMatrix() -> mat4
|
365
365
|
*
|
366
|
-
* Returns the
|
366
|
+
* Returns the transformation matrix. This matrix represents the camera's position and
|
367
367
|
* orientation in the world.
|
368
368
|
**/
|
369
|
-
|
369
|
+
getTransformationMatrix: function() { return this.matrices.mv; },
|
370
370
|
|
371
371
|
/**
|
372
372
|
* Jax.Camera#getProjectionMatrix() -> mat4
|
@@ -377,16 +377,16 @@ Jax.Camera = (function() {
|
|
377
377
|
getProjectionMatrix: function() { return this.matrices.p; },
|
378
378
|
|
379
379
|
/**
|
380
|
-
* Jax.Camera#getNormalMatrix() ->
|
380
|
+
* Jax.Camera#getNormalMatrix() -> mat3
|
381
381
|
*
|
382
382
|
* Returns the normal matrix, which is defined as the transpose of the inverse of the
|
383
|
-
*
|
383
|
+
* transformation matrix.
|
384
384
|
*
|
385
385
|
* This matrix is commonly used in lighting calculations.
|
386
386
|
**/
|
387
387
|
getNormalMatrix: function() {
|
388
388
|
if (!this.normal_matrix_up_to_date) {
|
389
|
-
mat4.toInverseMat3(this.
|
389
|
+
mat4.toInverseMat3(this.getTransformationMatrix(), this.matrices.n);
|
390
390
|
mat3.transpose(this.matrices.n);
|
391
391
|
}
|
392
392
|
this.normal_matrix_up_to_date = true;
|
@@ -114,12 +114,12 @@ Jax.Framebuffer = (function() {
|
|
114
114
|
*
|
115
115
|
* * color: optionally, in place of a colors array, a single color format as above. If both
|
116
116
|
* _color_ and _colors_ are specified, _color_ is simply added to the _colors_ array.
|
117
|
-
* * depth: true if a depth attachment is required, false otherwise.
|
118
|
-
* * stencil: true if a stencil attachment is required, false otherwise.
|
117
|
+
* * depth: true if a depth attachment is required, false otherwise. Defaults to false.
|
118
|
+
* * stencil: true if a stencil attachment is required, false otherwise. Defaults to false.
|
119
119
|
* * width: the width of the render and color buffers. All render and color buffers for a given
|
120
|
-
* framebuffer must have the same width. Defaults to
|
120
|
+
* framebuffer must have the same width. Defaults to 512.
|
121
121
|
* * height: the height of the render and color buffers. All render and color buffers for a given
|
122
|
-
* framebuffer must have the same height. Defaults to
|
122
|
+
* framebuffer must have the same height. Defaults to 512.
|
123
123
|
*
|
124
124
|
**/
|
125
125
|
initialize: function(options) {
|
data/src/jax/webgl/material.js
CHANGED
@@ -83,6 +83,20 @@ Jax.Material = (function() {
|
|
83
83
|
}
|
84
84
|
},
|
85
85
|
|
86
|
+
/**
|
87
|
+
* Jax.Material#supportsLighting() -> Boolean
|
88
|
+
*
|
89
|
+
* Returns true if this material supports lighting effects.
|
90
|
+
**/
|
91
|
+
supportsLighting: function() {
|
92
|
+
if (this.getName() == "lighting")
|
93
|
+
return true;
|
94
|
+
for (var i = 0; i < this.layers.length; i++)
|
95
|
+
if (this.layers[i].getName() == "lighting")
|
96
|
+
return true;
|
97
|
+
return false;
|
98
|
+
},
|
99
|
+
|
86
100
|
getName: function() { return this.name; },
|
87
101
|
|
88
102
|
addTextureLayer: function(tex) {
|
@@ -369,8 +383,10 @@ Jax.Material.addResources = function(resources) {
|
|
369
383
|
//= require "../../../builtin/shaders/depthmap/material"
|
370
384
|
//= require "../../../builtin/shaders/paraboloid/material"
|
371
385
|
//= require "../../../builtin/shaders/fog/material"
|
386
|
+
//= require "../../../builtin/shaders/picking/material"
|
372
387
|
|
373
388
|
Jax.Material.create("basic");
|
374
389
|
Jax.Material.create("default", {default_shader:'basic'});
|
375
390
|
Jax.Material.create("depthmap", {default_shader:"depthmap"});
|
376
391
|
Jax.Material.create("paraboloid-depthmap", {type:"Paraboloid",default_shader:"paraboloid",layers:[{type:"Depthmap"}]});
|
392
|
+
Jax.Material.create("picking", {type:"Picking"});
|
data/src/jax/webgl/mesh.js
CHANGED
@@ -225,6 +225,24 @@ Jax.Mesh = (function() {
|
|
225
225
|
if (!this.draw_mode)
|
226
226
|
this.draw_mode = GL_TRIANGLES;
|
227
227
|
},
|
228
|
+
|
229
|
+
/**
|
230
|
+
* Jax.Mesh#setColor(red, green, blue, alpha) -> Jax.Mesh
|
231
|
+
* Sets the color of this mesh. This will set the color at each vertex, regardless
|
232
|
+
* of the original color of that vertex. The result will be that the entire mesh
|
233
|
+
* takes on the specified color (not just a particular vertex).
|
234
|
+
**/
|
235
|
+
setColor: function(red, green, blue, alpha) {
|
236
|
+
var buf = this.getColorBuffer();
|
237
|
+
for (var i = 0; i < buf.js.length; i += 4) {
|
238
|
+
buf.js[i] = red;
|
239
|
+
buf.js[i+1] = green;
|
240
|
+
buf.js[i+2] = blue;
|
241
|
+
buf.js[i+3] = alpha;
|
242
|
+
}
|
243
|
+
buf.refresh();
|
244
|
+
return this;
|
245
|
+
},
|
228
246
|
|
229
247
|
/**
|
230
248
|
* Jax.Mesh#dispose() -> undefined
|
@@ -302,14 +320,11 @@ Jax.Mesh = (function() {
|
|
302
320
|
var result = Jax.Util.normalizeOptions(options, {
|
303
321
|
material: this.material,
|
304
322
|
default_material: this.default_material,
|
305
|
-
// default_shader: this.default_shader,
|
306
|
-
// shader: this.shader,
|
307
323
|
draw_mode: this.draw_mode || GL_TRIANGLES
|
308
324
|
});
|
309
325
|
|
310
326
|
if (!result.material) result.material = result.default_material;
|
311
|
-
|
312
|
-
|
327
|
+
|
313
328
|
result.material = findMaterial(result.material);
|
314
329
|
|
315
330
|
return result;
|
@@ -38,11 +38,15 @@ Jax.Scene.LightManager = (function() {
|
|
38
38
|
},
|
39
39
|
|
40
40
|
illuminate: function(context, objects, options) {
|
41
|
+
options = Jax.Util.normalizeOptions(options, {});
|
42
|
+
|
41
43
|
// Use alpha blending for the first pass, and additive blending for subsequent passes.
|
42
44
|
this.context.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
43
45
|
for (var i = 0; i < this._lights.length; i++) {
|
44
46
|
for (var j = 0; j < objects.length; j++) {
|
45
47
|
this._current_light = i;
|
48
|
+
options.model_index = j;
|
49
|
+
|
46
50
|
/* TODO optimization: see if objects[j] is even affected by this._lights[i] (based on attenuation) */
|
47
51
|
if (objects[j].isLit())
|
48
52
|
objects[j].render(context, options);
|
@@ -53,9 +57,13 @@ Jax.Scene.LightManager = (function() {
|
|
53
57
|
},
|
54
58
|
|
55
59
|
ambient: function(context, objects, options) {
|
60
|
+
options = Jax.Util.normalizeOptions(options, {});
|
61
|
+
|
56
62
|
for (var i = 0; i < this._lights.length; i++) {
|
57
63
|
this._current_light = i;
|
58
64
|
for (var j = 0; j < objects.length; j++) {
|
65
|
+
options.model_index = j;
|
66
|
+
|
59
67
|
/* TODO optimization: see if objects[j] is even affected by this._lights[i] (based on attenuation) */
|
60
68
|
if (objects[j].isLit())
|
61
69
|
objects[j].render(context, options);
|
@@ -167,7 +167,7 @@ Jax.Scene.LightSource = (function() {
|
|
167
167
|
// front paraboloid
|
168
168
|
self.framebuffers[0].viewport(context);
|
169
169
|
context.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
170
|
-
context.loadViewMatrix(self.camera.
|
170
|
+
context.loadViewMatrix(self.camera.getTransformationMatrix());
|
171
171
|
mat4.set(context.getInverseViewMatrix(), sm);
|
172
172
|
|
173
173
|
for (var i = 0; i < objects.length; i++) {
|
@@ -179,7 +179,7 @@ Jax.Scene.LightSource = (function() {
|
|
179
179
|
// back paraboloid
|
180
180
|
self.framebuffers[1].viewport(context);
|
181
181
|
context.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
182
|
-
context.loadViewMatrix(self.camera.
|
182
|
+
context.loadViewMatrix(self.camera.getTransformationMatrix());
|
183
183
|
for (var i = 0; i < objects.length; i++) {
|
184
184
|
objects[i].render(context, {material:paraboloid_depthmap,direction:-1});
|
185
185
|
}
|
@@ -203,7 +203,7 @@ Jax.Scene.LightSource = (function() {
|
|
203
203
|
context.pushMatrix(function() {
|
204
204
|
self.framebuffers[0].viewport(context);
|
205
205
|
context.matrix_stack.loadProjectionMatrix(self.camera.getProjectionMatrix());
|
206
|
-
context.matrix_stack.loadViewMatrix(self.camera.
|
206
|
+
context.matrix_stack.loadViewMatrix(self.camera.getTransformationMatrix());
|
207
207
|
mat4.identity(sm);
|
208
208
|
sm[0] = sm[5] = sm[10] = sm[12] = sm[13] = sm[14] = 0.5;
|
209
209
|
mat4.multiply(sm, context.getModelViewProjectionMatrix());
|
data/src/jax/webgl/shader.js
CHANGED
@@ -103,12 +103,13 @@ Jax.Shader = (function() {
|
|
103
103
|
for (var i in map) {
|
104
104
|
if (map[i].shared) {
|
105
105
|
if (options.skip_global_definitions && options.skip_global_definitions.indexOf(map[i].full_name) != -1) {
|
106
|
-
var rx = new RegExp("(shared\\s+)
|
106
|
+
var rx = new RegExp("(shared\\s+)"+map[i].scope+"\\s*"+map[i].type+"[^;]*?"+map[i].full_name+"[^;]*?;\n?", "g");
|
107
107
|
source = source.replace(rx, "");
|
108
108
|
}
|
109
109
|
// else source = source.replace(rx, map[i].scope+" "+map[i].type+" "+map[i].full_name+";\n");
|
110
110
|
}
|
111
111
|
}
|
112
|
+
|
112
113
|
return source.replace(/shared\s+/, '');
|
113
114
|
}
|
114
115
|
|
@@ -121,6 +122,7 @@ Jax.Shader = (function() {
|
|
121
122
|
source = applyExports(self, options, source);
|
122
123
|
source = applyImports(self, options, source);
|
123
124
|
source = mangleUniformsAndAttributes(self, options, source);
|
125
|
+
|
124
126
|
return source;
|
125
127
|
}
|
126
128
|
|
@@ -234,7 +236,7 @@ Jax.Shader = (function() {
|
|
234
236
|
(this.getRawSource(options, 'fragment') || "");
|
235
237
|
|
236
238
|
// if it's not a "shared" uniform, mangle its name.
|
237
|
-
var rx = new RegExp("(^|\\n|\\s+)((shared\\s+)?)(uniform|attribute|varying)
|
239
|
+
var rx = new RegExp("(^|\\n|\\s+)((shared\\s+)?)(uniform|attribute|varying)\\s+(\\w+)\\s+((?!"+prefix+")[^;]*);"), result;
|
238
240
|
while (result = rx.exec(source)) {
|
239
241
|
var shared = /shared/.test(result[2]);
|
240
242
|
var scope = result[4];
|
data/src/jax/webgl/world.js
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
//= require "scene"
|
2
2
|
|
3
|
+
/**
|
4
|
+
* class Jax.World
|
5
|
+
*
|
6
|
+
* A +Jax.World+ represents a scene in the graphics engine. All objects to be rendered (or at least,
|
7
|
+
* all objects that you do not want to manually control!) should be added to the world. Each instance
|
8
|
+
* of +Jax.Context+ has its own +Jax.World+, and the currently-active +Jax.World+ is delegated into
|
9
|
+
* controllers and views as the +this.world+ property.
|
10
|
+
*
|
11
|
+
**/
|
3
12
|
Jax.World = (function() {
|
13
|
+
function getPickBuffer(self) {
|
14
|
+
if (self.pickBuffer) return self.pickBuffer;
|
15
|
+
return self.pickBuffer = new Jax.Framebuffer({
|
16
|
+
width:self.context.canvas.width,
|
17
|
+
height:self.context.canvas.height
|
18
|
+
});
|
19
|
+
}
|
20
|
+
|
4
21
|
return Jax.Class.create({
|
5
22
|
initialize: function(context) {
|
6
23
|
this.context = context;
|
@@ -9,12 +26,38 @@ Jax.World = (function() {
|
|
9
26
|
this.shadow_casters = [];
|
10
27
|
},
|
11
28
|
|
29
|
+
/**
|
30
|
+
* Jax.World#addLightSource(light) -> Jax.Scene.LightSource
|
31
|
+
* - light (Jax.Scene.LightSource) : the instance of Jax.Scene.LightSource to add to this world.
|
32
|
+
*
|
33
|
+
* Adds the light to the world and then returns the light itself unchanged.
|
34
|
+
**/
|
12
35
|
addLightSource: function(light) { this.lighting.add(light); },
|
13
36
|
|
37
|
+
/**
|
38
|
+
* Jax.World#addObject(object) -> Jax.Model
|
39
|
+
* - object (Jax.Model) : the instance of Jax.Model to add to this world.
|
40
|
+
*
|
41
|
+
* Adds the model to the world and then returns the model itself unchanged.
|
42
|
+
*
|
43
|
+
**/
|
14
44
|
addObject: function(object) { this.objects.push(object); this.invalidate(); return object; },
|
15
45
|
|
46
|
+
/**
|
47
|
+
* Jax.World#getObject(index) -> Jax.Model
|
48
|
+
* - index (Number) : the world index of this object
|
49
|
+
*
|
50
|
+
* Returns the object with the specified world index, or undefined.
|
51
|
+
**/
|
16
52
|
getObject: function(index) { return this.objects[index]; },
|
17
53
|
|
54
|
+
/**
|
55
|
+
* Jax.World#removeObject(object_or_index) -> Jax.Model
|
56
|
+
* - object_or_index (Number|Jax.Model) : the model instance to remove, or its world index
|
57
|
+
*
|
58
|
+
* If the model or its index cannot be found, nothing happens and the return value is undefined.
|
59
|
+
* Otherwise, the object is removed from this World and then returned.
|
60
|
+
**/
|
18
61
|
removeObject: function(object_or_index) {
|
19
62
|
if (this.objects[object_or_index]) {
|
20
63
|
var obj = this.objects[object_or_index];
|
@@ -32,6 +75,110 @@ Jax.World = (function() {
|
|
32
75
|
}
|
33
76
|
},
|
34
77
|
|
78
|
+
/**
|
79
|
+
* Jax.World#pickRegionalIndices(x1, y1, x2, y2[, ary]) -> Array
|
80
|
+
* - x1 (Number): the screen X coordinate of the first corner of the 2D rectangle within which to pick
|
81
|
+
* - y1 (Number): the screen Y coordinate of the first corner of the 2D rectangle within which to pick
|
82
|
+
* - x2 (Number): the screen X coordinate of the second corner of the 2D rectangle within which to pick
|
83
|
+
* - y2 (Number): the screen Y coordinate of the second corner of the 2D rectangle within which to pick
|
84
|
+
* - ary (Array): an optional array to populate. A new one will be created if this is not specified.
|
85
|
+
* (Note: the array's contents will be cleared.)
|
86
|
+
*
|
87
|
+
* Picks all visible object indices within the specified rectangular regions and returns them as elements in
|
88
|
+
* an array.
|
89
|
+
*
|
90
|
+
* An object's index matches its position in the world's object list. That is, the following code is
|
91
|
+
* valid:
|
92
|
+
*
|
93
|
+
* this.world.getObjects(this.world.pickRegionalIDs(0,0, 100,100));
|
94
|
+
*
|
95
|
+
**/
|
96
|
+
pickRegionalIndices: function(x1, y1, x2, y2, ary) {
|
97
|
+
var w = Math.abs(x2 - x1), h = Math.abs(y2 - y1);
|
98
|
+
if (ary) ary.clear();
|
99
|
+
else ary = new Array();
|
100
|
+
var world = this, pickBuffer = getPickBuffer(this), context = this.context;
|
101
|
+
var data = new Uint8Array(w*h*4);
|
102
|
+
|
103
|
+
pickBuffer.bind(context, function() {
|
104
|
+
pickBuffer.viewport(context);
|
105
|
+
context.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
106
|
+
context.glDisable(GL_BLEND);
|
107
|
+
world.render({material:"picking"});
|
108
|
+
// read it back in
|
109
|
+
context.glReadPixels(x1, y1, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
110
|
+
if (data.data) data = data.data;
|
111
|
+
});
|
112
|
+
|
113
|
+
// restore the visible viewport and blending
|
114
|
+
context.glViewport(0, 0, context.canvas.width, context.canvas.height);
|
115
|
+
context.glEnable(GL_BLEND);
|
116
|
+
|
117
|
+
var index;
|
118
|
+
for (var i = 2; i < data.length; i += 4) {
|
119
|
+
if (data[i] > 0) { // blue key exists, we've found an object
|
120
|
+
index = Jax.Util.decodePickingColor(data[i-2], data[i-1], data[i], data[i+1]);
|
121
|
+
if (index != undefined) {
|
122
|
+
ary.push(index);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
return ary;
|
128
|
+
},
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Jax.World#pickRegion(x1, y1, x2, y2) -> Array
|
132
|
+
* - x1 (Number): the screen X coordinate of the first corner of the 2D rectangle within which to pick
|
133
|
+
* - y1 (Number): the screen Y coordinate of the first corner of the 2D rectangle within which to pick
|
134
|
+
* - x2 (Number): the screen X coordinate of the second corner of the 2D rectangle within which to pick
|
135
|
+
* - y2 (Number): the screen Y coordinate of the second corner of the 2D rectangle within which to pick
|
136
|
+
* - ary (Array): an optional array to populate. A new one will be created if this is not specified.
|
137
|
+
* (Note: the array's contents will be cleared.)
|
138
|
+
*
|
139
|
+
* Picks all visible objects within the specified rectangular regions and returns them as elements in
|
140
|
+
* an array.
|
141
|
+
**/
|
142
|
+
pickRegion: function(x1, y1, x2, y2, ary) {
|
143
|
+
var result = this.pickRegionalIndices(x1, y1, x2, y2);
|
144
|
+
for (var i = 0; i < result.length; i++)
|
145
|
+
result[i] = this.getObject(i);
|
146
|
+
return result;
|
147
|
+
},
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Jax.World#pickIndex(x, y) -> Number | undefined
|
151
|
+
* - x (Number): the screen X coordinate to pick at
|
152
|
+
* - y (Number): the screen Y coordinate to pick at
|
153
|
+
*
|
154
|
+
* Picks the visible object at the specified position and returns its index as used by
|
155
|
+
* +Jax.World#getObject+. If no object is visible at the given position, the special value
|
156
|
+
* +undefined+ is returned.
|
157
|
+
**/
|
158
|
+
pickIndex: function(x, y) {
|
159
|
+
this._pick_ary = this._pick_ary || new Array();
|
160
|
+
return this.pickRegionalIndices(x, y, x+1, y+1, this._pick_ary)[0];
|
161
|
+
},
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Jax.World#pick(x, y) -> Jax.Model | undefined
|
165
|
+
* - x (Number): the screen X coordinate to pick at
|
166
|
+
* - y (Number): the screen Y coordinate to pick at
|
167
|
+
*
|
168
|
+
* Picks the visible object at the specified position and returns it. If no object is visible
|
169
|
+
* at the given position, the special value +undefined+ is returned.
|
170
|
+
**/
|
171
|
+
pick: function(x, y) {
|
172
|
+
var index = this.pickIndex(x, y);
|
173
|
+
if (index != undefined)
|
174
|
+
return this.getObject(index);
|
175
|
+
return index;
|
176
|
+
},
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Jax.World#countObjects() -> Number
|
180
|
+
* Returns the number of objects currently registered with this World.
|
181
|
+
**/
|
35
182
|
countObjects: function() {
|
36
183
|
return this.objects.length;
|
37
184
|
},
|
@@ -63,16 +210,16 @@ Jax.World = (function() {
|
|
63
210
|
|
64
211
|
getShadowCasters: function() { return this.shadow_casters; },
|
65
212
|
|
66
|
-
render: function() {
|
213
|
+
render: function(options) {
|
67
214
|
var i;
|
68
215
|
|
69
216
|
/* this.current_pass is used by the material */
|
70
217
|
|
71
218
|
this.context.current_pass = Jax.Scene.AMBIENT_PASS;
|
72
219
|
this.context.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
73
|
-
var unlit = {unlit:true};
|
220
|
+
var unlit = Jax.Util.normalizeOptions(options, {unlit:true});
|
74
221
|
|
75
|
-
if (this.lighting.isEnabled()) {
|
222
|
+
if (this.lighting.isEnabled() && (!unlit.material || unlit.material.supportsLighting())) {
|
76
223
|
/* ambient pass */
|
77
224
|
/*
|
78
225
|
So.... I see a legit need for an ambient pass for A) unlit objects and B)
|
@@ -81,8 +228,10 @@ Jax.World = (function() {
|
|
81
228
|
lighting take care of (ambient + diffuse + specular) all at once?
|
82
229
|
*/
|
83
230
|
for (i = 0; i < this.objects.length; i++)
|
84
|
-
if (!this.objects[i].lit)
|
231
|
+
if (!this.objects[i].lit) {
|
232
|
+
unlit.model_index = i;
|
85
233
|
this.objects[i].render(this.context, unlit);
|
234
|
+
}
|
86
235
|
// this.lighting.ambient(this.context, this.objects);
|
87
236
|
|
88
237
|
/* shadowgen pass */
|
@@ -94,10 +243,12 @@ Jax.World = (function() {
|
|
94
243
|
|
95
244
|
/* illumination pass */
|
96
245
|
this.context.current_pass = Jax.Scene.ILLUMINATION_PASS;
|
97
|
-
this.lighting.illuminate(this.context, this.objects);
|
246
|
+
this.lighting.illuminate(this.context, this.objects, options);
|
98
247
|
} else {
|
99
|
-
for (i = 0; i < this.objects.length; i++)
|
248
|
+
for (i = 0; i < this.objects.length; i++) {
|
249
|
+
unlit.model_index = i;
|
100
250
|
this.objects[i].render(this.context, unlit);
|
251
|
+
}
|
101
252
|
}
|
102
253
|
},
|
103
254
|
|