1 /* Copyright 2014 Yukkuri Games
2 Licensed under the terms of the GNU GPL v2 or later
3 @license http://www.gnu.org/licenses/gpl-2.0.html
4 @source: http://yukkurigames.com/yuu/
10 var yT
= this.yT
|| require("./yT");
11 var yf
= this.yf
|| require("./yf");
13 if (!yuu
.C
) require("./ce");
14 if (!yuu
.Material
) require("./gfx");
17 constructor: function (vbuf
, primitive
, material
, uniforms
, z
) {
19 this.primitive
= primitive
|| yuu
.gl
.TRIANGLES
;
20 this.material
= material
|| yuu
.Material
.DEFAULT
;
21 this.uniforms
= uniforms
|| {};
26 this.material
.program
.setUniforms(this.uniforms
);
27 this.vbuf
.bindBuffer();
28 this.material
.program
.setAttribPointers(this.vbuf
);
33 yuu
.gl
.drawArrays(this.primitive
, 0, this.vbuf
.vertexCount
);
36 vertexCount
: { alias
: "vbuf.vertexCount" }
39 yuu
.IndexedRenderable
= yT(yuu
.Renderable
, {
40 constructor: function (vbuf
, primitive
, material
, uniforms
, z
, ibuf
) {
41 yuu
.Renderable
.call(this, vbuf
, primitive
, material
, uniforms
, z
);
46 yuu
.Renderable
.prototype.bind
.call(this);
47 this.ibuf
.bindBuffer();
53 this.primitive
, this.ibuf
.length
, this.ibuf
.GL_TYPE
, 0);
58 return this.ibuf
.length
;
60 set: function (vertexCount
) {
61 this.vbuf
.vertexCount
= vertexCount
;
62 this.ibuf
.maxIndex
= vertexCount
;
68 /** A vertex view containing a 2D quadrilateral
70 You probably don't want to use this directly. If you want a
71 simple quad, look at QuadC.
73 constructor: function (vbuf
) {
75 this.anchor
= "center";
76 this.position
= [0.0, 0.0];
77 this.size
= [1.0, 1.0];
78 this.texBounds
= [0.0, 0.0, 1.0, 1.0];
79 this.color
= [1.0, 1.0, 1.0, 1.0];
84 var b
= this._vbuf
.arrays
.position
;
85 return [b
[6] - b
[0], b
[4] - b
[1]];
88 var position
= this.position
;
89 var b
= this._vbuf
.arrays
.position
;
90 b
[0] = b
[3] = b
[1] = b
[7] = 0;
91 b
[6] = b
[9] = size
[0];
92 b
[4] = b
[10] = size
[1];
93 this.position
= position
;
94 this._vbuf
.dirty
= true;
100 var b
= this._vbuf
.arrays
.position
;
101 return yuu
.anchorPoint(this.anchor
, b
[0], b
[1], b
[6], b
[4]);
103 set: function (position
) {
104 var size
= this.size
;
105 var b
= this._vbuf
.arrays
.position
;
106 var bottomLeft
= yuu
.bottomLeft(
107 this.anchor
, position
[0], position
[1], size
[0], size
[1]);
108 b
[0] = b
[3] = bottomLeft
[0];
109 b
[1] = b
[7] = bottomLeft
[1];
110 b
[6] = b
[9] = bottomLeft
[0] + size
[0];
111 b
[4] = b
[10] = bottomLeft
[1] + size
[1];
112 this._vbuf
.dirty
= true;
116 x
: { synthetic
: "position[0]" },
117 y
: { synthetic
: "position[1]" },
119 // Texture coordinate vertices: 12 +...
125 var b
= this._vbuf
.arrays
.texCoord
;
126 return [b
[0], b
[1], b
[6], b
[7]];
128 set: function (uv0uv1
) {
129 var b
= this._vbuf
.arrays
.texCoord
;
130 b
[0] = b
[2] = uv0uv1
[0];
131 b
[1] = b
[5] = uv0uv1
[1];
132 b
[6] = b
[4] = uv0uv1
[2];
133 b
[3] = b
[7] = uv0uv1
[3];
134 this._vbuf
.dirty
= true;
138 // Color vertices: 20 +...
139 // 4,5,6,7 12,13,14,15
144 var b
= this._vbuf
.arrays
.color
;
145 return [b
[0], b
[1], b
[2], b
[3]];
147 set: function (rgba
) {
148 var b
= this._vbuf
.arrays
.color
;
150 b
[0] = b
[4] = b
[8] = b
[12] = rgba
[0];
151 b
[1] = b
[5] = b
[9] = b
[13] = rgba
[1];
152 b
[2] = b
[6] = b
[10] = b
[14] = rgba
[2];
154 b
[3] = b
[7] = b
[11] = b
[15] = a
;
155 this._vbuf
.dirty
= true;
161 var color
= this.color
;
162 return 0.2126 * color
[0]
168 this.color
= [v
, v
, v
];
173 get: function () { return this._vbuf
.arrays
.color
[3]; },
175 var b
= this._vbuf
.arrays
.color
;
176 b
[3] = b
[7] = b
[11] = b
[15] = a
;
177 this._vbuf
.dirty
= true;
183 constructor: function (capacity
) {
184 this.vbuf
= new yuu
.VertexBuffer(yuu
.V3T2C4_F
, capacity
* 4);
185 this.ibuf
= new yuu
.IndexBuffer(
186 this.vbuf
.vertexCount
, capacity
* 6);
187 this._capacity
= capacity
;
188 this._resetAllocations();
191 _vbufSlotFromQuad: function (quad
) {
192 if (quad
._vbuf
.arrays
.position
.buffer
!== this.vbuf
.buffer
)
193 throw new Error("invalid quad buffer");
194 var offset
= quad
._vbuf
.arrays
.position
.byteOffset
;
196 this.vbuf
.spec
.attribs
.position
.View
.BYTES_PER_ELEMENT
197 * this.vbuf
.spec
.attribs
.position
.elements
198 * 4 /* vertices per quad */);
199 return offset
/ bytesPerQuad
;
202 createQuad: function () {
203 var slot
= this._freeVbufSlots
[this._allocated
];
204 if (slot
=== undefined)
205 throw new Error("out of batch slots");
206 var subdata
= this.vbuf
.subdata(slot
* 4, 4);
207 var index
= this._allocated
++;
209 this.ibuf
.buffer
[n
+ 0] = slot
* 4 + 0;
210 this.ibuf
.buffer
[n
+ 1] = slot
* 4 + 1;
211 this.ibuf
.buffer
[n
+ 2] = slot
* 4 + 2;
212 this.ibuf
.buffer
[n
+ 3] = slot
* 4 + 2;
213 this.ibuf
.buffer
[n
+ 4] = slot
* 4 + 1;
214 this.ibuf
.buffer
[n
+ 5] = slot
* 4 + 3;
215 this.ibuf
.length
+= 6;
216 this.ibuf
.dirty
= true;
217 this._vbufToIndex
[slot
] = index
;
218 return new yuu
.Quad(subdata
);
221 disposeQuad: function (quad
) {
222 var slot
= this._vbufSlotFromQuad(quad
);
223 var index
= this._vbufToIndex
[slot
];
225 if (index
!== this._allocated
) {
226 // Unless this was the last index, swap the last index
227 // into the new hole.
228 var n
= 6 /* indices per quad */ * index
;
229 var m
= 6 /* indices per quad */ * this._allocated
;
230 var b
= this.ibuf
.buffer
;
231 var lastVbufSlot
= b
[m
] / 4 /* vertices per quad */;
232 if (this._vbufToIndex
[lastVbufSlot
] !== this._allocated
)
233 throw new Error("allocation index mismatch");
240 this.ibuf
.dirty
= true;
241 this._vbufToIndex
[lastVbufSlot
] = index
;
243 this._freeVbufSlots
[this._allocated
] = slot
;
244 this.ibuf
.length
-= 6;
247 _resetAllocations: function () {
248 this.ibuf
.length
= 0;
249 var Array
= yuu
.IndexBuffer
.Array(this._capacity
);
250 this._freeVbufSlots
= new Array(this._capacity
);
251 yf
.transform(yf
.counter(), this._freeVbufSlots
);
253 this._vbufToIndex
= new Array(this._capacity
);
256 disposeAll: function () {
257 this._resetAllocations();
261 yuu
.QuadC
= yT(yuu
.C
, {
262 /** A 2D quadrilateral that tracks the entity's transform
264 By default, the extents of this quad are [-0.5, -0.5] to
265 [0.5, 0.5], and its model matrix is identical to the
266 entity's transform, i.e. it is centered around [0, 0] in
267 the entity's local space, or the entity's nominal location
268 in world space. This can be changed by adjusting the
269 anchor, position, and size properties.
272 constructor: function (material
) {
273 var buffer
= new yuu
.VertexBuffer(yuu
.V3T2C4_F
, 4);
274 this._quad
= new yuu
.Quad(buffer
);
275 this._rdro
= new yuu
.Renderable(
276 buffer
, yuu
.gl
.TRIANGLE_STRIP
, material
,
277 { model
: mat4
.create() }, 0.0);
280 TAPS
: ["queueRenderables"],
282 queueRenderables: function (rdros
) {
283 mat4
.copy(this._rdro
.uniforms
.model
,
284 this.entity
.transform
.matrix
);
285 rdros
.push(this._rdro
);
288 // TODO: yT should offer some way to specify these in two
289 // lists, i.e. the rdro aliases, and the quad aliases.
291 material
: { alias
: "_rdro.material", chainable
: true },
292 z
: { alias
: "_rdro.z", chainable
: true },
293 uniforms
: { alias
: "_rdro.uniforms" },
294 size
: { alias
: "_quad.size", chainable
: true },
295 position
: { alias
: "_quad.position", chainable
: true },
296 anchor
: { alias
: "_quad.anchor", chainable
: true },
297 xy
: { alias
: "_quad.position", chainable
: true },
298 texBounds
: { alias
: "_quad.texBounds", chainable
: true },
299 color
: { alias
: "_quad.color", chainable
: true },
300 alpha
: { alias
: "_quad.alpha", chainable
: true },
301 luminance
: { alias
: "_quad.luminance", chainable
: true },
304 yuu
.QuadBatchC
= yT(yuu
.C
, {
305 /** A 2D quadrilateral batch that tracks the entity's transform
309 constructor: function (capacity
, material
) {
310 this._batch
= new yuu
.QuadBatch(capacity
);
311 this._rdro
= new yuu
.IndexedRenderable(
312 this._batch
.vbuf
, yuu
.gl
.TRIANGLES
, material
,
313 { model
: mat4
.create() }, 0.0, this._batch
.ibuf
);
316 TAPS
: ["queueRenderables"],
318 queueRenderables: function (rdros
) {
319 mat4
.copy(this._rdro
.uniforms
.model
,
320 this.entity
.transform
.matrix
);
321 rdros
.push(this._rdro
);
324 material
: { alias
: "_rdro.material", chainable
: true },
325 z
: { alias
: "_rdro.z", chainable
: true },
326 uniforms
: { alias
: "_rdro.uniforms" },
327 createQuad
: { proxy
: "_batch.createQuad" },
328 disposeQuad
: { proxy
: "_batch.disposeQuad" },
329 disposeAll
: { proxy
: "_batch.disposeAll" },
332 function sortRenderables(a
, b
) { return a
.z
- b
.z
; }
335 /** List of renderables and per-layer uniforms
337 These uniforms usually include the projection and view
338 matrices, set to a [-1, 1] orthographic projection and the
339 identity view by default.
342 // TODO: This is a bad design. Too powerful to be efficient or
343 // a straightforward part of Scene; not enough to abstract
344 // hard things like render passes.
346 constructor: function () {
349 projection
: mat4
.ortho(mat4
.create(), -1, 1, -1, 1, -1, 1),
354 worldFromDevice
: yf
.argcd(
356 var t
= this.worldFromDevice(p
.x
|| p
.pageX
|| p
[0] || 0,
357 p
.y
|| p
.pageY
|| p
[1] || 0);
362 var p
= { 0: x
, 1: y
};
363 var m
= mat4
.mul(mat4
.create(),
364 this.uniforms
.projection
, this.uniforms
.view
);
365 m
= mat4
.invert(m
, m
);
366 vec2
.transformMat4(p
, p
, m
);
367 p
.x
= p
[0]; p
.y
= p
[1];
372 worldFromCanvas
: yf
.argcd(
374 return this.worldFromDevice(yuu
.deviceFromCanvas(p
));
377 return this.worldFromDevice(yuu
.deviceFromCanvas(x
, y
));
381 resize: function (x
, y
, w
, h
) {
382 /** Set a 2D orthographic project with an origin and size
385 scene.resize(originX, originY, width, height)
386 scene.resize(width, height) // Origin at 0, 0
387 scene.resize(origin, size)
388 scene.resize(size) // Origin at 0, 0
390 if (y
=== undefined) {
391 w
= x
[0]; h
= x
[1]; x
= y
= 0;
392 } else if (w
=== undefined) {
393 if (x
.length
=== undefined) {
394 w
= x
; h
= y
; x
= y
= 0;
400 mat4
.ortho(this.uniforms
.projection
, x
, x
+ w
, y
, y
+ h
, -1, 1);
403 render: function () {
404 /** Render all queued renderables */
405 this.rdros
.sort(sortRenderables
);
407 for (var j
= 0; j
< this.rdros
.length
; ++j
) {
408 var rdro
= this.rdros
[j
];
409 if (mat
!== rdro
.material
) {
413 rdro
.material
.enable(this.uniforms
);
420 this.rdros
.length
= 0;
424 }).call(typeof exports
=== "undefined" ? this : exports
,
425 typeof exports
=== "undefined"
426 ? this.yuu
: (module
.exports
= require('./core')));