gluDrawUtil.js (18220B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ 20 21 'use strict'; 22 goog.provide('framework.opengl.gluDrawUtil'); 23 goog.require('framework.opengl.gluShaderProgram'); 24 25 goog.scope(function() { 26 27 var gluDrawUtil = framework.opengl.gluDrawUtil; 28 var gluShaderProgram = framework.opengl.gluShaderProgram; 29 30 /** 31 * Description of a vertex array binding 32 * @constructor 33 * @param {number} type GL gluDrawUtil.Type of data 34 * @param {(number|undefined)} location Binding location 35 * @param {number} components Number of components per vertex 36 * @param {number} elements Number of elements in the array 37 * @param {Array<number>} data Source data 38 * @param {number=} stride 39 * @param {number=} offset 40 */ 41 gluDrawUtil.VertexArrayBinding = function(type, location, components, elements, data, stride, offset) { 42 this.type = type; 43 this.location = location === undefined ? -1 : location; 44 this.components = components; 45 this.elements = elements; 46 this.data = data; 47 /** @type {?string} */ this.name = null; 48 this.stride = stride || 0; 49 this.offset = offset || 0; 50 }; 51 52 /** 53 * Description of a vertex array binding 54 * @param {gluDrawUtil.BindingPoint} binding 55 * @param {gluDrawUtil.VertexArrayPointer} pointer 56 * @param {number=} dataType GL Data Type 57 * @return {gluDrawUtil.VertexArrayBinding} 58 */ 59 gluDrawUtil.vabFromBindingPointAndArrayPointer = function(binding, pointer, dataType) { 60 var type = dataType === undefined ? gl.FLOAT : dataType; 61 var location = binding.location; 62 var components = pointer.numComponents; 63 var elements = pointer.numElements; 64 var data = pointer.data; 65 var vaBinding = new gluDrawUtil.VertexArrayBinding(type, location, components, elements, data); 66 vaBinding.componentType = pointer.componentType; 67 vaBinding.name = binding.name; 68 vaBinding.convert = pointer.convert; 69 vaBinding.stride = pointer.stride; 70 return vaBinding; 71 }; 72 73 /** 74 * ! Lower named bindings to locations and eliminate bindings that are not used by program. 75 * @param {WebGL2RenderingContext} gl WebGL context 76 * @param {WebGLProgram} program 77 * @param {Array} inputArray - Array with the named binding locations 78 * @param {Array=} outputArray - Array with the lowered locations 79 * @return {Array} outputArray 80 */ 81 gluDrawUtil.namedBindingsToProgramLocations = function(gl, program, inputArray, outputArray) { 82 outputArray = outputArray || []; 83 84 for (var i = 0; i < inputArray.length; i++) { 85 var cur = inputArray[i]; 86 if (cur.name) { 87 //assert(binding.location >= 0); 88 var location = gl.getAttribLocation(program, cur.name); 89 if (location >= 0) { 90 if (cur.location >= 0) 91 location += cur.location; 92 // Add binding.location as an offset to accomodate matrices. 93 outputArray.push(new gluDrawUtil.VertexArrayBinding(cur.type, location, cur.components, cur.elements, cur.data, cur.stride, cur.offset)); 94 } 95 } else { 96 outputArray.push(cur); 97 } 98 } 99 100 return outputArray; 101 }; 102 103 /** 104 * Creates vertex buffer, binds it and draws elements 105 * @param {WebGL2RenderingContext} gl WebGL context 106 * @param {WebGLProgram} program ID, vertexProgramID 107 * @param {Array<gluDrawUtil.VertexArrayBinding>} vertexArrays 108 * @param {gluDrawUtil.PrimitiveList} primitives to gluDrawUtil.draw 109 * @param { {beforeDrawCall:function(), afterDrawCall:function()}=} callback 110 */ 111 gluDrawUtil.draw = function(gl, program, vertexArrays, primitives, callback) { 112 /** TODO: finish implementation */ 113 /** @type {Array<WebGLBuffer>} */ var objects = []; 114 115 // Lower bindings to locations 116 vertexArrays = gluDrawUtil.namedBindingsToProgramLocations(gl, program, vertexArrays); 117 118 for (var i = 0; i < vertexArrays.length; i++) { 119 /** @type {WebGLBuffer} */ var buffer = gluDrawUtil.vertexBuffer(gl, vertexArrays[i]); 120 objects.push(buffer); 121 } 122 123 if (primitives.indices) { 124 /** @type {WebGLBuffer} */ var elemBuffer = gluDrawUtil.indexBuffer(gl, primitives); 125 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer); 126 127 if (callback) 128 callback.beforeDrawCall(); 129 130 gluDrawUtil.drawIndexed(gl, primitives, 0); 131 132 if (callback) 133 callback.afterDrawCall(); 134 135 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 136 } else { 137 if (callback) 138 callback.beforeDrawCall(); 139 140 gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, primitives.type), 0, primitives.numElements); 141 142 if (callback) 143 callback.afterDrawCall(); 144 } 145 146 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'drawArrays', false, true); 147 for (var i = 0; i < vertexArrays.length; i++) { 148 gl.disableVertexAttribArray(vertexArrays[i].location); 149 } 150 gl.bindBuffer(gl.ARRAY_BUFFER, null); 151 }; 152 153 /** 154 * Creates vertex buffer, binds it and draws elements 155 * @param {WebGL2RenderingContext} gl WebGL context 156 * @param {gluDrawUtil.PrimitiveList} primitives Primitives to gluDrawUtil.draw 157 * @param {number} offset 158 */ 159 gluDrawUtil.drawIndexed = function(gl, primitives, offset) { 160 /** @type {number} */ var mode = gluDrawUtil.getPrimitiveGLType(gl, primitives.type); 161 /** TODO: C++ implementation supports different index types, we use only int16. 162 Could it cause any issues? 163 164 deUint32 indexGLType = getIndexGLType(primitives.indexType); 165 */ 166 167 gl.drawElements(mode, primitives.indices.length, gl.UNSIGNED_SHORT, offset); 168 }; 169 170 /** 171 * Enums for primitive types 172 * @enum 173 */ 174 gluDrawUtil.primitiveType = { 175 TRIANGLES: 0, 176 TRIANGLE_STRIP: 1, 177 TRIANGLE_FAN: 2, 178 179 LINES: 3, 180 LINE_STRIP: 4, 181 LINE_LOOP: 5, 182 183 POINTS: 6, 184 185 PATCHES: 7 186 }; 187 188 /** 189 * get GL type from primitive type 190 * @param {WebGL2RenderingContext} gl WebGL context 191 * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType 192 * @return {number} GL primitive type 193 */ 194 gluDrawUtil.getPrimitiveGLType = function(gl, type) { 195 switch (type) { 196 case gluDrawUtil.primitiveType.TRIANGLES: return gl.TRIANGLES; 197 case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return gl.TRIANGLE_STRIP; 198 case gluDrawUtil.primitiveType.TRIANGLE_FAN: return gl.TRIANGLE_FAN; 199 case gluDrawUtil.primitiveType.LINES: return gl.LINES; 200 case gluDrawUtil.primitiveType.LINE_STRIP: return gl.LINE_STRIP; 201 case gluDrawUtil.primitiveType.LINE_LOOP: return gl.LINE_LOOP; 202 case gluDrawUtil.primitiveType.POINTS: return gl.POINTS; 203 // case gluDrawUtil.primitiveType.PATCHES: return gl.PATCHES; 204 default: 205 throw new Error('Unknown primitive type ' + type); 206 } 207 }; 208 209 /** 210 * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Points 211 * @param {number} numElements 212 */ 213 gluDrawUtil.pointsFromElements = function(numElements) { 214 return new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.POINTS, numElements); 215 }; 216 217 /** 218 * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Triangles 219 * @param {Array<number>} indices 220 */ 221 gluDrawUtil.triangles = function(indices) { 222 return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.TRIANGLES, indices); 223 }; 224 225 /** 226 * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Patches 227 * @param {Array<number>} indices 228 */ 229 gluDrawUtil.patches = function(indices) { 230 return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.PATCHES, indices); 231 }; 232 233 /** 234 * Creates primitive list for Triangles or Patches, depending on type 235 * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType 236 * @param {number} numElements 237 * @constructor 238 */ 239 gluDrawUtil.PrimitiveList = function(type, numElements) { 240 this.type = type; 241 this.indices = 0; 242 this.numElements = numElements; 243 }; 244 245 /** 246 * @param {gluDrawUtil.primitiveType} type 247 * @param {Array<number>} indices 248 * @return {gluDrawUtil.PrimitiveList} 249 */ 250 gluDrawUtil.newPrimitiveListFromIndices = function(type, indices) { 251 /** @type {gluDrawUtil.PrimitiveList} */ var primitiveList = new gluDrawUtil.PrimitiveList(type, 0); 252 primitiveList.indices = indices; 253 return primitiveList; 254 }; 255 256 /** 257 * Create Element Array Buffer 258 * @param {WebGL2RenderingContext} gl WebGL context 259 * @param {gluDrawUtil.PrimitiveList} primitives to construct the buffer from 260 * @return {WebGLBuffer} indexObject buffer with elements 261 */ 262 gluDrawUtil.indexBuffer = function(gl, primitives) { 263 /** @type {WebGLBuffer} */ var indexObject = gl.createBuffer(); 264 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject); 265 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true); 266 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(primitives.indices), gl.STATIC_DRAW); 267 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true); 268 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 269 return indexObject; 270 }; 271 272 /** 273 * Create Array Buffer 274 * @param {WebGL2RenderingContext} gl WebGL context 275 * @param {gluDrawUtil.VertexArrayBinding} vertexArray primitives, Array buffer descriptor 276 * @return {WebGLBuffer} buffer of vertices 277 */ 278 gluDrawUtil.vertexBuffer = function(gl, vertexArray) { 279 /** @type {goog.TypedArray} */ var typedArray; 280 switch (vertexArray.type) { 281 case gl.BYTE: typedArray = new Int8Array(vertexArray.data); break; 282 case gl.UNSIGNED_BYTE: typedArray = new Uint8Array(vertexArray.data); break; 283 case gl.SHORT: typedArray = new Int16Array(vertexArray.data); break; 284 case gl.UNSIGNED_SHORT: typedArray = new Uint16Array(vertexArray.data); break; 285 case gl.INT: typedArray = new Int32Array(vertexArray.data); break; 286 case gl.UNSIGNED_INT: typedArray = new Uint32Array(vertexArray.data); break; 287 default: typedArray = new Float32Array(vertexArray.data); break; 288 } 289 290 /** @type {WebGLBuffer} */ var buffer = gl.createBuffer(); 291 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 292 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true); 293 gl.bufferData(gl.ARRAY_BUFFER, typedArray, gl.STATIC_DRAW); 294 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true); 295 gl.enableVertexAttribArray(vertexArray.location); 296 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'enableVertexAttribArray', false, true); 297 if (vertexArray.type === gl.FLOAT) { 298 gl.vertexAttribPointer(vertexArray.location, vertexArray.components, vertexArray.type, false, vertexArray.stride, vertexArray.offset); 299 } else { 300 gl.vertexAttribIPointer(vertexArray.location, vertexArray.components, vertexArray.type, vertexArray.stride, vertexArray.offset); 301 } 302 assertMsgOptions(gl.getError() === gl.NO_ERROR, 'vertexAttribPointer', false, true); 303 return buffer; 304 }; 305 306 /** 307 * @param {Array<number>} rgba 308 * @constructor 309 */ 310 gluDrawUtil.Pixel = function(rgba) { 311 this.rgba = rgba; 312 }; 313 314 gluDrawUtil.Pixel.prototype.getRed = function() { 315 return this.rgba[0]; 316 }; 317 gluDrawUtil.Pixel.prototype.getGreen = function() { 318 return this.rgba[1]; 319 }; 320 gluDrawUtil.Pixel.prototype.getBlue = function() { 321 return this.rgba[2]; 322 }; 323 gluDrawUtil.Pixel.prototype.getAlpha = function() { 324 return this.rgba[3]; 325 }; 326 gluDrawUtil.Pixel.prototype.equals = function(otherPixel) { 327 return this.rgba[0] == otherPixel.rgba[0] && 328 this.rgba[1] == otherPixel.rgba[1] && 329 this.rgba[2] == otherPixel.rgba[2] && 330 this.rgba[3] == otherPixel.rgba[3]; 331 }; 332 333 /** 334 * @constructor 335 */ 336 gluDrawUtil.Surface = function() { 337 }; 338 339 gluDrawUtil.Surface.prototype.readSurface = function(gl, x, y, width, height) { 340 this.buffer = new Uint8Array(width * height * 4); 341 gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this.buffer); 342 this.x = x; 343 this.y = y; 344 this.width = width; 345 this.height = height; 346 return this.buffer; 347 }; 348 349 gluDrawUtil.Surface.prototype.getPixel = function(x, y) { 350 /** @type {number} */ var base = (x + y * this.width) * 4; 351 /** @type {Array<number>} */ 352 var rgba = [ 353 this.buffer[base], 354 this.buffer[base + 1], 355 this.buffer[base + 2], 356 this.buffer[base + 3] 357 ]; 358 return new gluDrawUtil.Pixel(rgba); 359 }; 360 361 gluDrawUtil.Surface.prototype.getPixelUintRGB8 = function(x, y) { 362 /** @type {number} */ var base = (x + y * this.width) * 4; 363 /** @type {number} */ 364 return (this.buffer[base] << 16) + 365 (this.buffer[base + 1] << 8) + 366 this.buffer[base + 2]; 367 }; 368 369 /** 370 * @enum 371 */ 372 gluDrawUtil.VertexComponentType = { 373 // Standard types: all conversion types apply. 374 VTX_COMP_UNSIGNED_INT8: 0, 375 VTX_COMP_UNSIGNED_INT16: 1, 376 VTX_COMP_UNSIGNED_INT32: 2, 377 VTX_COMP_SIGNED_INT8: 3, 378 VTX_COMP_SIGNED_INT16: 4, 379 VTX_COMP_SIGNED_INT32: 5, 380 381 // Special types: only CONVERT_NONE is allowed. 382 VTX_COMP_FIXED: 6, 383 VTX_COMP_HALF_FLOAT: 7, 384 VTX_COMP_FLOAT: 8 385 }; 386 387 /** 388 * @enum 389 */ 390 gluDrawUtil.VertexComponentConversion = { 391 VTX_COMP_CONVERT_NONE: 0, //!< No conversion: integer types, or floating-point values. 392 VTX_COMP_CONVERT_NORMALIZE_TO_FLOAT: 1, //!< Normalize integers to range [0,1] or [-1,1] depending on type. 393 VTX_COMP_CONVERT_CAST_TO_FLOAT: 2 //!< Convert to floating-point directly. 394 }; 395 396 /** 397 * gluDrawUtil.VertexArrayPointer 398 * @constructor 399 * @param {gluDrawUtil.VertexComponentType} componentType_ 400 * @param {gluDrawUtil.VertexComponentConversion} convert_ 401 * @param {number} numComponents_ 402 * @param {number} numElements_ 403 * @param {number} stride_ 404 * @const @param {Array<number>} data_ 405 */ 406 gluDrawUtil.VertexArrayPointer = function(componentType_, convert_, numComponents_, numElements_, stride_, data_) { 407 this.componentType = componentType_; 408 this.convert = convert_; 409 this.numComponents = numComponents_; 410 this.numElements = numElements_; 411 this.stride = stride_; 412 this.data = data_; 413 }; 414 415 /** 416 * gluDrawUtil.BindingPoint 417 * @constructor 418 * @param {string} name 419 * @param {number} location 420 * @param {number=} offset 421 */ 422 gluDrawUtil.BindingPoint = function(name, location, offset) { 423 /** @type {string} */ this.name = name; 424 /** @type {number} */ this.location = location; 425 /** @type {number} */ this.offset = offset || 0; 426 }; 427 428 /** 429 * bindingPointFromLocation 430 * @param {number} location 431 * return {gluDrawUtil.BindingPoint} 432 */ 433 gluDrawUtil.bindingPointFromLocation = function(location) { 434 return new gluDrawUtil.BindingPoint('', location); 435 }; 436 437 /** 438 * bindingPointFromName 439 * @param {string} name 440 * @param {number=} location 441 * return {gluDrawUtil.BindingPoint} 442 */ 443 gluDrawUtil.bindingPointFromName = function(name, location) { 444 location = location === undefined ? -1 : location; 445 return new gluDrawUtil.BindingPoint(name, location); 446 }; 447 448 /** 449 * @param {string} name 450 * @param {number} numComponents 451 * @param {number} numElements 452 * @param {number} stride 453 * @param {Array<number>} data 454 * @return {gluDrawUtil.VertexArrayBinding} 455 */ 456 gluDrawUtil.newInt32VertexArrayBinding = function(name, numComponents, numElements, stride, data) { 457 var bindingPoint = gluDrawUtil.bindingPointFromName(name); 458 var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_SIGNED_INT32, 459 gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); 460 return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.INT); 461 }; 462 463 /** 464 * @param {string} name 465 * @param {number} numComponents 466 * @param {number} numElements 467 * @param {number} stride 468 * @param {Array<number>} data 469 * @return {gluDrawUtil.VertexArrayBinding} 470 */ 471 gluDrawUtil.newUint32VertexArrayBinding = function(name, numComponents, numElements, stride, data) { 472 var bindingPoint = gluDrawUtil.bindingPointFromName(name); 473 var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_UNSIGNED_INT32, 474 gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); 475 return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.UNSIGNED_INT); 476 }; 477 478 /** 479 * @param {string} name 480 * @param {number} numComponents 481 * @param {number} numElements 482 * @param {number} stride 483 * @param {Array<number>} data 484 * @return {gluDrawUtil.VertexArrayBinding} 485 */ 486 gluDrawUtil.newFloatVertexArrayBinding = function(name, numComponents, numElements, stride, data) { 487 var bindingPoint = gluDrawUtil.bindingPointFromName(name); 488 var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT, 489 gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data); 490 return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer); 491 }; 492 493 /** 494 * @param {string} name 495 * @param {number} column 496 * @param {number} rows 497 * @param {number} numElements 498 * @param {number} stride 499 * @param {Array<number>} data 500 * @return {gluDrawUtil.VertexArrayBinding} 501 */ 502 gluDrawUtil.newFloatColumnVertexArrayBinding = function(name, column, rows, numElements, stride, data) { 503 var bindingPoint = gluDrawUtil.bindingPointFromName(name); 504 bindingPoint.location = column; 505 var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT, 506 gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, rows, numElements, stride, data); 507 return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer); 508 }; 509 510 });