1 /*
  2 SpiderGL Computer Graphics Library
  3 Copyright (c) 2010, Marco Di Benedetto - Visual Computing Lab, ISTI - CNR
  4 All rights reserved.
  5 
  6 Redistribution and use in source and binary forms, with or without
  7 modification, are permitted provided that the following conditions are met:
  8     * Redistributions of source code must retain the above copyright
  9       notice, this list of conditions and the following disclaimer.
 10     * Redistributions in binary form must reproduce the above copyright
 11       notice, this list of conditions and the following disclaimer in the
 12       documentation and/or other materials provided with the distribution.
 13     * Neither the name of SpiderGL nor the
 14       names of its contributors may be used to endorse or promote products
 15       derived from this software without specific prior written permission.
 16 
 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY
 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 27 */
 28 
 29 /**
 30  * @fileOverview Model
 31  */
 32 
 33 /**
 34  * The SpiderGL.Model namespace.
 35  *
 36  * @namespace The SpiderGL.Model namespace.
 37  */
 38 SpiderGL.Model = { };
 39 
 40 /**
 41  * Creates a SpiderGL.Model.Model.
 42  *
 43  * A SpiderGL.Model.Model is a layered data structure that represents a geometric model.
 44  * Through the model descriptor, it provides the elements needed to form a 3D model, e.g. raw data, semantic bindings, logical sub-structures, and higher level information.
 45  * Bottom to top, each layer in the stack relies at most on the previous one. While layer flexibility decreases bottom to top, their expressiveness increases.
 46  *
 47  * @class The SpiderGL.Model.Model represents a complex geometric model.
 48  *
 49  * @augments SpiderGL.Core.ObjectBase
 50  */
 51 SpiderGL.Model.Model = function (gl, descriptor, options) {
 52 	SpiderGL.Core.ObjectBase.call(this);
 53 
 54 	options = SpiderGL.Utility.getDefaultObject({
 55 	}, options);
 56 
 57 	if (descriptor && ("vertices" in descriptor)) {
 58 		descriptor = SpiderGL.Model.Model._createSimpleDescriptor(descriptor);
 59 	}
 60 
 61 	this._descriptor = SpiderGL.Model.Model._fixDescriptor(descriptor);
 62 	this._gl = null;
 63 	this._renderData = { };
 64 
 65 	if (gl) {
 66 		this.updateGL(gl, options);
 67 		this.updateRenderData();
 68 	}
 69 };
 70 
 71 SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_SIZE       = 3;
 72 SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_TYPE       = SpiderGL.Type.FLOAT32;
 73 SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_NORMALIZED = false;
 74 SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_STRIDE     = 0;
 75 SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_OFFSET     = 0;
 76 
 77 SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_MODE    = SpiderGL.Type.TRIANGLES;
 78 SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_FIRST   = 0;
 79 SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_COUNT   = -1;
 80 SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_TYPE    = SpiderGL.Type.UINT16;
 81 SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_OFFSET  = 0;
 82 
 83 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP = { };
 84 
 85 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["position"] = {
 86 	size       : 3,
 87 	type       : SpiderGL.Type.FLOAT32,
 88 	normalized : false,
 89 	semantic   : "POSITION",
 90 	index      : 0,
 91 	value      : [0.0, 0.0, 0.0, 1.0]
 92 };
 93 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["normal"] = {
 94 	size       : 3,
 95 	type       : SpiderGL.Type.FLOAT32,
 96 	normalized : false,
 97 	semantic   : "NORMAL",
 98 	index      : 0,
 99 	value      : [0.0, 0.0, 1.0, 0.0]
100 };
101 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["color"] = {
102 	size       : 4,
103 	type       : SpiderGL.Type.UINT8,
104 	normalized : true,
105 	semantic   : "COLOR",
106 	index      : 0,
107 	value      : [0, 0, 0, 255]
108 };
109 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["texcoord"] = {
110 	size       : 2,
111 	type       : SpiderGL.Type.FLOAT32,
112 	normalized : false,
113 	semantic   : "TEXCOORD",
114 	index      : 0,
115 	value      : [0.0, 0.0, 0.0, 1.0]
116 };
117 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["user"] = {
118 	size       : 3,
119 	type       : SpiderGL.Type.FLOAT32,
120 	normalized : false,
121 	semantic   : "USER",
122 	index      : 0,
123 	value      : [0.0, 0.0, 0.0, 1.0]
124 };
125 
126 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP = { };
127 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangles"] = {
128 	mode       : SpiderGL.Type.TRIANGLES,
129 	type       : SpiderGL.Type.UINT16,
130 	count      : -1,
131 	semantic   : "FILL"
132 };
133 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangleStrip"] = {
134 	mode       : SpiderGL.Type.TRIANGLE_STRIP,
135 	type       : SpiderGL.Type.UINT16,
136 	count      : -1,
137 	semantic   : "FILL"
138 };
139 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["triangleFan"] = {
140 	mode       : SpiderGL.Type.TRIANGLE_FAN,
141 	type       : SpiderGL.Type.UINT16,
142 	count      : -1,
143 	semantic   : "FILL"
144 };
145 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lines"] = {
146 	mode       : SpiderGL.Type.LINES,
147 	type       : SpiderGL.Type.UINT16,
148 	count      : -1,
149 	semantic   : "LINE"
150 };
151 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lineStrip"] = {
152 	mode       : SpiderGL.Type.LINE_STRIP,
153 	type       : SpiderGL.Type.UINT16,
154 	count      : -1,
155 	semantic   : "LINE"
156 };
157 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["lineLoop"] = {
158 	mode       : SpiderGL.Type.LINE_LOOP,
159 	type       : SpiderGL.Type.UINT16,
160 	count      : -1,
161 	semantic   : "LINE"
162 };
163 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["points"] = {
164 	mode       : SpiderGL.Type.POINTS,
165 	type       : SpiderGL.Type.UINT16,
166 	count      : -1,
167 	semantic   : "POINT"
168 };
169 SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["user"] = {
170 	mode       : SpiderGL.Type.TRIANGLES,
171 	type       : SpiderGL.Type.UINT16,
172 	count      : -1,
173 	semantic   : "FILL"
174 };
175 
176 SpiderGL.Model.Model._fixDescriptor = function (d) {
177 	d = SpiderGL.Utility.getDefaultObject({
178 		version  : "0.0.0.1 EXP",
179 		meta     : null,
180 		data     : null,
181 		access   : null,
182 		semantic : null,
183 		logic    : null
184 	}, d);
185 
186 	d.meta     = SpiderGL.Model.Model._fixDescriptorMeta     (d.meta);
187 	d.data     = SpiderGL.Model.Model._fixDescriptorData     (d.data);
188 	d.access   = SpiderGL.Model.Model._fixDescriptorAccess   (d.access);
189 	d.semantic = SpiderGL.Model.Model._fixDescriptorSemantic (d.semantic);
190 	d.logic    = SpiderGL.Model.Model._fixDescriptorLogic    (d.logic);
191 
192 	return d;
193 };
194 
195 SpiderGL.Model.Model._fixDescriptorMeta = function (d) {
196 	d = SpiderGL.Utility.getDefaultObject({
197 		author      : null,
198 		date        : null,
199 		description : null
200 	}, d);
201 	return d;
202 };
203 
204 SpiderGL.Model.Model._fixDescriptorData = function (d) {
205 	d = SpiderGL.Utility.getDefaultObject({
206 		vertexBuffers : null,
207 		indexBuffers  : null
208 	}, d);
209 
210 	d.vertexBuffers = SpiderGL.Model.Model._fixDescriptorDataVertexBuffers (d.vertexBuffers);
211 	d.indexBuffers  = SpiderGL.Model.Model._fixDescriptorDataIndexBuffers  (d.indexBuffers);
212 
213 	return d;
214 };
215 
216 SpiderGL.Model.Model._fixDescriptorDataVertexBuffers = function (d) {
217 	d = SpiderGL.Utility.getDefaultObject({ }, d);
218 	for (var x in d) {
219 		d[x] = SpiderGL.Model.Model._fixDescriptorDataVertexBuffer(d[x]);
220 	}
221 	return d;
222 };
223 
224 SpiderGL.Model.Model._fixDescriptorDataVertexBuffer = function (d) {
225 	return SpiderGL.Model.Model._fixDescriptorDataBuffer(d);
226 };
227 
228 SpiderGL.Model.Model._fixDescriptorDataIndexBuffers = function (d) {
229 	d = SpiderGL.Utility.getDefaultObject({ }, d);
230 	for (var x in d) {
231 		d[x] = SpiderGL.Model.Model._fixDescriptorDataIndexBuffer(d[x]);
232 	}
233 	return d;
234 };
235 
236 SpiderGL.Model.Model._fixDescriptorDataIndexBuffer = function (d) {
237 	return SpiderGL.Model.Model._fixDescriptorDataBuffer(d);
238 };
239 
240 SpiderGL.Model.Model._fixDescriptorDataBuffer = function (d) {
241 	d = SpiderGL.Utility.getDefaultObject({
242 		type         : SpiderGL.Type.NO_TYPE,
243 		glType       : WebGLRenderingContext.NONE,
244 		untypedArray : null,
245 		typedArray   : null,
246 		glBuffer     : null
247 	}, d);
248 	return d;
249 };
250 
251 SpiderGL.Model.Model._fixDescriptorAccess = function (d) {
252 	d = SpiderGL.Utility.getDefaultObject({
253 		vertexStreams    : null,
254 		primitiveStreams : null
255 	}, d);
256 
257 	d.vertexStreams     = SpiderGL.Model.Model._fixDescriptorAccessVertexStreams    (d.vertexStreams);
258 	d.primitiveStreams  = SpiderGL.Model.Model._fixDescriptorAccessPrimitiveStreams (d.primitiveStreams);
259 
260 	return d;
261 };
262 
263 SpiderGL.Model.Model._fixDescriptorAccessVertexStreams = function (d) {
264 	d = SpiderGL.Utility.getDefaultObject({ }, d);
265 	for (var x in d) {
266 		d[x] = SpiderGL.Model.Model._fixDescriptorAccessVertexStream(d[x]);
267 	}
268 	return d;
269 };
270 
271 SpiderGL.Model.Model._fixDescriptorAccessVertexStream = function (d) {
272 	d = SpiderGL.Utility.getDefaultObject({
273 		buffer     : null,
274 		size       : SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_SIZE,
275 		type       : SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_TYPE,
276 		glType     : SpiderGL.Type.typeToGL(SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_TYPE),
277 		normalized : SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_NORMALIZED,
278 		stride     : SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_STRIDE,
279 		offset     : SpiderGL.Model.Model.DEFAULT_VERTEX_STREAM_OFFSET
280 	}, d);
281 	return d;
282 };
283 
284 SpiderGL.Model.Model._fixDescriptorAccessPrimitiveStreams = function (d) {
285 	d = SpiderGL.Utility.getDefaultObject({ }, d);
286 	for (var x in d) {
287 		d[x] = SpiderGL.Model.Model._fixDescriptorAccessPrimitiveStream(d[x]);
288 	}
289 	return d;
290 };
291 
292 SpiderGL.Model.Model._fixDescriptorAccessPrimitiveStream = function (d) {
293 	d = SpiderGL.Utility.getDefaultObject({
294 		buffer     : null,
295 		mode       : SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_MODE,
296 		first      : SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_FIRST,
297 		count      : SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_COUNT,
298 		type       : SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_TYPE,
299 		glType     : SpiderGL.Type.typeToGL(SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_TYPE),
300 		offset     : SpiderGL.Model.Model.DEFAULT_PRIMITIVE_STREAM_OFFSET
301 	}, d);
302 	return d;
303 };
304 
305 SpiderGL.Model.Model._fixDescriptorSemantic = function (d) {
306 	d = SpiderGL.Utility.getDefaultObject({
307 		bindings : null,
308 		chunks   : null
309 	}, d);
310 
311 	d.bindings = SpiderGL.Model.Model._fixDescriptorSemanticBindings (d.bindings);
312 	d.chunks   = SpiderGL.Model.Model._fixDescriptorSemanticChunks   (d.chunks);
313 
314 	return d;
315 };
316 
317 SpiderGL.Model.Model._fixDescriptorSemanticBindings = function (d) {
318 	d = SpiderGL.Utility.getDefaultObject({ }, d);
319 	for (var x in d) {
320 		d[x] = SpiderGL.Model.Model._fixDescriptorSemanticBinding(d[x]);
321 	}
322 	return d;
323 };
324 
325 SpiderGL.Model.Model._fixDescriptorSemanticBinding = function (d) {
326 	d = SpiderGL.Utility.getDefaultObject({
327 		vertexStreams    : null,
328 		primitiveStreams : null
329 	}, d);
330 
331 	d.vertexStreams    = SpiderGL.Model.Model._fixDescriptorSemanticBindingVertexStreams    (d.vertexStreams);
332 	d.primitiveStreams = SpiderGL.Model.Model._fixDescriptorSemanticBindingPrimitiveStreams (d.primitiveStreams);
333 
334 	return d;
335 };
336 
337 SpiderGL.Model.Model._fixDescriptorSemanticBindingVertexStreams = function (d) {
338 	d = SpiderGL.Utility.getDefaultObject({ }, d);
339 	for (var x in d) {
340 		d[x] = SpiderGL.Model.Model._fixDescriptorSemanticBindingVertexStream(d[x]);
341 	}
342 	return d;
343 };
344 
345 SpiderGL.Model.Model._fixDescriptorSemanticBindingVertexStream = function (d) {
346 	if (!d) return null;
347 	if (SpiderGL.Type.isArray(d)) return d.slice();
348 	return [ d ];
349 };
350 
351 SpiderGL.Model.Model._fixDescriptorSemanticBindingPrimitiveStreams = function (d) {
352 	d = SpiderGL.Utility.getDefaultObject({ }, d);
353 	for (var x in d) {
354 		d[x] = SpiderGL.Model.Model._fixDescriptorSemanticBindingPrimitiveStream(d[x]);
355 	}
356 	return d;
357 };
358 
359 SpiderGL.Model.Model._fixDescriptorSemanticBindingPrimitiveStream = function (d) {
360 	if (!d) return null;
361 	if (SpiderGL.Type.isArray(d)) return d.slice();
362 	return [ d ];
363 };
364 
365 SpiderGL.Model.Model._fixDescriptorSemanticChunks = function (d) {
366 	d = SpiderGL.Utility.getDefaultObject({ }, d);
367 	for (var x in d) {
368 		d[x] = SpiderGL.Model.Model._fixDescriptorSemanticChunk(d[x]);
369 	}
370 	return d;
371 };
372 
373 SpiderGL.Model.Model._fixDescriptorSemanticChunk = function (d) {
374 	d = SpiderGL.Utility.getDefaultObject({
375 		techniques : null
376 	}, d);
377 
378 	d.techniques = SpiderGL.Model.Model._fixDescriptorSemanticChunkTechniques(d.techniques);
379 
380 	return d;
381 };
382 
383 SpiderGL.Model.Model._fixDescriptorSemanticChunkTechniques = function (d) {
384 	d = SpiderGL.Utility.getDefaultObject({ }, d);
385 	for (var x in d) {
386 		d[x] = SpiderGL.Model.Model._fixDescriptorSemanticChunkTechnique(d[x]);
387 	}
388 	return d;
389 };
390 
391 SpiderGL.Model.Model._fixDescriptorSemanticChunkTechnique = function (d) {
392 	d = SpiderGL.Utility.getDefaultObject({
393 		binding : null
394 	}, d);
395 	return d;
396 };
397 
398 SpiderGL.Model.Model._fixDescriptorLogic = function (d) {
399 	d = SpiderGL.Utility.getDefaultObject({
400 		parts : null
401 	}, d);
402 
403 	d.parts = SpiderGL.Model.Model._fixDescriptorLogicParts(d.parts);
404 
405 	return d;
406 };
407 
408 SpiderGL.Model.Model._fixDescriptorLogicParts = function (d) {
409 	d = SpiderGL.Utility.getDefaultObject({ }, d);
410 	for (var x in d) {
411 		d[x] = SpiderGL.Model.Model._fixDescriptorLogicPart(d[x]);
412 	}
413 	return d;
414 };
415 
416 SpiderGL.Model.Model._fixDescriptorLogicPart = function (d) {
417 	d = SpiderGL.Utility.getDefaultObject({
418 		chunks : null
419 	}, d);
420 
421 	d.chunks = SpiderGL.Model.Model._fixDescriptorLogicPartChunks(d.chunks);
422 
423 	return d;
424 };
425 
426 SpiderGL.Model.Model._fixDescriptorLogicPartChunks = function (d) {
427 	if (!d) return null;
428 	if (SpiderGL.Type.isArray(d)) return d.slice();
429 	return [ d ];
430 };
431 
432 SpiderGL.Model.Model._createSimpleDescriptor = function (options) {
433 	options = SpiderGL.Utility.getDefaultObject({
434 		vertices   : null,
435 		primitives : null,
436 		options    : null
437 	}, options);
438 
439 	var bindingName        = "mainBinding";
440 	var chunkName          = "mainChunk";
441 	var partName           = "mainPart";
442 	var vertexBufferSuffix = "VertexBuffer";
443 	var indexBufferSuffix  = "IndexBuffer";
444 
445 	var d = {
446 		data : {
447 			vertexBuffers : {
448 			},
449 			indexBuffers : {
450 			},
451 		},
452 		access : {
453 			vertexStreams : {
454 			},
455 			primitiveStreams : {
456 			}
457 		},
458 		semantic : {
459 			bindings : {
460 			},
461 			chunks : {
462 			}
463 		},
464 		logic : {
465 			parts : {
466 			}
467 		}
468 	};
469 
470 	var binding = {
471 		vertexStreams : {
472 		},
473 		primitiveStreams : {
474 		}
475 	};
476 	d.semantic.bindings[bindingName] = binding;
477 
478 	var chunk = {
479 		techniques : {
480 			"common" : {
481 				binding : bindingName
482 			}
483 		}
484 	};
485 	d.semantic.chunks[chunkName] = chunk;
486 
487 	var part = {
488 		chunks : [ chunkName ]
489 	};
490 	d.logic.parts[partName] = part;
491 
492 	var minBufferedCount = -1;
493 	var hasBuffered = false;
494 	var hasConstant = false;
495 
496 	for (var x in options.vertices) {
497 		var src = options.vertices[x];
498 		if (!src) continue;
499 
500 		if (SpiderGL.Type.isArray(src) || SpiderGL.Type.isTypedArray(src) || SpiderGL.Type.instanceOf(src, ArrayBuffer)) {
501 			src = { data : src };
502 		}
503 
504 		var map = SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP[x];
505 		var mapSemantic = null;
506 		if (!map) {
507 			map = SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_VERTEX_MAP["user"];
508 			mapSemantic = x.toUpperCase();
509 		}
510 		else {
511 			mapSemantic = map.semantic;
512 		}
513 
514 		var info = SpiderGL.Utility.getDefaultObject({
515 			size       : map.size,
516 			type       : map.type,
517 			normalized : map.normalized,
518 			semantic   : mapSemantic,
519 			index      : map.index,
520 			data       : null,
521 			value      : map.value.slice()
522 		}, src);
523 
524 		var accessor = {
525 			buffer     : null,
526 			size       : info.size,
527 			type       : info.type,
528 			normalized : info.normalized,
529 			stride     : 0,
530 			offset     : 0,
531 			value      : info.value.slice(),
532 		};
533 
534 		if (info.data) {
535 			var buffer = {
536 				type : info.type
537 			};
538 			var count = 0;
539 			if (SpiderGL.Type.isArray(info.data)) {
540 				buffer.untypedArray = info.data;
541 				count = buffer.untypedArray.length / accessor.size;
542 			}
543 			else if (SpiderGL.Type.isTypedArray(src) || SpiderGL.Type.instanceOf(src, ArrayBuffer)) {
544 				buffer.typedArray = info.data;
545 				count = (buffer.typedArray.byteLength - accessor.offset) / (accessor.size * SpiderGL.Type.typeSize(accessor.type));
546 			}
547 			else {
548 				continue;
549 			}
550 			count = SpiderGL.Math.floor(count);
551 			hasBuffered = true;
552 			minBufferedCount = (minBufferedCount >= 0) ? (SpiderGL.Math.min(minBufferedCount, count)) : (count);
553 			var bufferName = x + vertexBufferSuffix;
554 			d.data.vertexBuffers[bufferName] = buffer;
555 			accessor.buffer = bufferName;
556 		}
557 		else {
558 			hasConstant = true;
559 		}
560 
561 		var streamName = x;
562 		d.access.vertexStreams[streamName] = accessor;
563 
564 		var streams = new Array(info.index + 1);
565 		streams[info.index] = streamName;
566 		binding.vertexStreams[info.semantic] = streams;
567 	}
568 
569 	var minCount = 0;
570 	if (hasBuffered) {
571 		minCount = minBufferedCount;
572 	}
573 	else if (hasConstant) {
574 		minCount = 1;
575 	}
576 
577 	var optionsPrimitives = options.primitives;
578 	if (SpiderGL.Type.isString(optionsPrimitives)) {
579 		optionsPrimitives = [ optionsPrimitives ];
580 	}
581 	if (SpiderGL.Type.isArray(optionsPrimitives)) {
582 		var op = optionsPrimitives;
583 		optionsPrimitives = { };
584 		for (var i=0, n=op.length; i<n; ++i) {
585 			var pn = op[i];
586 			if (!SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP[pn]) continue;
587 			optionsPrimitives[pn] = { };
588 		}
589 	}
590 
591 	for (var x in optionsPrimitives) {
592 		var src = optionsPrimitives[x];
593 		if (!src) continue;
594 
595 		if (SpiderGL.Type.isArray(src) || SpiderGL.Type.isTypedArray(src) || SpiderGL.Type.instanceOf(src, ArrayBuffer)) {
596 			src = { data : src };
597 		}
598 
599 		var map = SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP[x];
600 		if (!map) map = SpiderGL.Model.Model.DEFAULT_SIMPLE_MODEL_PRIMITIVE_MAP["user"];
601 
602 		var info = SpiderGL.Utility.getDefaultObject({
603 			mode     : map.mode,
604 			type     : map.type,
605 			count    : ((map.count >= 0) ? (map.count) : (minCount)),
606 			semantic : map.semantic
607 		}, src);
608 
609 		var accessor = {
610 			buffer     : null,
611 			mode       : info.mode,
612 			first      : 0,
613 			count      : info.count,
614 			type       : info.type,
615 			offset     : 0
616 		};
617 
618 		if (info.data) {
619 			var buffer = {
620 				type : info.type
621 			};
622 			var count = 0
623 			if (SpiderGL.Type.isArray(info.data)) {
624 				buffer.untypedArray = info.data;
625 				count = buffer.untypedArray.length;
626 			}
627 			else if (SpiderGL.Type.isTypedArray(src) || SpiderGL.Type.instanceOf(src, ArrayBuffer)) {
628 				buffer.typedArray = info.data;
629 				count = (buffer.typedArray.byteLength - accessor.offset) / (SpiderGL.Type.typeSize(accessor.type));
630 			}
631 			else {
632 				continue;
633 			}
634 			count = SpiderGL.Math.floor(count);
635 			var bufferName = x + indexBufferSuffix;
636 			d.data.indexBuffers[bufferName] = buffer;
637 			accessor.buffer = bufferName;
638 			accessor.count  = count;
639 		}
640 
641 		var streamName = x;
642 		d.access.primitiveStreams[streamName] = accessor;
643 
644 		var streams = new Array(1);
645 		streams[0] = streamName;
646 		binding.primitiveStreams[info.semantic] = streams;
647 	}
648 
649 	return d;
650 };
651 
652 SpiderGL.Model.Model.prototype = {
653 	get descriptor() {
654 		return this._descriptor;
655 	},
656 
657 	get isReady() {
658 		return !!this._descriptor;
659 	},
660 
661 	get gl() {
662 		return this._gl;
663 	},
664 
665 	get renderData() {
666 		return this._renderData;
667 	},
668 
669 	updateTypedArrays : function () {
670 		var d = this._descriptor;
671 		if (!d) return false;
672 
673 		var buffer = null;
674 		var ctor   = null;
675 
676 		var vertexBuffers = d.data.vertexBuffers;
677 		for (var x in vertexBuffers) {
678 			buffer = vertexBuffers[x];
679 			if (!buffer.untypedArray) continue;
680 			ctor = SpiderGL.Type.typeToTypedArrayConstructor(buffer.type);
681 			buffer.typedArray = new ctor(buffer.untypedArray);
682 		}
683 
684 		var indexBuffers = d.data.indexBuffers;
685 		for (var x in indexBuffers) {
686 			buffer = indexBuffers[x];
687 			if (!buffer.untypedArray) continue;
688 			ctor = SpiderGL.Type.typeToTypedArrayConstructor(buffer.type);
689 			buffer.typedArray = new ctor(buffer.untypedArray);
690 		}
691 
692 		return true;
693 	},
694 
695 	updateGL : function (gl, options) {
696 		if (!gl) return false;
697 
698 		var d = this._descriptor;
699 		if (!d) return false;
700 
701 		this._gl = gl;
702 
703 		var buffer     = null;
704 		var typedArray = null;
705 		var ctor       = null;
706 
707 		var bufferOptions = SpiderGL.Utility.getDefaultObject({
708 			data   : null,
709 			usage  : SpiderGL.Core.DEFAULT
710 		}, options);
711 		bufferOptions.data = null;
712 
713 		for (var x in d.data.vertexBuffers) {
714 			buffer = d.data.vertexBuffers[x];
715 			bufferOptions.data = buffer.typedArray;
716 			if (!bufferOptions.data) {
717 				ctor = SpiderGL.Type.typeToTypedArrayConstructor(buffer.type);
718 				bufferOptions.data = new ctor(buffer.untypedArray);
719 			}
720 			if (buffer.glBuffer) {
721 				buffer.glBuffer.destroy();
722 				buffer.glBuffer = null;
723 			}
724 			buffer.glBuffer = new SpiderGL.WebGL.VertexBuffer(gl, bufferOptions);
725 		}
726 
727 		for (var x in d.data.indexBuffers) {
728 			buffer = d.data.indexBuffers[x];
729 			bufferOptions.data = buffer.typedArray;
730 			if (!bufferOptions.data) {
731 				ctor = SpiderGL.Type.typeToTypedArrayConstructor(buffer.type);
732 				bufferOptions.data = new ctor(buffer.untypedArray);
733 			}
734 			if (buffer.glBuffer) {
735 				buffer.glBuffer.destroy();
736 				buffer.glBuffer = null;
737 			}
738 			buffer.glBuffer = new SpiderGL.WebGL.IndexBuffer(gl, bufferOptions);
739 		}
740 
741 		var stream = null;
742 
743 		for (var x in d.access.vertexStreams) {
744 			stream = d.access.vertexStreams[x];
745 			stream.glType = SpiderGL.Type.typeToGL(stream.type);
746 		}
747 
748 		for (var x in d.access.primitiveStreams) {
749 			stream = d.access.primitiveStreams[x];
750 			stream.glMode = SpiderGL.Type.primitiveToGL(stream.mode);
751 			stream.glType = SpiderGL.Type.typeToGL(stream.type);
752 		}
753 
754 		return true;
755 	},
756 
757 	destroyGL : function () {
758 		var d = this._descriptor;
759 		if (!d) return false;
760 
761 		var buffer = null;
762 
763 		for (var x in d.data.vertexBuffers) {
764 			buffer = d.data.vertexBuffers[x];
765 			if (buffer.glBuffer) {
766 				buffer.glBuffer.destroy();
767 				buffer.glBuffer = null;
768 			}
769 		}
770 
771 		for (var x in d.data.indexBuffers) {
772 			buffer = d.data.indexBuffers[x];
773 			if (buffer.glBuffer) {
774 				buffer.glBuffer.destroy();
775 				buffer.glBuffer = null;
776 			}
777 		}
778 	},
779 
780 	updateRenderData : function () {
781 		var d = this._descriptor;
782 		if (!d) return false;
783 
784 		var renderData = {
785 			partMap : { }
786 		};
787 
788 		for (var partName in d.logic.parts) {
789 			var part = d.logic.parts[partName];
790 			var chunkNames = part.chunks;
791 			var partInfo = { };
792 			renderData.partMap[partName] = partInfo;
793 
794 			for (var i=0, n=chunkNames.length; i<n; ++i) {
795 				var chunkName = chunkNames[i];
796 				var chunk = d.semantic.chunks[chunkName];
797 				var chunkInfo = { };
798 				partInfo[chunkName] = chunkInfo;
799 
800 				var techniques = chunk.techniques;
801 				for (var techniqueName in techniques) {
802 					var techique = techniques[techniqueName];
803 					var techiqueInfo = {
804 						vertexStreams : {
805 							buffered : [ ],
806 							constant : [ ]
807 						},
808 						primitiveStreams : { }
809 					};
810 					chunkInfo[techniqueName] = techiqueInfo;
811 
812 					var binding = d.semantic.bindings[techique.binding];
813 
814 					var streams = binding.vertexStreams;
815 					var bufferMap = { };
816 					for (var semantic in streams) {
817 						var streamNames = streams[semantic];
818 						for (var j=0, m=streamNames.length; j<m; ++j) {
819 							var streamName = streamNames[j];
820 							var stream = d.access.vertexStreams[streamName];
821 							var streamInfo = {
822 								semantic : semantic,
823 								index    : j,
824 								stream   : stream
825 							}
826 							var bufferName = stream.buffer;
827 							if (bufferName) {
828 								bufferMap[bufferName] = bufferMap[bufferName] || [ ];
829 								bufferMap[bufferName].push(streamInfo);
830 							}
831 							else {
832 								techiqueInfo.vertexStreams.constant.push(streamInfo);
833 							}
834 						}
835 					}
836 					for (var bufferName in bufferMap) {
837 						var bufferInfo = {
838 							buffer  : d.data.vertexBuffers[bufferName],
839 							streams : bufferMap[bufferName].slice()
840 						};
841 						techiqueInfo.vertexStreams.buffered.push(bufferInfo);
842 					}
843 
844 					var streams = binding.primitiveStreams;
845 					for (var semantic in streams) {
846 						var bufferMap = { };
847 						var primitiveStreamsInfo = {
848 							buffered : [ ],
849 							array    : [ ]
850 						};
851 						techiqueInfo.primitiveStreams[semantic] = primitiveStreamsInfo;
852 
853 						var streamNames = streams[semantic];
854 						for (var j=0, m=streamNames.length; j<m; ++j) {
855 							var streamName = streamNames[j];
856 							var stream = d.access.primitiveStreams[streamName];
857 							var bufferName = stream.buffer;
858 							if (bufferName) {
859 								bufferMap[bufferName] = bufferMap[bufferName] || [ ];
860 								bufferMap[bufferName].push(stream);
861 							}
862 							else {
863 								primitiveStreamsInfo.array.push(stream);
864 							}
865 						}
866 						for (var bufferName in bufferMap) {
867 							var bufferInfo = {
868 								buffer  : d.data.indexBuffers[bufferName],
869 								streams : bufferMap[bufferName].slice()
870 							};
871 							primitiveStreamsInfo.buffered.push(bufferInfo);
872 						}
873 					}
874 				}
875 			}
876 		}
877 
878 		this._renderData = renderData;
879 	}
880 };
881 
882 SpiderGL.Type.extend(SpiderGL.Model.Model, SpiderGL.Core.ObjectBase);
883 
884 /**
885  * Creates a SpiderGL.Model.Technique.
886  *
887  * @class The SpiderGL.Model.Technique handles the way a model is drawn.
888  *
889  * @augments SpiderGL.Core.ObjectBase
890  */
891 SpiderGL.Model.Technique = function (gl, descriptor, options) {
892 	SpiderGL.Core.ObjectBase.call(this);
893 
894 	options = SpiderGL.Utility.getDefaultObject({
895 	}, options);
896 
897 	if (descriptor && ("vertexShader" in descriptor) && ("fragmentShader" in descriptor)) {
898 		descriptor = SpiderGL.Model.Technique._createSimpleDescriptor(gl, descriptor);
899 	}
900 
901 	this._descriptor = SpiderGL.Model.Technique._fixDescriptor(descriptor);
902 	this._gl = this._descriptor.program.gl;
903 	this._renderData = { };
904 
905 	if (gl) {
906 		this.updateRenderData();
907 	}
908 };
909 
910 SpiderGL.Model.Technique._fixDescriptor = function (d) {
911 	d = SpiderGL.Utility.getDefaultObject({
912 		name     : "common",
913 		program  : null,
914 		semantic : { }
915 	}, d);
916 
917 	if (d.vertexStreams) {
918 		d.semantic.vertexStreams = d.vertexStreams;
919 		delete d.vertexStreams;
920 	}
921 
922 	if (d.globals) {
923 		d.semantic.globals = d.globals;
924 		delete d.globals;
925 	}
926 
927 	d.semantic = SpiderGL.Model.Technique._fixSemantic(d.program, d.semantic);
928 
929 	return d;
930 };
931 
932 SpiderGL.Model.Technique._fixSemantic = function (p, d) {
933 	d = SpiderGL.Utility.getDefaultObject({
934 		vertexStreams : null,
935 		globals       : null
936 	}, d);
937 
938 	d.vertexStreams = SpiderGL.Model.Technique._fixVertexStreams (p, d.vertexStreams);
939 	d.globals       = SpiderGL.Model.Technique._fixGlobals       (p, d.globals);
940 
941 	return d;
942 };
943 
944 SpiderGL.Model.Technique._fixVertexStreams = function (p, d) {
945 	var num = "0123456789";
946 	//var lwr = "abcdefghijklmnopqrstuvwxyz";
947 	//var upr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
948 
949 	var attribNames = p.getAttributesNames();
950 	var requiredAttribs = { };
951 	for (var i=0, n=attribNames.length; i<n; ++i) {
952 		var attribName  = attribNames[i];
953 
954 		var semanticStr = "";
955 		var indexStr    = "";
956 
957 		for (var j=attribName.length-1; j>=0; --j) {
958 			var ch = attribName.charAt(j);
959 			if (num.indexOf(ch, 0) == -1) {
960 				semanticStr = attribName.substring(0, j + 1);
961 				break;
962 			}
963 			indexStr = ch + indexStr;
964 		}
965 		var index = ((indexStr.length > 0) ? (parseInt(indexStr)) : (0));
966 
967 		var len = semanticStr.length;
968 		if (len >= 2) {
969 			if (semanticStr.charAt(0) == "a") {
970 				var ch = semanticStr.charAt(1);
971 				if ((ch == "_") && (len > 2)) {
972 					semanticStr = semanticStr.substring(2);
973 				}
974 				else if (ch == semanticStr.charAt(1).toUpperCase()) {
975 					semanticStr = semanticStr.substring(1);
976 				}
977 			}
978 		}
979 		var semantic = semanticStr.toUpperCase();
980 		requiredAttribs[attribName] = {
981 			semantic : semantic,
982 			index    : index,
983 			value    : [0.0, 0.0, 0.0, 1.0]
984 		};
985 	}
986 
987 	var dd = { };
988 	for (var x in d) {
989 		var r = requiredAttribs[x];
990 		if (!r) continue;
991 
992 		var s = d[x];
993 		if (SpiderGL.Type.isString(s)) {
994 			s = { semantic : s };
995 		}
996 		else if (SpiderGL.Type.isArray(s) || SpiderGL.Type.isTypedArray(s)) {
997 			s = { value : s };
998 		}
999 		else if (SpiderGL.Type.isNumber(s)) {
1000 			s = { value : [s, s, s, s] };
1001 		}
1002 		dd[x] = SpiderGL.Utility.getDefaultObject({
1003 			semantic : r.semantic,
1004 			index    : r.index,
1005 			value    : r.value
1006 		}, s);
1007 	}
1008 
1009 	d = SpiderGL.Utility.getDefaultObject(requiredAttribs, dd);
1010 	return d;
1011 };
1012 
1013 SpiderGL.Model.Technique._fixGlobals = function (p, d) {
1014 	var uniformValues = p.getUniformsValues();
1015 	var requiredUniforms = { };
1016 	for (var uniformName in uniformValues) {
1017 		var semanticStr = uniformName;
1018 		var len = semanticStr.length;
1019 		if (len >= 2) {
1020 			if (semanticStr.charAt(0) == "u") {
1021 				var ch = semanticStr.charAt(1);
1022 				if ((ch == "_") && (len > 2)) {
1023 					semanticStr = semanticStr.substring(2);
1024 				}
1025 				else if (ch == semanticStr.charAt(1).toUpperCase()) {
1026 					semanticStr = semanticStr.substring(1);
1027 				}
1028 			}
1029 		}
1030 		var semantic = semanticStr.toUpperCase();
1031 		requiredUniforms[uniformName] = {
1032 			semantic : semantic,
1033 			value    : uniformValues[uniformName]
1034 		};
1035 	};
1036 
1037 	d = SpiderGL.Utility.getDefaultObject(requiredUniforms, d);
1038 	return d;
1039 };
1040 
1041 SpiderGL.Model.Technique._createSimpleDescriptor = function (gl, options) {
1042 	options = SpiderGL.Utility.getDefaultObject({
1043 		name           : "common",
1044 		vertexShader   : null,
1045 		fragmentShader : null,
1046 		attributes     : null,
1047 		uniforms       : null,
1048 		semantic       : { },
1049 		vertexStreams  : null,
1050 		globals        : null,
1051 		options        : null
1052 	}, options);
1053 
1054 	if (options.vertexStreams) {
1055 		options.semantic.vertexStreams = options.vertexStreams;
1056 		delete options.vertexStreams;
1057 	}
1058 
1059 	if (options.globals) {
1060 		options.semantic.globals = options.globals;
1061 		delete options.globals;
1062 	}
1063 
1064 	var d = {
1065 		name     : options.name,
1066 		program  : null,
1067 		semantic : options.semantic
1068 	};
1069 
1070 	if (!gl) {
1071 		return d;
1072 	}
1073 
1074 	var vertexShader = options.vertexShader;
1075 	var fragmentShader = options.fragmentShader;
1076 
1077 	if (!vertexShader || !fragmentShader) {
1078 		return d;
1079 	}
1080 
1081 	if (SpiderGL.Type.isString(vertexShader)) {
1082 		vertexShader = new SpiderGL.WebGL.VertexShader(gl, vertexShader);
1083 	}
1084 	else if (!SpiderGL.Type.instanceOf(vertexShader, SpiderGL.WebGL.VertexShader)) {
1085 		return d;
1086 	}
1087 
1088 	if (SpiderGL.Type.isString(fragmentShader)) {
1089 		fragmentShader = new SpiderGL.WebGL.FragmentShader(gl, fragmentShader);
1090 	}
1091 	else if (!SpiderGL.Type.instanceOf(fragmentShader, SpiderGL.WebGL.FragmentShader)) {
1092 		return d;
1093 	}
1094 
1095 	var program = new SpiderGL.WebGL.Program(gl, {
1096 		shaders    : [ vertexShader, fragmentShader ],
1097 		attributes : options.attributes,
1098 		uniforms   : options.uniforms
1099 	});
1100 
1101 	d.program = program;
1102 
1103 	return d;
1104 };
1105 
1106 SpiderGL.Model.Technique.prototype = {
1107 	get descriptor() {
1108 		return this._descriptor;
1109 	},
1110 
1111 	get isReady() {
1112 		return !!this._descriptor;
1113 	},
1114 
1115 	get gl() {
1116 		return this._gl;
1117 	},
1118 
1119 	get name() {
1120 		return this._descriptor.name;
1121 	},
1122 
1123 	get renderData() {
1124 		return this._renderData;
1125 	},
1126 
1127 	get program() {
1128 		return this._descriptor.program;
1129 	},
1130 
1131 	setUniforms : function (uniforms) {
1132 		this._descriptor.program.setUniforms(uniforms);
1133 	},
1134 
1135 	updateRenderData : function () {
1136 		var d = this._descriptor;
1137 
1138 		var renderData = { };
1139 		this._renderData = renderData;
1140 
1141 		var attributesMap = { };
1142 		renderData.attributesMap = attributesMap;
1143 		var attributesIndices = d.program.getAttributesIndices();
1144 		for (var attribName in d.semantic.vertexStreams) {
1145 			var semanticInfo = d.semantic.vertexStreams[attribName];
1146 			var semanticName = semanticInfo.semantic;
1147 			var attribs = attributesMap[semanticName];
1148 			if (!attribs) {
1149 				attribs = [ ];
1150 				attributesMap[semanticName] = attribs;
1151 			}
1152 			attribs[semanticInfo.index] = {
1153 				index : attributesIndices[attribName],
1154 				value : semanticInfo.value
1155 			};
1156 		}
1157 
1158 		var globalsMap = { };
1159 		renderData.globalsMap = globalsMap;
1160 		for (var uniformName in d.semantic.globals) {
1161 			var semanticInfo = d.semantic.globals[uniformName];
1162 			globalsMap[semanticInfo.semantic] = {
1163 				name  : uniformName,
1164 				value : semanticInfo.value
1165 			};
1166 		}
1167 	}
1168 };
1169 
1170 /**
1171  * Creates a SpiderGL.Model.Technique.
1172  *
1173  * @class The SpiderGL.Model.Technique handles the way a model is drawn.
1174  *
1175  * @augments SpiderGL.Core.ObjectBase
1176  */
1177 SpiderGL.Model.ModelRenderer = function (gl) {
1178 	this._gl = gl;
1179 	this._vertexAttributesCount = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
1180 	this._textureUnitsCount     = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
1181 	this._internalFramebuffer   = new SpiderGL.WebGL.Framebuffer(gl);
1182 	this._reset();
1183 };
1184 
1185 SpiderGL.Model.ModelRenderer.prototype = {
1186 	_reset : function () {
1187 		this._technique        = null;
1188 		this._model            = null;
1189 		this._partName         = null;
1190 		this._chunkName        = null;
1191 		this._primMode         = null;
1192 		this._framebuffer      = null;
1193 
1194 		this._inBegin          = false;
1195 
1196 		this._enabledArrays    = [ ];
1197 		this._boundTextures    = [ ];
1198 		this._attribValues     = [ ];
1199 		this._primitiveStreams = [ ];
1200 
1201 		this._techniqueDirty   = true;
1202 		this._modelDirty       = true;
1203 		this._modelPartDirty   = true;
1204 		this._modelChunkDirty  = true;
1205 		this._primModeDirty    = true;
1206 		this._framebufferDirty = true;
1207 		this._viewportDirty    = true;
1208 
1209 		this._dirty            = true;
1210 	},
1211 
1212 	_resetContext : function () {
1213 		var gl = this._gl;
1214 
1215 		for (var i=0, n=this._vertexAttributesCount; i<n; ++i) {
1216 			gl.disableVertexAttribArray(i);
1217 		}
1218 
1219 		for (var i=this._textureUnitsCount-1; i>=0; --i) {
1220 			gl.activeTexture(gl.TEXTURE0 + i);
1221 			gl.bindTexture(gl.TEXTURE_2D, null);
1222 			gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
1223 		}
1224 
1225 		SpiderGL.WebGL.VertexBuffer .unbind(gl);
1226 		SpiderGL.WebGL.IndexBuffer  .unbind(gl);
1227 		SpiderGL.WebGL.Program      .unbind(gl);
1228 		SpiderGL.WebGL.Framebuffer  .unbind(gl);
1229 	},
1230 
1231 	_update : function () {
1232 		if (!this._dirty) return true;
1233 
1234 		var gl = this._gl;
1235 
1236 		if (this._techniqueDirty) {
1237 			var technique = this._technique;
1238 			if (!technique) return false;
1239 
1240 			var techniqueRenderData = technique.renderData;
1241 			var attributesMap = techniqueRenderData.attributesMap;
1242 			var attribValues = [ ];
1243 			for (var semantic in attributesMap) {
1244 				var attribs = attributesMap[semantic];
1245 				for (var i in attribs) {
1246 					var attribInfo = attribs[i];
1247 					var attribData = null;
1248 					if (attribInfo) {
1249 						attribData = {
1250 							index : attribInfo.index,
1251 							value : attribInfo.value
1252 						};
1253 					}
1254 					attribValues.push(attribData);
1255 				}
1256 			}
1257 			this._attribValues = attribValues;
1258 
1259 			technique.program.bind();
1260 
1261 			this._techniqueDirty = false;
1262 		}
1263 
1264 		if (this._modelDirty) {
1265 			var model = this._model;
1266 			if (!model) return false;
1267 
1268 			// default vertex attributes
1269 			//////////////
1270 			var attribValues = this._attribValues;
1271 			for (var i=0, n=attribValues.length; i<n; ++i) {
1272 				var attribData = attribValues[i];
1273 				if (!attribData) continue;
1274 				gl.vertexAttrib4fv(attribData.index, attribData.value);
1275 			}
1276 			//////////////
1277 
1278 			var modelRenderData = model.renderData;
1279 
1280 			var technique = this._technique;
1281 			if (!technique) return false;
1282 
1283 			var techniqueRenderData = technique.renderData;
1284 			if (!techniqueRenderData) return false;
1285 			var attributesMap = techniqueRenderData.attributesMap;
1286 
1287 			if (this._modelPartDirty) {
1288 				var partName = this._partName;
1289 				if (!partName) return false;
1290 				this._modelPartDirty = false;
1291 			}
1292 
1293 			if (this._modelChunkDirty) {
1294 				var chunkName = this._chunkName;
1295 				if (!chunkName) return false;
1296 
1297 				var partInfo = modelRenderData.partMap[this._partName];
1298 				if (!partInfo) return false;
1299 
1300 				var chunkInfo = partInfo[chunkName];
1301 				if (!chunkInfo) return false;
1302 
1303 				var techniqueInfo = chunkInfo[technique.name];
1304 				if (!techniqueInfo) {
1305 					techniqueInfo = chunkInfo["common"];
1306 				}
1307 				if (!techniqueInfo) return false;
1308 
1309 				// buffered vertex streams
1310 				//////////////
1311 				var enabledArrays = this._enabledArrays;
1312 				for (var i=0, n=enabledArrays.length; i<n; ++i) {
1313 					gl.disableVertexAttribArray(enabledArrays[i]);
1314 				}
1315 				enabledArrays = [ ];
1316 				var streams = techniqueInfo.vertexStreams.buffered;
1317 				for (var i=0, n=streams.length; i<n; ++i) {
1318 					var data   = streams[i];
1319 					var buffer = data.buffer.glBuffer;
1320 					buffer.bind();
1321 
1322 					var infos = data.streams;
1323 					for (var j=0, m=infos.length; j<m; ++j) {
1324 						var info   = infos[j];
1325 						if (!attributesMap[info.semantic] || !attributesMap[info.semantic][info.index]) continue;
1326 						var index  = attributesMap[info.semantic][info.index].index;
1327 						var stream = info.stream;
1328 						stream.index = index;
1329 						enabledArrays.push(index);
1330 						buffer.vertexAttribPointer(stream);
1331 						//gl.enableVertexAttribArray(index);
1332 						//gl.vertexAttribPointer(index, stream.size, stream.glType, stream.normalized, stream.stride, stream.offset);
1333 					}
1334 				}
1335 				this._enabledArrays = enabledArrays;
1336 				//////////////
1337 
1338 				// constant vertex streams
1339 				//////////////
1340 				var infos = techniqueInfo.vertexStreams.constant;
1341 				for (var j=0, n=infos.length; j<n; ++j) {
1342 					var info   = infos[j];
1343 					if (!attributesMap[info.semantic] || !attributesMap[info.semantic][info.index]) continue;
1344 					var index  = attributesMap[info.semantic][info.index].index;
1345 					var stream = info.stream;
1346 					gl.vertexAttrib4fv(index, stream.value);
1347 				}
1348 				//////////////
1349 
1350 				this._modelChunkDirty = false;
1351 			}
1352 
1353 			if (this._primModeDirty) {
1354 				var primMode = this._primMode;
1355 				if (!primMode) return false;
1356 
1357 				var partInfo = modelRenderData.partMap[this._partName];
1358 				if (!partInfo) return false;
1359 
1360 				var chunkInfo = partInfo[this._chunkName];
1361 				if (!chunkInfo) return false;
1362 
1363 				var techniqueInfo = chunkInfo[technique.name];
1364 				if (!techniqueInfo) {
1365 					techniqueInfo = chunkInfo["common"];
1366 				}
1367 				if (!techniqueInfo) return false;
1368 
1369 				var primitiveStreams = techniqueInfo.primitiveStreams[primMode];
1370 				if (!primitiveStreams) return false;
1371 
1372 				// primitive streams
1373 				/////////////////////////////////////////////////
1374 				this._primitiveStreams = primitiveStreams;
1375 
1376 				this._primModeDirty = false;
1377 			}
1378 
1379 			this._modelDirty = false;
1380 		}
1381 
1382 		if (this._framebufferDirty) {
1383 			if (this._framebuffer) {
1384 				this._framebuffer.bind();
1385 			}
1386 			else {
1387 				SpiderGL.WebGL.Framebuffer.unbind(gl);
1388 			}
1389 			this._framebufferDirty = false;
1390 		}
1391 
1392 		if (this._viewportDirty) {
1393 			if (this._framebuffer) {
1394 				if (this._framebuffer.autoViewport) {
1395 					this._framebuffer.applyViewport();
1396 				}
1397 			}
1398 			this._viewportDirty = false;
1399 		}
1400 
1401 		this._dirty = false;
1402 
1403 		return true;
1404 	},
1405 
1406 	get gl() {
1407 		return this._gl;
1408 	},
1409 
1410 	get isValid() {
1411 		return (!!this._gl);
1412 	},
1413 
1414 	destroy : function () {
1415 		this.end();
1416 		this._internalFramebuffer.destroy();
1417 		this._internalFramebuffer = null;
1418 		this._gl = null;
1419 	},
1420 
1421 	begin : function () {
1422 		if (this._inBegin) return;
1423 		this._resetContext();
1424 		this._inBegin = true;
1425 	},
1426 
1427 	end : function () {
1428 		if (!this._inBegin) return;
1429 		this._inBegin = false;
1430 		var gl = this._gl;
1431 
1432 		var enabledArrays = this._enabledArrays;
1433 		for (var i=0, n=enabledArrays.length; i<n; ++i) {
1434 			gl.disableVertexAttribArray(enabledArrays[i]);
1435 		}
1436 
1437 		var boundTextures = this._boundTextures;
1438 		for (var i=0, n=boundTextures.length; i<n; ++i) {
1439 			var tex = boundTextures[i];
1440 			if (!tex) continue;
1441 			if (tex.target == gl.TEXTURE_2D) {
1442 				SpiderGL.WebGL.Texture2D.unbind(gl, tex.unit);
1443 			}
1444 			else if (tex.target == gl.TEXTURE_CUBE_MAP) {
1445 				SpiderGL.WebGL.TextureCubeMap.unbind(gl, tex.unit);
1446 			}
1447 		}
1448 
1449 		if (this._framebuffer) {
1450 			SpiderGL.WebGL.Framebuffer.unbind(this._gl);
1451 		}
1452 
1453 		this._internalFramebuffer.detachAll();
1454 
1455 		this._reset();
1456 		this._resetContext();
1457 	},
1458 
1459 	get isInBegin() {
1460 		return this._inBegin;
1461 	},
1462 
1463 	setTechnique : function (t) {
1464 		if (!this._inBegin) return;
1465 		if (this._technique == t) return;
1466 		this._technique = t;
1467 		this._techniqueDirty = true;
1468 		this._dirty = true;
1469 
1470 		if (!t) {
1471 			SpiderGL.WebGL.Program.unbind(this._gl);
1472 		}
1473 	},
1474 
1475 	get technique() {
1476 		return this._technique;
1477 	},
1478 
1479 	setModel : function (m) {
1480 		if (!this._inBegin) return;
1481 		if (this._model == m) return;
1482 		this._model = m;
1483 		this._modelDirty = true;
1484 		this._modelPartDirty = true;
1485 		this._modelChunkDirty = true;
1486 		this._dirty = true;
1487 	},
1488 
1489 	get model() {
1490 		return this._model;
1491 	},
1492 
1493 	setPart : function (p) {
1494 		if (!this._inBegin) return;
1495 		if (this._part == p) return;
1496 		this._partName = p;
1497 		this._modelPartDirty = true;
1498 		this._modelDirty = true;
1499 		this._dirty = true;
1500 	},
1501 
1502 	get part() {
1503 		return this._partName;
1504 	},
1505 
1506 	setChunk : function (c) {
1507 		if (!this._inBegin) return;
1508 		if (this._chunk == c) return;
1509 		this._chunkName = c;
1510 		this._modelDirty = true;
1511 		this._modelChunkDirty = true;
1512 		this._primModeDirty = true;
1513 		this._dirty = true;
1514 	},
1515 
1516 	get chunk() {
1517 		return this._chunkName;
1518 	},
1519 
1520 	setPrimitiveMode : function (m) {
1521 		if (!this._inBegin) return;
1522 		if (this._primMode == m) return;
1523 		this._primMode = m;
1524 		this._primModeDirty = true;
1525 		this._modelDirty = true;
1526 		this._dirty = true;
1527 	},
1528 
1529 	get primitiveMode() {
1530 		return this._primMode;
1531 	},
1532 
1533 	setUniforms : function (u) {
1534 		if (!this._inBegin) return;
1535 		if (!this._technique) return;
1536 		this._technique.program.setUniforms(u);
1537 	},
1538 
1539 	setDefaultGlobals : function () {
1540 		if (!this._inBegin) return;
1541 
1542 		var technique = this._technique;
1543 		if (!technique) return;
1544 
1545 		var globalsMap = technique.renderData.globalsMap;
1546 		var uniforms = { };
1547 		for (var semantic in globalsMap) {
1548 			var uniformName  = globalsMap[semantic].name;
1549 			var uniformValue = globalsMap[semantic].value;
1550 			uniforms[uniformName] = uniformValue;
1551 		}
1552 
1553 		technique.program.setUniforms(uniforms);
1554 	},
1555 
1556 	setGlobals : function (g) {
1557 		if (!this._inBegin) return;
1558 		if (!g) return;
1559 
1560 		var technique = this._technique;
1561 		if (!technique) return;
1562 
1563 		var globalsMap = technique.renderData.globalsMap;
1564 		var uniforms = { };
1565 		for (var semantic in g) {
1566 			if (!globalsMap[semantic]) continue;
1567 			var uniformName  = globalsMap[semantic].name;
1568 			var uniformValue = g[semantic];
1569 			uniforms[uniformName] = uniformValue;
1570 		}
1571 
1572 		technique.program.setUniforms(uniforms);
1573 	},
1574 
1575 	setFramebuffer : function (fb) {
1576 		if (!this._inBegin) return;
1577 
1578 		//this._internalFramebuffer.detachAll();
1579 		if (this._framebuffer == fb) return;
1580 
1581 		this._framebuffer = fb;
1582 		this._framebufferDirty = true;
1583 		this._viewportDirty = true;
1584 		this._dirty = true;
1585 
1586 		if (fb) {
1587 			fb.bind();
1588 		}
1589 		else {
1590 			SpiderGL.WebGL.Framebuffer.unbind(this._gl);
1591 		}
1592 	},
1593 
1594 	activateOffScreenFramebuffer : function () {
1595 		this.setFramebuffer(this._internalFramebuffer);
1596 	},
1597 
1598 	activateMainFramebuffer : function () {
1599 		return this.setFramebuffer(null);
1600 	},
1601 
1602 	setFramebufferAttachments : function (attachments) {
1603 		if (!this._inBegin) return;
1604 		if (!this._framebuffer) return;
1605 		this._framebuffer.setAttachments(attachments);
1606 		this._framebufferDirty = true;
1607 		this._viewportDirty = true;
1608 	},
1609 
1610 	setColorRenderTarget : function (rt) {
1611 		if (!this._inBegin) return;
1612 		if (!this._framebuffer) return;
1613 		this._framebuffer.colorTarget = rt;
1614 		this._viewportDirty = true;
1615 		this._dirty = true;
1616 	},
1617 
1618 	setDepthRenderTarget : function (rt) {
1619 		if (!this._inBegin) return;
1620 		if (!this._framebuffer) return;
1621 		this._framebuffer.depthTarget = rt;
1622 		this._viewportDirty = true;
1623 		this._dirty = true;
1624 	},
1625 
1626 	setStencilRenderTarget : function (rt) {
1627 		if (!this._inBegin) return;
1628 		if (!this._framebuffer) return;
1629 		this._framebuffer.stencilTarget = rt;
1630 		this._viewportDirty = true;
1631 		this._dirty = true;
1632 	},
1633 
1634 	setDepthStencilRenderTarget : function (rt) {
1635 		if (!this._inBegin) return;
1636 		if (!this._framebuffer) return;
1637 		this._framebuffer.depthStencilTarget = rt;
1638 		this._viewportDirty = true;
1639 		this._dirty = true;
1640 	},
1641 
1642 	clearFramebuffer : function (options) {
1643 		if (!this._inBegin) return;
1644 		if (!options) return;
1645 		var gl   = this._gl;
1646 		var mask = 0;
1647 		if (SpiderGL.Type.isNumber(options)) {
1648 			mask = options;
1649 		}
1650 		else {
1651 			if ("color" in options) {
1652 				var color = options.color;
1653 				if (color) {
1654 					gl.clearColor(color[0], color[1], color[2], color[3]);
1655 				}
1656 				mask |= gl.COLOR_BUFFER_BIT;
1657 			}
1658 			if ("depth" in options) {
1659 				var depth = options.depth;
1660 				if (SpiderGL.Type.isNumber(depth)) {
1661 					gl.clearDepth(depth);
1662 				}
1663 				mask |= gl.DEPTH_BUFFER_BIT;
1664 			}
1665 			if ("stencil" in options) {
1666 				var stencil = options.stencil;
1667 				if (SpiderGL.Type.isNumber(stencil)) {
1668 					gl.clearStencil(stencil);
1669 				}
1670 				mask |= gl.Stencil_BUFFER_BIT;
1671 			}
1672 		}
1673 		if (mask) {
1674 			var fb = this._framebuffer;
1675 			if (fb) {
1676 				fb.clear(mask);
1677 			}
1678 			else {
1679 				gl.clear(mask);
1680 			}
1681 		}
1682 	},
1683 
1684 	setViewport : function (x, y, width, height) {
1685 		if (!this._inBegin) return;
1686 		var gl = this._gl;
1687 		gl.viewport(x, y, width, height);
1688 	},
1689 
1690 	setTexture : function (unit, texture) {
1691 		if (texture) {
1692 			texture.bind(unit);
1693 		}
1694 		else {
1695 			var gl = this._gl;
1696 			SpiderGL.WebGL.Texture2D.unbind(gl, unit);
1697 			SpiderGL.WebGL.TextureCubeMap.unbind(gl, unit);
1698 		}
1699 	},
1700 
1701 	get canRender() {
1702 		return (!!this._inBegin && !!this._technique && !!this._model && !!this._partName && !!this._chunkName && !!this._primMode);
1703 	},
1704 
1705 	render : function () {
1706 		if (!this.canRender) return;
1707 		if (!this._update()) return;
1708 
1709 		var gl = this._gl;
1710 
1711 		var primitiveStreams = this._primitiveStreams;
1712 
1713 		var bufferedStreams = primitiveStreams.buffered;
1714 		var arrayStreams    = primitiveStreams.array;
1715 
1716 		// buffered
1717 		//////////////
1718 		for (var i=0, n=bufferedStreams.length; i<n; ++i) {
1719 			var data = bufferedStreams[i];
1720 			var buffer = data.buffer.glBuffer;
1721 			buffer.bind();
1722 
1723 			var infos = data.streams;
1724 			for (var j=0, m=infos.length; j<m; ++j) {
1725 				var stream = infos[j];
1726 				//gl.drawElements(stream.glMode, stream.count, stream.glType, stream.offset);
1727 				buffer.drawElements(stream);
1728 			}
1729 		}
1730 		//////////////
1731 
1732 		// array
1733 		//////////////
1734 		for (var j=0, n=arrayStreams.length; j<n; ++j) {
1735 			var stream = arrayStreams[j];
1736 			gl.drawArrays(stream.glMode, stream.first, stream.count);
1737 		}
1738 		//////////////
1739 	},
1740 
1741 	renderModelPart : function(partName) {
1742 		var part = this.model.descriptor.logic.parts[partName];
1743 		this.setPart(partName);
1744 		for (var c in part.chunks) {
1745 			var chunkName = part.chunks[c];
1746 			this.setChunk(chunkName);
1747 			this.render();
1748 		}
1749 	},
1750 
1751 	renderModel : function() {
1752 		var parts = this.model.descriptor.logic.parts;
1753 		for (var partName in parts) {
1754 			var part = parts[partName];
1755 			this.setPart(partName);
1756 			for (var c in part.chunks) {
1757 				var chunkName = part.chunks[c];
1758 				this.setChunk(chunkName);
1759 				this.render();
1760 			}
1761 		}
1762 	}
1763 };
1764