jax 2.0.5 → 2.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,27 @@
1
+ * 2.0.6 *
2
+
3
+ * Resolved issue #30: `Jax.Framebuffer#getTexture(context, index)` now returns texture
4
+ with index 0 if index was not given.
5
+
6
+ * Resolved issue #43: Plugin models appear after app models in load order.
7
+
8
+ * Minor improvements to `Jax.Framebuffer`
9
+
10
+ * `Jax.Texture` data type can now be specified, for example, in apps which make use of
11
+ the OES_texture_float extension
12
+
13
+ * Resolved issue #38: `Jax.RouteSet` now underscores CamelCase routes.
14
+
15
+ * `Jax.World#addLightSource()` now returns the light source that was added, just like
16
+ `Jax.World#addObject()` returns the object that was added.
17
+
18
+ * Resolved issue #46: Render errors when shadows are disabled, but shadowmapping is not
19
+
20
+ * Resolved issue #47: Removing an object from the scene causes infinite recursion in light
21
+ manager
22
+
23
+
24
+
1
25
  * 2.0.5 *
2
26
 
3
27
  * Setting `shadowcaster` to `false` for a light source now has the expected result: it
@@ -0,0 +1,9 @@
1
+ @rails
2
+ Feature: Models
3
+
4
+ Scenario: Plugin models loaded first
5
+ Given file "app/assets/jax/models/person.js" contains "__feature_model_person"
6
+ And file "vendor/plugins/mine/app/assets/jax/models/human.js" contains "__feature_model_human"
7
+ When I visit "/assets/jax/application.js"
8
+ # Then show me the response
9
+ Then "__feature_model_human" should come before "__feature_model_person"
@@ -11,3 +11,7 @@ end
11
11
  Then /^the response should contain:$/ do |text|
12
12
  (!!page.body.to_s[text]).should be_true
13
13
  end
14
+
15
+ Then /^"([^"]*)" should come before "([^"]*)"$/ do |first, second|
16
+ page.body.to_s.index(first).should be_less_than(page.body.to_s.index(second))
17
+ end
@@ -0,0 +1,26 @@
1
+ module Matchers
2
+ class NumericMatcher
3
+ def initialize(expected, operation)
4
+ @expected, @operation = expected, operation
5
+ end
6
+
7
+ def matches?(actual)
8
+ @actual = actual
9
+ @actual.respond_to?(@operation) ? actual.send(@operation, @expected) : false
10
+ end
11
+
12
+ def failure_message
13
+ "Expected #{@actual.inspect} #{@operation} #{@expected.inspect}"
14
+ end
15
+
16
+ def negative_failure_message
17
+ "Expected #{@actual.inspect} not #{@operation} #{@expected.inspect}"
18
+ end
19
+ end
20
+
21
+ def be_less_than(other)
22
+ Matchers::NumericMatcher.new other, :<
23
+ end
24
+ end
25
+
26
+ World(Matchers)
@@ -18,6 +18,53 @@ Jax.Util = {
18
18
  "a string representing a material in the Jax material registry");
19
19
  },
20
20
 
21
+ gsub: function(source, pattern, replacement) {
22
+ var match, result, submatch, _replacement;
23
+ if (!((pattern != null) && (replacement != null))) {
24
+ return source;
25
+ }
26
+ result = '';
27
+ while (source.length > 0) {
28
+ if ((match = source.match(pattern))) {
29
+ // handle \1, \2, etc in replacement string
30
+ _replacement = replacement;
31
+ while (submatch = _replacement.match(/\\(\d+)/)) {
32
+ _replacement = _replacement.replace('\\'+submatch[1], match[submatch[1]]);
33
+ }
34
+
35
+ result += source.slice(0, match.index);
36
+ result += _replacement;
37
+ source = source.slice(match.index + match[0].length);
38
+ } else {
39
+ result += source;
40
+ source = '';
41
+ }
42
+ }
43
+ return result;
44
+ },
45
+
46
+ /**
47
+ * Jax.Util.underscore(word) -> String
48
+ * word (String): a String to be converted to underscore.
49
+ *
50
+ * Takes a String, which may be in CamelCase format, and returns
51
+ * the same string converted to underscored_format. Examples:
52
+ *
53
+ * "HelloWorld" => "hello_world"
54
+ * "Hello_World" => "hello_world"
55
+ * "Hello" => "hello"
56
+ *
57
+ **/
58
+ underscore: function(word) {
59
+ word = Jax.Util.gsub(word, /::/, "\/");
60
+ word = Jax.Util.gsub(word, /([A-Z]+)([A-Z][a-z])/,'\\1_\\2');
61
+ word = Jax.Util.gsub(word, /([a-z\d])([A-Z])/,'\\1_\\2');
62
+
63
+ while (word.indexOf('-') != -1) word = word.replace('-', '_');
64
+
65
+ return word.toLowerCase();
66
+ },
67
+
21
68
  /**
22
69
  * Jax.Util.decodePickingColor(red, green, blue, alpha) -> Number
23
70
  *
@@ -282,6 +282,19 @@
282
282
  for (var id in resources)
283
283
  if (this.resources[id]) throw new Error("Duplicate resource ID: "+id);
284
284
  else this.resources[id] = resources[id];
285
+ },
286
+
287
+ /**
288
+ * Jax.Model.removeAllResources() -> undefined
289
+ *
290
+ * Removes all resources from this model. Existing instances won't be
291
+ * affected, but #find() will fail for any resource not re-added using
292
+ * #addResources().
293
+ *
294
+ * Useful for managing test cases, so that they can run in isolation.
295
+ **/
296
+ removeAllResources: function() {
297
+ this.resources = {};
285
298
  }
286
299
  };
287
300
 
@@ -66,7 +66,7 @@ Jax.RouteSet = (function() {
66
66
  var parts = path.split(/\//);
67
67
  var controller_name = parts[0];
68
68
 
69
- this._map[controller_name.toLowerCase()] = controller;
69
+ this._map[Jax.Util.underscore(controller_name)] = controller;
70
70
 
71
71
  if (!Jax.views.exists(controller_name+"/index"))
72
72
  Jax.views.push(controller_name+"/index", function() {
@@ -107,7 +107,7 @@ Jax.RouteSet = (function() {
107
107
  var controller_name = parts[0];
108
108
  var action_name = parts[1] || "index";
109
109
 
110
- var controller_class = this._map[controller_name.toLowerCase()];
110
+ var controller_class = this._map[Jax.Util.underscore(controller_name)];
111
111
  if (!controller_class || !controller_class.prototype)
112
112
  throw new Error("Route not recognized: '"+path+"' (controller not found)");
113
113
 
@@ -47,11 +47,12 @@ Jax.Framebuffer = (function() {
47
47
  format:GL_RGBA,
48
48
  width:width,
49
49
  height:height,
50
- min_filter:GL_LINEAR,
51
- mag_filter:GL_LINEAR,
52
- wrap_s:GL_CLAMP_TO_EDGE,
53
- wrap_t:GL_CLAMP_TO_EDGE,
54
- generate_mipmap:false
50
+ min_filter:self.options.min_filter,
51
+ mag_filter:self.options.mag_filter,
52
+ wrap_s:self.options.wrap_s,
53
+ wrap_t:self.options.wrap_t,
54
+ generate_mipmap:self.options.generate_mipmap,
55
+ data_type: self.options.data_type
55
56
  };
56
57
  if (typeof(format) != "number") { texture_options = Jax.Util.normalizeOptions(format, texture_options); }
57
58
  else { texture_options.format = format; }
@@ -66,7 +67,13 @@ Jax.Framebuffer = (function() {
66
67
  attachment++;
67
68
  }
68
69
 
69
- checkStatus(context, self);
70
+ try {
71
+ checkStatus(context, self);
72
+ } catch(e) {
73
+ // build failed, release all objects so user can (maybe) change options and try again
74
+ self.dispose(context);
75
+ throw e;
76
+ }
70
77
  }
71
78
 
72
79
  function checkStatus(context, self) {
@@ -101,6 +108,40 @@ Jax.Framebuffer = (function() {
101
108
  }
102
109
 
103
110
  return Jax.Class.create({
111
+ dispose: function(context) {
112
+ if (!this.handles) return;
113
+
114
+ var handle = this.getHandle(context);
115
+ if (!handle) return;
116
+
117
+ // handle.stencilbuffer, handle.depthbuffer, handle.depthstencilbuffer
118
+ if (handle.stencilbuffer) {
119
+ context.glDeleteRenderbuffer(handle.stencilbuffer);
120
+ delete handle.stencilbuffer;
121
+ }
122
+ if (handle.depthbuffer) {
123
+ context.glDeleteRenderbuffer(handle.depthbuffer);
124
+ delete handle.depthbuffer;
125
+ }
126
+ if (handle.depthstencilbuffer) {
127
+ context.glDeleteRenderbuffer(handle.depthstencilbuffer);
128
+ delete handle.depthstencilbuffer;
129
+ }
130
+
131
+ // texture attachments
132
+ if (handle.textures) {
133
+ while (handle.textures.length > 0) {
134
+ handle.textures[0].dispose(context);
135
+ handle.textures.splice(0, 1);
136
+ }
137
+ delete handle.textures;
138
+ }
139
+
140
+ // finally, delete the framebuffer itself
141
+ context.glDeleteFramebuffer(handle);
142
+ this.setHandle(context, null);
143
+ },
144
+
104
145
  /**
105
146
  * new Jax.Framebuffer([options])
106
147
  * - options (Object): a generic object containing the following optional properties:
@@ -120,6 +161,15 @@ Jax.Framebuffer = (function() {
120
161
  * framebuffer must have the same width. Defaults to 512.
121
162
  * * height: the height of the render and color buffers. All render and color buffers for a given
122
163
  * framebuffer must have the same height. Defaults to 512.
164
+ *
165
+ * The following options may also be present. If they are, they will be passed into Jax.Texture:
166
+ *
167
+ * * data_type: defaults to GL_UNSIGNED_BYTE
168
+ * * min_filter: defaults to GL_LINEAR
169
+ * * mag_filter: defaults to GL_LINEAR
170
+ * * wrap_s: defaults to GL_CLAMP_TO_EDGE
171
+ * * wrap_t: defaults to GL_CLAMP_TO_EDGE
172
+ * * generate_mipmap: defaults to false
123
173
  *
124
174
  **/
125
175
  initialize: function(options) {
@@ -127,7 +177,13 @@ Jax.Framebuffer = (function() {
127
177
  depth: false,
128
178
  stencil: false,
129
179
  width:512,
130
- height:512
180
+ height:512,
181
+ data_type: GL_UNSIGNED_BYTE,
182
+ min_filter: GL_LINEAR,
183
+ mag_filter: GL_LINEAR,
184
+ wrap_s: GL_CLAMP_TO_EDGE,
185
+ wrap_t: GL_CLAMP_TO_EDGE,
186
+ generate_mipmap: false
131
187
  };
132
188
  if (!(options && (options.color || options.colors))) defaults.colors = [GL_RGBA];
133
189
 
@@ -151,12 +207,12 @@ Jax.Framebuffer = (function() {
151
207
  * For cube map framebuffers only, this will bind the specified cube map face to its color buffer position.
152
208
  * The faceEnum can be any of the following face enums:
153
209
  *
154
- * 0: GL_TEXTURE_CUBE_MAP_POSITIVE_X
155
- * 1: GL_TEXTURE_CUBE_MAP_NEGATIVE_X
156
- * 2: GL_TEXTURE_CUBE_MAP_POSITIVE_Y
157
- * 3: GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
158
- * 4: GL_TEXTURE_CUBE_MAP_POSITIVE_Z
159
- * 5: GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
210
+ * 0 or GL_TEXTURE_CUBE_MAP_POSITIVE_X
211
+ * 1 or GL_TEXTURE_CUBE_MAP_NEGATIVE_X
212
+ * 2 or GL_TEXTURE_CUBE_MAP_POSITIVE_Y
213
+ * 3 or GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
214
+ * 4 or GL_TEXTURE_CUBE_MAP_POSITIVE_Z
215
+ * 5 or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
160
216
  *
161
217
  * Example:
162
218
  *
@@ -168,8 +224,7 @@ Jax.Framebuffer = (function() {
168
224
  * });
169
225
  **/
170
226
  bindCubeFace: function(context, texIndex, faceEnum, callback) {
171
- if (!this.getHandle(context)) build(context, this);
172
- var texture = this.getHandle(context).textures[texIndex];
227
+ var texture = this.getTexture(context, texIndex);
173
228
  if (texture.options.target != GL_TEXTURE_CUBE_MAP)
174
229
  throw new Error("Texture at index "+texIndex+" is not a cube map!");
175
230
 
@@ -198,7 +253,7 @@ Jax.Framebuffer = (function() {
198
253
  *
199
254
  **/
200
255
  bind: function(context, callback) {
201
- if (!this.getHandle(context)) build(context, this);
256
+ this.validate(context);
202
257
  context.glBindFramebuffer(GL_FRAMEBUFFER, this.getHandle(context));
203
258
 
204
259
  if (callback) {
@@ -209,6 +264,33 @@ Jax.Framebuffer = (function() {
209
264
  return this;
210
265
  },
211
266
 
267
+ /**
268
+ * Jax.Framebuffer#validate(context) -> Jax.Framebuffer
269
+ * - context (Jax.Context): the context to validate this framebuffer for
270
+ *
271
+ * If this framebuffer's underlying WebGL counterpart has not yet been
272
+ * created, this method will do so. This method may raise errors per the
273
+ * WebGL specification if the framebuffer is not complete or compatible
274
+ * with the client hardware.
275
+ *
276
+ * After successful construction, or if the framebuffer has already been
277
+ * built, this framebuffer is returned.
278
+ **/
279
+ validate: function(context) {
280
+ if (!this.getHandle(context)) build(context, this);
281
+ return this;
282
+ },
283
+
284
+ /**
285
+ * Jax.Framebuffer#countTextures(context) -> Jax.Framebuffer
286
+ * - context (Jax.Context): a WebGL context
287
+ *
288
+ * Returns the number of textures associated with this framebuffer.
289
+ **/
290
+ countTextures: function(context) {
291
+ return this.validate().getHandle(context).textures.length;
292
+ },
293
+
212
294
  /**
213
295
  * Jax.Framebuffer#unbind(context) -> Jax.Framebuffer
214
296
  * - context (Jax.Context): the context to bind this framebuffer to
@@ -245,7 +327,8 @@ Jax.Framebuffer = (function() {
245
327
  * first texture available is returned.
246
328
  **/
247
329
  getTexture: function(context, index) {
248
- return this.getHandle(context) && this.getHandle(context).textures[index];
330
+ this.validate(context);
331
+ return this.getHandle(context).textures[index || 0];
249
332
  },
250
333
 
251
334
  /**
@@ -311,6 +394,12 @@ Jax.Framebuffer = (function() {
311
394
  *
312
395
  * Returns this instance of Jax.Framebuffer.
313
396
  **/
314
- setHandle: function(context, handle) { this.handles[context.id] = handle; return this; }
397
+ setHandle: function(context, handle) {
398
+ if (handle)
399
+ this.handles[context.id] = handle;
400
+ else if (this.handles[context.id])
401
+ delete this.handles[context.id];
402
+ return this;
403
+ }
315
404
  });
316
405
  })();
@@ -17,6 +17,7 @@ Jax.Scene.LightManager = (function() {
17
17
  },
18
18
 
19
19
  removeObject: function(obj) {
20
+ // if obj is a number, remove that index
20
21
  if (this.objects[obj]) {
21
22
  var o = this.objects[obj];
22
23
  this.objects.splice(obj, 1);
@@ -26,9 +27,10 @@ Jax.Scene.LightManager = (function() {
26
27
  this.recalculateBoundingRadius();
27
28
  return o;
28
29
  }
30
+ // ...if it's not, find its index and remove it.
29
31
  for (var i = 0; i < this.objects.length; i++)
30
32
  if (this.objects[i] == obj)
31
- return this.removeObject(obj);
33
+ return this.removeObject(i);
32
34
  },
33
35
 
34
36
  getShadowCasters: function() {
@@ -80,10 +80,10 @@ Jax.Texture = (function() {
80
80
 
81
81
  function ti2d(glEnum) {
82
82
  try {
83
- context.glTexImage2D(glEnum, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, null);
83
+ context.glTexImage2D(glEnum, 0, format, width, height, 0, format, data_type, null);
84
84
  } catch (e) {
85
85
  var tex = new Uint8Array(width*height*Jax.Util.sizeofFormat(format));
86
- context.glTexImage2D(glEnum, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, tex);
86
+ context.glTexImage2D(glEnum, 0, format, width, height, 0, format, data_type, tex);
87
87
  }
88
88
  }
89
89
 
@@ -391,7 +391,7 @@ Jax.Texture = (function() {
391
391
  * to dispose the texture for all contexts except for one).
392
392
  **/
393
393
  dispose: function(context) {
394
- context.glDeleteTexture(getHandle(context));
394
+ context.glDeleteTexture(this.getHandle(context));
395
395
  delete this.handles[context.id];
396
396
  },
397
397
 
@@ -31,7 +31,7 @@ Jax.World = (function() {
31
31
  *
32
32
  * Adds the light to the world and then returns the light itself unchanged.
33
33
  **/
34
- addLightSource: function(light) { this.lighting.add(light); },
34
+ addLightSource: function(light) { this.lighting.add(light); return light; },
35
35
 
36
36
  /**
37
37
  * Jax.World#addObject(object) -> Jax.Model
@@ -4,21 +4,26 @@ Jax.Material.ShadowMap = Jax.Class.create(Jax.Material, {
4
4
  },
5
5
 
6
6
  setVariables: function(context, mesh, options, vars) {
7
+ var light = context.world.lighting.getLight();
8
+ var shadowmap_enabled = light.isShadowMapEnabled();
9
+
7
10
  vars.set({
8
11
  DP_SHADOW_NEAR: 0.1, //c.world.lighting.getLight().getDPShadowNear() || 0.1;}},
9
12
  DP_SHADOW_FAR: 500,//c.world.lighting.getLight().getDPShadowFar() || 500;}},
10
13
 
11
14
  SHADOWMAP_PCF_ENABLED: false,
12
- SHADOWMAP_MATRIX: context.world.lighting.getLight().getShadowMatrix(),
13
- SHADOWMAP_ENABLED: context.world.lighting.getLight().isShadowMapEnabled()
15
+ SHADOWMAP_ENABLED: shadowmap_enabled
14
16
  });
15
17
 
16
- var light = context.world.lighting.getLight(), front, back;
18
+ if (shadowmap_enabled) {
19
+ vars.set({SHADOWMAP_MATRIX: light.getShadowMatrix()});
20
+ var front, back;
17
21
 
18
- front = light.getShadowMapTextures(context)[0];
19
- back = light.getShadowMapTextures(context)[1];
20
-
21
- if (front) vars.texture('SHADOWMAP0', front, context);
22
- if (back) vars.texture('SHADOWMAP1', back, context);
22
+ front = light.getShadowMapTextures(context)[0];
23
+ back = light.getShadowMapTextures(context)[1];
24
+
25
+ if (front) vars.texture('SHADOWMAP0', front, context);
26
+ if (back) vars.texture('SHADOWMAP1', back, context);
27
+ }
23
28
  }
24
29
  });
@@ -25,6 +25,8 @@ module Jax
25
25
  end
26
26
 
27
27
  def process_require_everything_matching_directive(subpath)
28
+ # TODO this method is very dirty. Make it prettier.
29
+
28
30
  # depend on any base subpath directories that may exist
29
31
  # this should pick up any new shaders as they are added to app
30
32
  context.environment.paths.each do |base_path|
@@ -33,7 +35,6 @@ module Jax
33
35
  end
34
36
 
35
37
  files = []
36
- # context.environment.each_logical_path do |path|
37
38
  context.environment.each_file do |path|
38
39
  # skip all.js and skip manifest.yml
39
40
  path = path.to_s
@@ -42,12 +43,20 @@ module Jax
42
43
  logical_path = attrs.logical_path
43
44
  if logical_path[/^#{Regexp::escape subpath}/]
44
45
  # skip if logical path has already been processed
45
- next if files.include?(logical_path)
46
- files << logical_path
47
- path = context.resolve(logical_path).to_s
48
- process_require_directive path
46
+ ary = [ path, logical_path ]
47
+ files << ary unless files.include?(ary)
49
48
  end
50
49
  end
50
+
51
+ # order files so they appear in order: plugin files, then app files.
52
+ plugins_path = 'vendor/plugins'
53
+ numerize = proc { |a| a[plugins_path] ? 0 : 1 }
54
+ files.sort! { |a, b| numerize.call(a[0]) <=> numerize.call(b[0]) }
55
+
56
+ # require files, now that they are in order
57
+ files.each do |(path, logical_path)|
58
+ process_require_directive path
59
+ end
51
60
  end
52
61
  end
53
62
  end
data/lib/jax/version.rb CHANGED
@@ -2,7 +2,7 @@ module Jax
2
2
  module Version
3
3
  MAJOR = 2
4
4
  MINOR = 0
5
- PATCH = 5
5
+ PATCH = 6
6
6
  BUILD = nil
7
7
  STRING = BUILD ? [MAJOR, MINOR, PATCH, BUILD].join(".") : [MAJOR, MINOR, PATCH].join(".")
8
8
  end
@@ -1,6 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'jax:scaffold' do
4
+ with_args "test_breaker" do
5
+ it "should camelize model name" do
6
+ subject.should generate("app/assets/jax/models/test_breaker.js.coffee") { |f|
7
+ f.should =~ /TestBreaker/
8
+ }
9
+ end
10
+
11
+ it "should camelize controller name" do
12
+ subject.should generate("app/assets/jax/controllers/test_breaker_controller.js.coffee") { |f|
13
+ f.should =~ /TestBreaker/
14
+ }
15
+ end
16
+
17
+ it "should camelize names in controller spec" do
18
+ subject.should generate("spec/javascripts/jax/controllers/test_breaker_controller_spec.js.coffee") { |f|
19
+ f.should =~ /describe "TestBreakerController"/
20
+ f.should =~ /redirectTo "test_breaker/
21
+ }
22
+ end
23
+ end
24
+
4
25
  with_args "dungeon" do
5
26
  it "should generate dungeon model" do
6
27
  subject.should generate("app/assets/jax/models/dungeon.js.coffee")
@@ -1,4 +1,15 @@
1
1
  describe("Jax.Util", function() {
2
+ describe("underscore", function() {
3
+ it("should work", function() {
4
+ expect(Jax.Util.underscore("Product")).toEqual("product");
5
+ expect(Jax.Util.underscore("SpecialGuest")).toEqual("special_guest");
6
+ expect(Jax.Util.underscore("ApplicationController")).toEqual("application_controller");
7
+ expect(Jax.Util.underscore("Area51Controller")).toEqual("area51_controller");
8
+ expect(Jax.Util.underscore("HTMLTidy")).toEqual('html_tidy');
9
+ expect(Jax.Util.underscore('HTMLTidyGenerator')).toEqual('html_tidy_generator');
10
+ });
11
+ });
12
+
2
13
  describe("vectorize", function() {
3
14
  var data;
4
15
 
@@ -5,6 +5,17 @@ describe("Jax.RouteSet", function() {
5
5
 
6
6
  beforeEach(function() { map = Jax.routes; map.clear(); });
7
7
 
8
+ describe("when a CamelCase controller name is given", function() {
9
+ beforeEach(function() {
10
+ controller_class = Jax.Controller.create("TestBreaker", {index: function() { }});
11
+ });
12
+
13
+ it("should recognize underscored route names", function() {
14
+ var route = map.recognizeRoute("test_breaker");
15
+ expect(route.controller).toEqual(controller_class);
16
+ });
17
+ });
18
+
8
19
  describe("when a controller name is given during controller definition", function() {
9
20
  beforeEach(function() {
10
21
  controller_class = Jax.Controller.create("welcome", {index: function() { }});
@@ -1,6 +1,13 @@
1
1
  describe("Framebuffer", function() {
2
2
  var buf;
3
3
 
4
+ it("should return the first texture if index not given (issue #30)", function() {
5
+ // https://github.com/sinisterchipmunk/jax/issues/30
6
+ buf = new Jax.Framebuffer();
7
+ expect(buf.getTexture(SPEC_CONTEXT)).toBeTruthy();
8
+ expect(buf.getTexture(SPEC_CONTEXT)).toBe(buf.getTexture(SPEC_CONTEXT, 0));
9
+ });
10
+
4
11
  describe("with no attachments", function() {
5
12
  beforeEach(function() { buf = new Jax.Framebuffer(); });
6
13
 
@@ -3,11 +3,12 @@ describe("LightManager", function() {
3
3
 
4
4
  describe("when a light resource is defined with shadowcasting disabled", function() {
5
5
  beforeEach(function() {
6
+ LightSource.removeAllResources();
6
7
  LightSource.addResources({"__test_shadowcast_disabled":{
7
8
  shadowcaster:!1,enabled:!0,
8
9
  position:{x:-20,y:0,z:0},
9
- type:"POINT_LIGHT",
10
- attenuation:{constant:0,linear:1,quadratic:0},
10
+ type:"DIRECTIONAL_LIGHT",
11
+ attenuation:{constant:1,linear:0,quadratic:0},
11
12
  color:{ambient:{red:.15,green:.15,blue:.15,alpha:1},
12
13
  diffuse:{red:.33,green:.1843137254901961,blue:.12679738562091503,alpha:1},
13
14
  specular:{red:0,green:0,blue:0,alpha:0}}}});
@@ -16,6 +17,17 @@ describe("LightManager", function() {
16
17
  it("should not be a shadow caster", function() {
17
18
  expect(LightSource.find("__test_shadowcast_disabled").isShadowCaster()).toBeFalsy();
18
19
  });
20
+
21
+ it("should not cause render errors with materials that have shadow mapping enabled", function() {
22
+ var model = new Jax.Model({position:[-20,0,0], lit: true, shadow_caster: false, mesh: new Jax.Mesh.Cube()});
23
+ model.mesh.lit = true;
24
+ model.mesh.default_material = new Jax.Material({ layers:[ {type:"Lighting"} ] });
25
+ model.mesh.default_material.addLayer(new Jax.Material.ShadowMap());
26
+
27
+ SPEC_CONTEXT.world.addLightSource("__test_shadowcast_disabled");
28
+ SPEC_CONTEXT.world.addObject(model);
29
+ SPEC_CONTEXT.world.render();
30
+ });
19
31
  });
20
32
 
21
33
  describe("when more than 1 light source is active", function() {
@@ -66,7 +78,24 @@ describe("LightManager", function() {
66
78
  });
67
79
 
68
80
  describe("by default", function() {
81
+ var model;
69
82
  beforeEach(function() { mgr = new Jax.Scene.LightManager(); });
83
+
84
+ describe("after adding an object", function() {
85
+ beforeEach(function() { mgr.addObject(model = new Jax.Model({shadow_caster:true})); });
86
+
87
+ it("should be in the shadowcasters list", function() {
88
+ expect(mgr.getShadowCasters().length).toEqual(1);
89
+ });
90
+
91
+ describe("removing the object", function() {
92
+ beforeEach(function() { mgr.removeObject(model); });
93
+
94
+ it("should be gone", function() {
95
+ expect(mgr.getShadowCasters().length).toEqual(0);
96
+ });
97
+ });
98
+ });
70
99
 
71
100
  it("should not be enabled", function() {
72
101
  expect(mgr.isEnabled()).toBeFalsy();
@@ -14,6 +14,16 @@ describe("Jax.World", function() {
14
14
  world = SPEC_CONTEXT.world;
15
15
  });
16
16
 
17
+ it("should return objects added to world", function() {
18
+ var obj = new (Jax.Model.create({one:1}))();
19
+ expect(world.addObject(obj)).toBe(obj);
20
+ });
21
+
22
+ it("should return light sources added to world", function() {
23
+ var lite = new Jax.Scene.LightSource();
24
+ expect(world.addLightSource(lite)).toBe(lite);
25
+ });
26
+
17
27
  describe("picking", function() {
18
28
  var at, ofront, otopleft, otopright, obottomleft, obottomright, mesh;
19
29
 
@@ -1,51 +1,56 @@
1
- var jsdom = require('jsdom'),
2
- doc = jsdom.jsdom('<html><body></body></html>');
1
+ // This file's name matches the regexp used to load Jasmine helpers,
2
+ // so we need to code a special case to avoid causing errors.
3
+
4
+ if (typeof(require) != 'undefined') {
5
+ var jsdom = require('jsdom'),
6
+ doc = jsdom.jsdom('<html><body></body></html>');
3
7
 
4
- global.document = doc;
5
- global.window = doc.createWindow();
8
+ global.document = doc;
9
+ global.window = doc.createWindow();
6
10
 
7
- global.ENV = global.ENV || process.env;
8
- global.ENV['SILENCED'] = '1';
11
+ global.ENV = global.ENV || process.env;
12
+ global.ENV['SILENCED'] = '1';
9
13
 
10
- /* TODO remove this when node-canvas supports webgl */
11
- var canvas = document._elementBuilders.canvas;
12
- document._elementBuilders.canvas = function(document, tagName) {
13
- var element = canvas.call(this, document, tagName);
14
- var getContext = element.getContext;
14
+ /* TODO remove this when node-canvas supports webgl */
15
+ var canvas = document._elementBuilders.canvas;
16
+ document._elementBuilders.canvas = function(document, tagName) {
17
+ var element = canvas.call(this, document, tagName);
18
+ var getContext = element.getContext;
15
19
 
16
- element.getContext = function(name) {
17
- if (name == "webgl" || name == "experimental-webgl") {
18
- return require("./node/mocks/webgl.js").context();
19
- } else {
20
- return getContext.call(this, name);
21
- }
22
- };
20
+ element.getContext = function(name) {
21
+ if (name == "webgl" || name == "experimental-webgl") {
22
+ return require("./node/mocks/webgl.js").context();
23
+ } else {
24
+ return getContext.call(this, name);
25
+ }
26
+ };
23
27
 
24
- element.width = element.height = 100;
28
+ element.width = element.height = 100;
25
29
 
26
- return element;
27
- };
30
+ return element;
31
+ };
28
32
 
29
- // mock navigator
30
- global.navigator = {
31
- userAgent: 'firefox'
32
- };
33
+ // mock navigator
34
+ global.navigator = {
35
+ userAgent: 'firefox'
36
+ };
33
37
 
34
- global.Image = global.Image || function() {
35
- var src;
38
+ global.Image = global.Image || function() {
39
+ var src;
36
40
 
37
- this.__defineGetter__("src", function() {
38
- return src;
39
- });
41
+ this.__defineGetter__("src", function() {
42
+ return src;
43
+ });
40
44
 
41
- this.__defineSetter__("src", function(s) {
42
- src = s;
43
- if (this.onload) this.onload();
44
- return src;
45
- });
46
- };
45
+ this.__defineSetter__("src", function(s) {
46
+ src = s;
47
+ if (this.onload) this.onload();
48
+ return src;
49
+ });
50
+ };
47
51
 
48
- global.Jax = require("../../tmp/jax.js").Jax;
52
+ global.Jax = require("../../tmp/jax.js").Jax;
49
53
 
50
- require("./helpers/jax_spec_environment_helper.js");
51
- setupJaxSpecContext();
54
+ require("./helpers/jax_spec_environment_helper.js");
55
+ setupJaxSpecContext();
56
+ } // if (typeof(require) != 'undefined')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jax
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 2.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-02 00:00:00.000000000Z
12
+ date: 2011-12-17 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &2153721020 !ruby/object:Gem::Requirement
16
+ requirement: &2153610220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153721020
24
+ version_requirements: *2153610220
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: jquery-rails
27
- requirement: &2153720420 !ruby/object:Gem::Requirement
27
+ requirement: &2153609620 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.13
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153720420
35
+ version_requirements: *2153609620
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jasmine
38
- requirement: &2153719960 !ruby/object:Gem::Requirement
38
+ requirement: &2153609040 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.2.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2153719960
46
+ version_requirements: *2153609040
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rest-client
49
- requirement: &2153719480 !ruby/object:Gem::Requirement
49
+ requirement: &2153608480 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.6.3
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2153719480
57
+ version_requirements: *2153608480
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rspec
60
- requirement: &2153718920 !ruby/object:Gem::Requirement
60
+ requirement: &2153593920 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 2.6.0
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2153718920
68
+ version_requirements: *2153593920
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: coffee-rails
71
- requirement: &2153718340 !ruby/object:Gem::Requirement
71
+ requirement: &2153593380 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 3.1.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2153718340
79
+ version_requirements: *2153593380
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: coderay
82
- requirement: &2153717740 !ruby/object:Gem::Requirement
82
+ requirement: &2153592720 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 0.9.7
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2153717740
90
+ version_requirements: *2153592720
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: sqlite3
93
- requirement: &2153717260 !ruby/object:Gem::Requirement
93
+ requirement: &2153592180 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 1.3.4
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *2153717260
101
+ version_requirements: *2153592180
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: sass-rails
104
- requirement: &2153716680 !ruby/object:Gem::Requirement
104
+ requirement: &2153591580 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 3.1.0
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *2153716680
112
+ version_requirements: *2153591580
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: uglifier
115
- requirement: &2153716180 !ruby/object:Gem::Requirement
115
+ requirement: &2153591000 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: 1.0.2
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *2153716180
123
+ version_requirements: *2153591000
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: genspec
126
- requirement: &2153715720 !ruby/object:Gem::Requirement
126
+ requirement: &2153590400 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ~>
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: 0.2.3
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *2153715720
134
+ version_requirements: *2153590400
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: selenium-webdriver
137
- requirement: &2153715120 !ruby/object:Gem::Requirement
137
+ requirement: &2153589820 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ~>
@@ -142,10 +142,10 @@ dependencies:
142
142
  version: 2.9.1
143
143
  type: :development
144
144
  prerelease: false
145
- version_requirements: *2153715120
145
+ version_requirements: *2153589820
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: fakeweb
148
- requirement: &2153714620 !ruby/object:Gem::Requirement
148
+ requirement: &2153589220 !ruby/object:Gem::Requirement
149
149
  none: false
150
150
  requirements:
151
151
  - - ~>
@@ -153,10 +153,10 @@ dependencies:
153
153
  version: 1.3.0
154
154
  type: :development
155
155
  prerelease: false
156
- version_requirements: *2153714620
156
+ version_requirements: *2153589220
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: ansi
159
- requirement: &2153714240 !ruby/object:Gem::Requirement
159
+ requirement: &2153588720 !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements:
162
162
  - - ! '>='
@@ -164,10 +164,10 @@ dependencies:
164
164
  version: '0'
165
165
  type: :development
166
166
  prerelease: false
167
- version_requirements: *2153714240
167
+ version_requirements: *2153588720
168
168
  - !ruby/object:Gem::Dependency
169
169
  name: cucumber-rails
170
- requirement: &2153713680 !ruby/object:Gem::Requirement
170
+ requirement: &2153588060 !ruby/object:Gem::Requirement
171
171
  none: false
172
172
  requirements:
173
173
  - - ~>
@@ -175,10 +175,10 @@ dependencies:
175
175
  version: 1.0.2
176
176
  type: :development
177
177
  prerelease: false
178
- version_requirements: *2153713680
178
+ version_requirements: *2153588060
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: RedCloth
181
- requirement: &2153713040 !ruby/object:Gem::Requirement
181
+ requirement: &2153587440 !ruby/object:Gem::Requirement
182
182
  none: false
183
183
  requirements:
184
184
  - - ~>
@@ -186,10 +186,10 @@ dependencies:
186
186
  version: '4.2'
187
187
  type: :development
188
188
  prerelease: false
189
- version_requirements: *2153713040
189
+ version_requirements: *2153587440
190
190
  - !ruby/object:Gem::Dependency
191
191
  name: w3c_validators
192
- requirement: &2153712580 !ruby/object:Gem::Requirement
192
+ requirement: &2153586860 !ruby/object:Gem::Requirement
193
193
  none: false
194
194
  requirements:
195
195
  - - ~>
@@ -197,10 +197,10 @@ dependencies:
197
197
  version: '1.2'
198
198
  type: :development
199
199
  prerelease: false
200
- version_requirements: *2153712580
200
+ version_requirements: *2153586860
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: treetop
203
- requirement: &2153712120 !ruby/object:Gem::Requirement
203
+ requirement: &2153586280 !ruby/object:Gem::Requirement
204
204
  none: false
205
205
  requirements:
206
206
  - - ~>
@@ -208,10 +208,10 @@ dependencies:
208
208
  version: 1.4.9
209
209
  type: :development
210
210
  prerelease: false
211
- version_requirements: *2153712120
211
+ version_requirements: *2153586280
212
212
  - !ruby/object:Gem::Dependency
213
213
  name: bluecloth
214
- requirement: &2153711500 !ruby/object:Gem::Requirement
214
+ requirement: &2153584940 !ruby/object:Gem::Requirement
215
215
  none: false
216
216
  requirements:
217
217
  - - ~>
@@ -219,7 +219,7 @@ dependencies:
219
219
  version: 2.0.11
220
220
  type: :development
221
221
  prerelease: false
222
- version_requirements: *2153711500
222
+ version_requirements: *2153584940
223
223
  description: ! "\n Framework for creating rich WebGL-enabled applications using
224
224
  JavaScript and Ruby.\n Can be used stand-alone to create static JavaScript documents,
225
225
  or integrated\n seamlessly with Ruby on Rails to build dynamic WebGL applications.\n
@@ -259,6 +259,7 @@ files:
259
259
  - bin/jax
260
260
  - config.ru
261
261
  - config/routes.rb
262
+ - features/rails/models.feature
262
263
  - features/rails/resources.feature
263
264
  - features/rails/shaders.feature
264
265
  - features/rails/specs.feature
@@ -268,6 +269,7 @@ files:
268
269
  - features/step_definitions/runtime.rb
269
270
  - features/step_definitions/web_steps.rb
270
271
  - features/support/env.rb
272
+ - features/support/numeric_matcher.rb
271
273
  - features/support/paths.rb
272
274
  - features/support/rails_environment.rb
273
275
  - features/support/selectors.rb
@@ -646,7 +648,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
646
648
  version: '0'
647
649
  segments:
648
650
  - 0
649
- hash: 2586210584584297927
651
+ hash: 1570841926271225879
650
652
  required_rubygems_version: !ruby/object:Gem::Requirement
651
653
  none: false
652
654
  requirements:
@@ -655,7 +657,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
655
657
  version: '0'
656
658
  segments:
657
659
  - 0
658
- hash: 2586210584584297927
660
+ hash: 1570841926271225879
659
661
  requirements: []
660
662
  rubyforge_project: jax
661
663
  rubygems_version: 1.8.10
@@ -664,6 +666,7 @@ specification_version: 3
664
666
  summary: Framework for creating rich WebGL-enabled applications using JavaScript and
665
667
  Ruby
666
668
  test_files:
669
+ - features/rails/models.feature
667
670
  - features/rails/resources.feature
668
671
  - features/rails/shaders.feature
669
672
  - features/rails/specs.feature
@@ -673,6 +676,7 @@ test_files:
673
676
  - features/step_definitions/runtime.rb
674
677
  - features/step_definitions/web_steps.rb
675
678
  - features/support/env.rb
679
+ - features/support/numeric_matcher.rb
676
680
  - features/support/paths.rb
677
681
  - features/support/rails_environment.rb
678
682
  - features/support/selectors.rb