├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── __tests__ └── browser │ ├── animation │ ├── fs.glsl │ ├── index.html │ └── vs.glsl │ ├── basic │ ├── fs.glsl │ ├── index.html │ └── vs.glsl │ ├── feedback │ ├── fs.glsl │ ├── index.html │ └── vs.glsl │ ├── particle │ ├── index.html │ ├── particle_renderer_fs.glsl │ ├── particle_renderer_vs.glsl │ ├── particle_updater_fs.glsl │ └── particle_updater_vs.glsl │ ├── texture │ ├── fs.glsl │ ├── index.html │ ├── texture-300x300.png │ └── vs.glsl │ └── uniformbufferobject │ ├── fs.glsl │ ├── index.html │ └── vs.glsl ├── build └── xenogl.min.js ├── docs ├── .nojekyll ├── assets │ ├── css │ │ ├── main.css │ │ └── main.css.map │ ├── images │ │ ├── icons.png │ │ ├── icons@2x.png │ │ ├── widgets.png │ │ └── widgets@2x.png │ └── js │ │ ├── main.js │ │ └── search.js ├── classes │ ├── _buffer_.arraybuffer.html │ ├── _buffer_.bufferbase.html │ ├── _buffer_.elementarraybuffer.html │ ├── _buffer_.uniformbuffer.html │ ├── _shader_program_.fragmentshader.html │ ├── _shader_program_.program.html │ ├── _shader_program_.shaderbase.html │ ├── _shader_program_.vertexshader.html │ ├── _texture_.texture2d.html │ ├── _texture_.texturebase.html │ ├── _transform_feedback_.transformfeedback.html │ ├── _uniform_buffer_object_.uniformbufferobject.html │ ├── _variable_.attribute.html │ ├── _variable_.uniform.html │ ├── _vertex_array_object_.vertexarrayobject.html │ └── _webgl2_.webgl2.html ├── globals.html ├── index.html ├── interfaces │ ├── _buffer_.buffer.html │ └── _texture_.texture.html └── modules │ ├── _buffer_.html │ ├── _constants_.html │ ├── _index_.html │ ├── _shader_program_.html │ ├── _texture_.html │ ├── _transform_feedback_.html │ ├── _uniform_buffer_object_.html │ ├── _utils_.html │ ├── _variable_.html │ ├── _vertex_array_object_.html │ └── _webgl2_.html ├── jest.config.js ├── lib ├── buffer.d.ts ├── buffer.js ├── constants.d.ts ├── constants.js ├── index.d.ts ├── index.js ├── shader_program.d.ts ├── shader_program.js ├── texture.d.ts ├── texture.js ├── transform_feedback.d.ts ├── transform_feedback.js ├── transformfeedback.d.ts ├── transformfeedback.js ├── uniform_buffer_object.d.ts ├── uniform_buffer_object.js ├── utils.d.ts ├── utils.js ├── variable.d.ts ├── variable.js ├── vertex_array_object.d.ts ├── vertex_array_object.js ├── webgl2.d.ts └── webgl2.js ├── package-lock.json ├── package.json ├── src ├── buffer.ts ├── constants.ts ├── index.ts ├── shader_program.ts ├── texture.ts ├── transform_feedback.ts ├── uniform_buffer_object.ts ├── utils.ts ├── variable.ts ├── vertex_array_object.ts └── webgl2.ts ├── tsconfig.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | charset = utf-8 7 | 8 | indent_style = space 9 | indent_size = 2 10 | 11 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea 3 | *.iml 4 | out 5 | gen 6 | *~ 7 | .fuse_hidden* 8 | .directory 9 | .Trash-* 10 | .nfs* 11 | .DS_Store 12 | .AppleDouble 13 | .LSOverride 14 | Icon 15 | ._* 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | logs 29 | *.log 30 | npm-debug.log* 31 | yarn-debug.log* 32 | yarn-error.log* 33 | pids 34 | *.pid 35 | *.seed 36 | *.pid.lock 37 | lib-cov 38 | coverage 39 | .nyc_output 40 | .grunt 41 | bower_components 42 | .lock-wscript 43 | build/Release 44 | node_modules/ 45 | jspm_packages/ 46 | typings/ 47 | .npm 48 | .eslintcache 49 | .node_repl_history 50 | *.tgz 51 | .yarn-integrity 52 | .env 53 | .next 54 | Thumbs.db 55 | ehthumbs.db 56 | ehthumbs_vista.db 57 | *.stackdump 58 | [Dd]esktop.ini 59 | $RECYCLE.BIN/ 60 | *.cab 61 | *.msi 62 | *.msm 63 | *.msp 64 | *.lnk 65 | .idea 66 | *.iml 67 | out 68 | gen 69 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.0 4 | 5 | * \[Breaking Change\] Buffers treat dataOrLength as length rather than byte length when its value is number. 6 | 7 | * \[Breaking Change\] TransformFeedback.feedback() receives an array of targetBuffers rather than single buffer. 8 | 9 | * Support textures. 10 | 11 | ## 0.0.1 12 | 13 | * Initial release with basic functions. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Koto Furumiya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XenoGL 2 | 3 | XenoGL is a lightweight and Object-Oriented wrapper for WebGL2. 4 | 5 | ## Unstable 6 | 7 | XenoGL is under unstable yet. APIs may be going to change, which breaks your code. **Do not use XenoGL for production softwares**. 8 | 9 | ## Install without Node.js 10 | 11 | Download the zip file from [Release page on GitHub](https://github.com/kotofurumiya/xenogl/releases) and unzip the file. 12 | 13 | Copy **build/xenogl.min.js** to your directory and append below code to your HTML file: 14 | 15 | ```html 16 | 17 | 20 | ``` 21 | 22 | ## Install with Node.js 23 | 24 | Run the install command. 25 | 26 | ``` 27 | $ npm install xenogl --save 28 | ``` 29 | 30 | Then import xenogl in JavaScript file. 31 | 32 | ```javascript 33 | const XenoGL = require('xenogl'); 34 | ``` 35 | 36 | ## Basic usage 37 | 38 | First, create a WebGL2 context from a canvas. 39 | 40 | ```javascript 41 | // create a canvas. 42 | const canvas = document.body.createElement('canvas'); 43 | canvas.width = 500; 44 | canvas.height = 500; 45 | document.body.appendChild(canvas); 46 | 47 | // create a context. 48 | const xgl = new XenoGL.WebGL2(canvas); 49 | ``` 50 | 51 | Next, create two shaders and a program. And add the program to the context. 52 | 53 | ```javascript 54 | // load source as you like. 55 | const vertexShaderSource = await fetch('vertex_shader.glsl').then((res) => res.text()); 56 | const fragmentShaderSource = await fetch('fragment_shader.glsl').then((res) => res.text()); 57 | 58 | // create shaders. 59 | const vertexShader = new XenoGL.VertexShader(vertexShaderSource); 60 | const fragmentShader = new XenoGL.FragmentShader(fragmentShaderSource); 61 | 62 | // create a program. 63 | const program = new XenoGL.Program({ 64 | vertexShader: vertexShader, 65 | fragmentShader: fragmentShader 66 | }); 67 | 68 | // add the program to the context. 69 | xgl.addProgram(program); 70 | ``` 71 | 72 | You need data to draw. For example, vertex positions and colors. 73 | 74 | ```javascript 75 | const vertices = new Float32Array([ 76 | -0.5, 0.5, 0.0, 77 | -0.5, -0.5, 0.0, 78 | 0.5, 0.5, 0.0, 79 | -0.5, -0.5, 0.0, 80 | 0.5, -0.5, 0.0, 81 | 0.5, 0.5, 0.0 82 | ]); 83 | 84 | const colors = new Float32Array([ 85 | 1.0, 0.0, 0.0, 1.0, 86 | 0.0, 1.0, 0.0, 1.0, 87 | 0.0, 0.0, 1.0, 1.0, 88 | 0.0, 1.0, 0.0, 1.0, 89 | 0.0, 0.0, 0.0, 1.0, 90 | 0.0, 0.0, 1.0, 1.0 91 | ]); 92 | ``` 93 | 94 | Then, create a buffer from data. 95 | 96 | ```javascript 97 | // create attributes which is defined in shaders. 98 | const positionAttribute = new XenoGL.Attribute('vertexPosition', 3); 99 | const colorAttribute = new XenoGL.Attribute('color', 4); 100 | 101 | // create buffers with data and attributes. 102 | const positionBuffer = new XenoGL.ArrayBuffer({ 103 | dataOrLength: vertices, 104 | attributes: [positionAttribute], 105 | dataType: XenoGL.FLOAT 106 | }); 107 | 108 | const colorBuffer = new XenoGL.ArrayBuffer({ 109 | dataOrLength: colors, 110 | attributes: [colorAttribute], 111 | dataType: XenoGL.FLOAT 112 | }); 113 | 114 | // add buffers to the program. 115 | program.addBuffer(positionBuffer); 116 | program.addBuffer(colorBuffer); 117 | ``` 118 | 119 | Finally, draw it! 120 | 121 | ```javascript 122 | xgl.draw(XenoGL.TRIANGLES); 123 | ``` 124 | 125 | That's all. 126 | 127 | ## Program 128 | 129 | You can use multiple programs. 130 | 131 | To switch programs, use `activateProgram`. 132 | 133 | ```javascript 134 | xgl.addProgram(updaterProgram); 135 | xgl.addProgram(rendererProgram); 136 | 137 | xgl.activateProgram(rendererProgram); 138 | ``` 139 | 140 | `activateProgram` is a very heavy operation. If you switch programs every frames, it causes performance issues. Because it toggles every attributes on buffers. 141 | 142 | If you want just change the program without toggling attributes, use `useProgram` instead. 143 | 144 | But if you don't have knowledge about OpenGL/WebGL, you should use `activateProgram`. 145 | 146 | ## Buffer 147 | 148 | You can send data to buffers. 149 | 150 | ```javascript 151 | const positionBuffer = new XenoGL.ArrayBuffer({ 152 | attributes: [positionAttribute], 153 | dataType: XenoGL.FLOAT 154 | }); 155 | 156 | program.addBuffer(positionBuffer); 157 | 158 | positionBuffer.bufferData(new Float32Array([1.0, 1.0, 1.0])); 159 | ``` 160 | 161 | ## Interleaved buffer 162 | 163 | To make a buffer interleaved, pass an array of attributes to constructor of ArrayBuffer. 164 | 165 | ```javascript 166 | const vertices = new Float32Array([ 167 | -30.0, 30.0, 0.0, // position 168 | 0.0, 1.0, 0.0, 1.0, // color 169 | -30.0, -30.0, 0.0, 170 | 1.0, 0.0, 0.0, 1.0, 171 | 30.0, 30.0, 0.0, 172 | 1.0, 0.0, 0.0, 1.0, 173 | 30.0, -30.0, 0.0, 174 | 0.0, 0.0, 1.0, 1.0 175 | ]); 176 | 177 | const positionAttribute = new XenoGL.Attribute('vertexPosition', 3); 178 | const colorAttribute = new XenoGL.Attribute('color', 4); 179 | 180 | const buffer = new XenoGL.ArrayBuffer({ 181 | dataOrLength: vertices, 182 | attributes: [positionAttribute, colorAttribute], 183 | dataType: XenoGL.FLOAT, 184 | usage: XenoGL.DYNAMIC_DRAW 185 | }); 186 | ``` 187 | 188 | XenoGL detect stride and offset automatically and make the buffer interleaved. 189 | 190 | ## Index buffer 191 | 192 | You can create a index buffer by using `XenoGL.ElementArrayBuffer` object. 193 | 194 | ```javascript 195 | const indices = new Uint16Array([0, 1, 2, 1, 3, 2]); 196 | 197 | const indexBuffer = new XenoGL.ElementArrayBuffer({ 198 | dataOrLength: indices, 199 | dataType: XenoGL.UNSIGNED_SHORT, 200 | usage: XenoGL.DYNAMIC_DRAW 201 | }); 202 | 203 | program.addBuffer(indexBuffer); 204 | ``` 205 | 206 | An ElementArrayBuffer object is treated as an index buffer when it is added to the program. 207 | 208 | When you add multiple ElementArrayBuffer to the program, latest one is used as an index buffer. 209 | 210 | If you need to choose an index buffer manually, use `program.activateElemntArrayBuffer()`. 211 | 212 | ```javascript 213 | program.activateElementArrayBuffer(firstBuffer); 214 | ``` 215 | 216 | ## Other buffers 217 | 218 | Not supported yet. Stay tuned. 219 | 220 | ## Uniform variables 221 | 222 | To create uniform variables, use `XenoGL.Uniform` and add it to the program. 223 | 224 | ```javascript 225 | const modelUniform = new XenoGL.Uniform('model'); 226 | const viewUniform = new XenoGL.Uniform('view'); 227 | const projectionUniform = new XenoGL.Uniform('projection'); 228 | 229 | modelUniform.setMatrix(model); 230 | projectionUniform.setMatrix(projection); 231 | 232 | program.addUniform(modelUniform); 233 | program.addUniform(viewUniform); 234 | program.addUniform(projectionUniform); 235 | ``` 236 | 237 | `XenoGL.Uniform` object has `setValue(value, type)`, `setVector(vector, type)` and `setMatrix(matrix)` to apply a value. `type` can be XenoGL.FLOAT, XenoGL.UNSIGNED_SHORT and other data types. 238 | 239 | Don't forget to add an uniform to the program. 240 | 241 | ## Vertex Array Objects 242 | 243 | XenoGL supports Vertex Array Object(VAO). 244 | 245 | ```javascript 246 | const buffer = new XenoGL.ArrayBuffer({ 247 | dataOrLength: particleInitialDataF32, 248 | attributes: [positionAttr, velocityAttr, ageAttr, lifeAttr], 249 | dataType: XenoGL.FLOAT, 250 | usage: XenoGL.DYNAMIC_COPY 251 | }); 252 | 253 | // 2nd arg is optional. 254 | const vao = new XenoGL.VertexArrayObject(buffer, { 255 | dataOrLength: particleInitialDataF32, // initial data 256 | attributes: [positionAttr, velocityAttr] // attributes to enable 257 | }); 258 | 259 | // add it to the program. 260 | program.addVertexArrayObject(vao); 261 | ``` 262 | 263 | If you activate another VAO, use `program.activateVertexArrayObject`. 264 | 265 | ```javascript 266 | program.activateVertexArrayObject(vao); 267 | ``` 268 | 269 | ## Uniform Buffer Object 270 | 271 | Uniform Buffer Objects(UBO) make you able to share values between programs. 272 | 273 | ```javascript 274 | // create a buffer. 275 | const sharedUniformBuffer = new XenoGL.UniformBuffer({ 276 | dataOrLength: new Float32Array([1.0, 0.0, 0.0, 1.0]), 277 | dataType: XenoGL.FLOAT 278 | }); 279 | 280 | // create ubos. 281 | const ubo1 = new XenoGL.UniformBufferObject('param', sharedUniformBuffer); 282 | const ubo2 = new XenoGL.UniformBufferObject('param', sharedUniformBuffer); 283 | 284 | // add to programs. 285 | program1.addUniformBufferObject(ubo1); 286 | program2.addUniformBufferObject(ubo2); 287 | ``` 288 | 289 | ## Transform Feedback 290 | 291 | To use transform feedbacks, first, create a program with additional options. 292 | 293 | ```javascript 294 | const program = new XenoGL.Program({ 295 | vertexShader: vs, 296 | fragmentShader: fs, 297 | feedbackVaryings: ['vertexPosition', 'vertexVelocity', 'vertexAge', 'vertexLife'], // variables to feedback. 298 | feedbackBufferMode: XenoGL.INTERLEAVED_ATTRIBS // XenoGL.SEPARATE_ATTRIB or XenoGL.INTERLEAVED_ATTRIBS 299 | }); 300 | ``` 301 | 302 | Then, create a `TransformFeedback` object and add it to the context(**not to the program**). 303 | 304 | ```javascript 305 | const tf = new XenoGL.TransformFeedback(); 306 | xgl.addTransformFeedback(tf); 307 | ``` 308 | 309 | `feedback` method executes a calc and feedback. 310 | 311 | ```javascript 312 | tf.feedback({ 313 | mode: XenoGL.POINTS, 314 | targetBuffers: [buffer], // buffers to feedback. 315 | count: 100 // how many calc. 316 | }); 317 | ``` 318 | 319 | ## Textures 320 | 321 | Using textures, create a `Texture2D` object and add it to the context. 322 | 323 | ```javascript 324 | const textureSource = await fetch('texture-300x300.png').then((res) => res.blob()) 325 | .then((blob) => createImageBitmap(blob)); 326 | const texture = new XenoGL.Texture2D(textureSource); 327 | xgl.addTexture(texture); 328 | ``` 329 | 330 | Source of texture can be img, canvas, video, ImageBitmap, ImageData or ArrayBufferView. 331 | 332 | You can crete textures with options. 333 | 334 | ```javascript 335 | const texture = new XenoGL.Texture2D(textureSource, { 336 | target: XenoGL.TEXTURE_2D, 337 | mipmapLevel: 0, 338 | internalFormat: XenoGL.RGBA, 339 | format: XenoGL.RGBA, 340 | dataType: XenoGL.UNSIGNED_BYTE, 341 | width: 500, 342 | height: 500 343 | }); 344 | ``` 345 | 346 | To use another texture, use `xgl.activateTexture(texture)`. 347 | 348 | ```javascript 349 | xgl.activateTexture(texture2); 350 | ``` 351 | 352 | 353 | ## Misc. 354 | 355 | ```javascript 356 | xgl.clearColor(0.0, 0.0, 0.0, 1.0); 357 | xgl.clear(XenoGL.COLOR_BUFFER_BIT | XenoGL.DEPTH_BUFFER_BIT); 358 | xgl.enable(XenoGL.RASTERIZER_DISCARD); 359 | xgl.disable(XenoGL.RASTERIZER_DISCARD); 360 | ``` 361 | 362 | ## API Document 363 | 364 | For more information, see [API Document](https://kotofurumiya.github.io/xenogl/). -------------------------------------------------------------------------------- /__tests__/browser/animation/fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | 4 | in vec4 vColor; 5 | out vec4 fragmentColor; 6 | 7 | void main() { 8 | fragmentColor = vColor; 9 | } 10 | -------------------------------------------------------------------------------- /__tests__/browser/animation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - Animation 6 | 7 | 8 | 9 | 10 | 11 | 108 | 109 | -------------------------------------------------------------------------------- /__tests__/browser/animation/vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec3 vertexPosition; 4 | in vec4 color; 5 | 6 | uniform mat4 model; 7 | uniform mat4 view; 8 | uniform mat4 projection; 9 | 10 | out vec4 vColor; 11 | 12 | void main() { 13 | vColor = color; 14 | gl_Position = projection * view * model * vec4(vertexPosition, 1.0); 15 | } -------------------------------------------------------------------------------- /__tests__/browser/basic/fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | 4 | in vec4 vColor; 5 | out vec4 fragmentColor; 6 | 7 | void main() { 8 | fragmentColor = vColor; 9 | } 10 | -------------------------------------------------------------------------------- /__tests__/browser/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - Basic 6 | 7 | 8 | 9 | 10 | 73 | 74 | -------------------------------------------------------------------------------- /__tests__/browser/basic/vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec3 vertexPosition; 4 | in vec4 color; 5 | 6 | out vec4 vColor; 7 | 8 | void main() { 9 | vColor = color; 10 | gl_Position = vec4(vertexPosition, 1.0); 11 | } -------------------------------------------------------------------------------- /__tests__/browser/feedback/fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | out vec4 fragmentColor; 6 | 7 | void main() { 8 | fragmentColor = vec4(1.0); 9 | } -------------------------------------------------------------------------------- /__tests__/browser/feedback/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - Feedback 6 | 7 | 8 | 9 | 10 | 83 | 84 | -------------------------------------------------------------------------------- /__tests__/browser/feedback/vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec4 vecA; 4 | in vec4 vecB; 5 | 6 | out vec4 result1; 7 | out vec4 result2; 8 | 9 | void main() { 10 | result1 = vecA + vecB; 11 | result2 = vecA - vecB; 12 | } 13 | -------------------------------------------------------------------------------- /__tests__/browser/particle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - Particle 6 | 7 | 8 | 9 | 10 | 157 | 158 | -------------------------------------------------------------------------------- /__tests__/browser/particle/particle_renderer_fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | out vec4 fragColor; 6 | 7 | void main() { 8 | fragColor = vec4(1.0); 9 | } -------------------------------------------------------------------------------- /__tests__/browser/particle/particle_renderer_vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec2 particlePosition; 4 | 5 | void main() { 6 | gl_PointSize = 2.0; 7 | gl_Position = vec4(particlePosition, 0.0, 1.0); 8 | } -------------------------------------------------------------------------------- /__tests__/browser/particle/particle_updater_fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | void main() { 6 | discard; 7 | } -------------------------------------------------------------------------------- /__tests__/browser/particle/particle_updater_vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform vec2 origin; 4 | uniform float elapsedTimeDelta; 5 | 6 | in vec2 particlePosition; 7 | in vec2 particleVelocity; 8 | in float particleAge; 9 | in float particleLife; 10 | 11 | out vec2 vertexPosition; 12 | out vec2 vertexVelocity; 13 | out float vertexAge; 14 | out float vertexLife; 15 | 16 | void main() { 17 | if(particleAge > particleLife) { 18 | vertexPosition = origin; 19 | vertexVelocity = particleVelocity; 20 | vertexAge = 0.0; 21 | vertexLife = particleLife; 22 | } else { 23 | vertexPosition = particlePosition + (particleVelocity * elapsedTimeDelta); 24 | vertexVelocity = particleVelocity; 25 | vertexAge = particleAge + elapsedTimeDelta; 26 | vertexLife = particleLife; 27 | } 28 | } -------------------------------------------------------------------------------- /__tests__/browser/texture/fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | precision highp float; 3 | 4 | uniform sampler2D tex; 5 | in vec2 textureCoord; 6 | out vec4 fragmentColor; 7 | 8 | void main() { 9 | fragmentColor = texture(tex, textureCoord); 10 | } -------------------------------------------------------------------------------- /__tests__/browser/texture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - Texture 6 | 7 | 8 | 9 | 72 | 73 | -------------------------------------------------------------------------------- /__tests__/browser/texture/texture-300x300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/__tests__/browser/texture/texture-300x300.png -------------------------------------------------------------------------------- /__tests__/browser/texture/vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec3 vertexPosition; 4 | in vec2 texCoord; 5 | 6 | out vec2 textureCoord; 7 | 8 | void main() { 9 | textureCoord = texCoord; 10 | gl_Position = vec4(vertexPosition, 1.0); 11 | } 12 | -------------------------------------------------------------------------------- /__tests__/browser/uniformbufferobject/fs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | in vec4 vColor; 6 | out vec4 fragmentColor; 7 | 8 | void main() { 9 | fragmentColor = vColor; 10 | } 11 | -------------------------------------------------------------------------------- /__tests__/browser/uniformbufferobject/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | XenoGL Test - UBO 6 | 7 | 8 | 9 |
It's ok if you see a red square.
10 | 90 | 91 | -------------------------------------------------------------------------------- /__tests__/browser/uniformbufferobject/vs.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec3 vertexPosition; 4 | 5 | layout (std140) uniform param { 6 | vec4 color; 7 | }; 8 | 9 | out vec4 vColor; 10 | 11 | void main() { 12 | vColor = color; 13 | gl_Position = vec4(vertexPosition, 1.0); 14 | } -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/docs/.nojekyll -------------------------------------------------------------------------------- /docs/assets/images/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/docs/assets/images/icons.png -------------------------------------------------------------------------------- /docs/assets/images/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/docs/assets/images/icons@2x.png -------------------------------------------------------------------------------- /docs/assets/images/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/docs/assets/images/widgets.png -------------------------------------------------------------------------------- /docs/assets/images/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotofurumiya/xenogl/8ab6a66fdb585c2d6a3c207d4433e7097e80982c/docs/assets/images/widgets@2x.png -------------------------------------------------------------------------------- /docs/globals.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 59 |

xenogl

60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |

Index

68 |
69 |
70 |
71 |

External modules

72 | 85 |
86 |
87 |
88 |
89 |
90 | 136 |
137 |
138 | 197 |
198 |

Generated using TypeDoc

199 |
200 |
201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/modules/_buffer_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "buffer" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "buffer"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 81 |
82 |
83 |

Interfaces

84 | 87 |
88 |
89 |
90 |
91 |
92 | 153 |
154 |
155 | 214 |
215 |

Generated using TypeDoc

216 |
217 |
218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /docs/modules/_index_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "index" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "index"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | 116 |
117 |
118 | 177 |
178 |

Generated using TypeDoc

179 |
180 |
181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /docs/modules/_shader_program_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "shader_program" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "shader_program"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 81 |
82 |
83 |
84 |
85 |
86 | 144 |
145 |
146 | 205 |
206 |

Generated using TypeDoc

207 |
208 |
209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /docs/modules/_transform_feedback_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "transform_feedback" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "transform_feedback"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 132 |
133 |
134 | 193 |
194 |

Generated using TypeDoc

195 |
196 |
197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /docs/modules/_uniform_buffer_object_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "uniform_buffer_object" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "uniform_buffer_object"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 132 |
133 |
134 | 193 |
194 |

Generated using TypeDoc

195 |
196 |
197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /docs/modules/_utils_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "utils" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "utils"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Functions

75 | 78 |
79 |
80 |
81 |
82 |
83 |

Functions

84 |
85 | 86 |

getBytesPerElementByGlType

87 |
    88 |
  • getBytesPerElementByGlType(type: number): number | null
  • 89 |
90 |
    91 |
  • 92 | 97 |

    Parameters

    98 |
      99 |
    • 100 |
      type: number
      101 |
    • 102 |
    103 |

    Returns number 104 | | 105 | null 106 |

    107 |
  • 108 |
109 |
110 |
111 |
112 | 161 |
162 |
163 | 222 |
223 |

Generated using TypeDoc

224 |
225 |
226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /docs/modules/_vertex_array_object_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "vertex_array_object" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "vertex_array_object"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 132 |
133 |
134 | 193 |
194 |

Generated using TypeDoc

195 |
196 |
197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /docs/modules/_webgl2_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | "webgl2" | xenogl 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 | 27 |
28 |
29 | Options 30 |
31 |
32 | All 33 |
    34 |
  • Public
  • 35 |
  • Public/Protected
  • 36 |
  • All
  • 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | Menu 48 |
49 |
50 |
51 |
52 |
53 |
54 | 62 |

External module "webgl2"

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |

Index

71 |
72 |
73 |
74 |

Classes

75 | 78 |
79 |
80 |
81 |
82 |
83 | 132 |
133 |
134 | 193 |
194 |

Generated using TypeDoc

195 |
196 |
197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "transform": { 3 | "^.+\\.tsx?$": "ts-jest" 4 | }, 5 | "testMatch": ['**/__tests__/**/*.test.(ts|js)?(x)'], 6 | "moduleFileExtensions": [ 7 | "ts", 8 | "tsx", 9 | "js", 10 | "jsx", 11 | "json", 12 | "node" 13 | ] 14 | }; -------------------------------------------------------------------------------- /lib/buffer.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Attribute, TypedArrayLike } from './variable'; 3 | export interface Buffer { 4 | readonly data: TypedArrayLike | null; 5 | readonly dataType: number; 6 | readonly usage: number; 7 | readonly bufferType: number; 8 | readonly totalAttributesSize: number; 9 | readonly dataCount: number; 10 | readonly glBuffer: WebGLBuffer | null; 11 | readonly isInitialized: boolean; 12 | bufferData(data: TypedArrayLike | number): void; 13 | activate(): void; 14 | deactivate(): void; 15 | _init(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): void; 16 | _initOnce(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): void; 17 | _createWebGLVertexArrayObject(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): WebGLVertexArrayObject; 18 | } 19 | export declare abstract class BufferBase implements Buffer { 20 | protected _glContext: WebGL2RenderingContext | null; 21 | protected _glProgram: WebGLProgram | null; 22 | protected _glBuffer: WebGLBuffer | null; 23 | protected _dataOrLength: TypedArrayLike | number | null; 24 | protected _data: TypedArrayLike | null; 25 | protected _attributes: Attribute[]; 26 | protected _enabledAttributes: Attribute[]; 27 | protected _attributeToLocation: Map; 28 | protected _dataType: number; 29 | protected _usage: number; 30 | protected _bufferType: number; 31 | protected _isInitialized: boolean; 32 | protected _flushData: (context: WebGL2RenderingContext, buffer: WebGLBuffer) => void; 33 | protected _totalAttributesSize: number; 34 | constructor(args: { 35 | dataOrLength?: number | Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | null | undefined; 36 | attributes?: Attribute[] | undefined; 37 | dataType?: number | undefined; 38 | usage?: number | undefined; 39 | } | undefined, bufferType: number); 40 | /** 41 | * Send data to the buffer. 42 | * @param {TypedArrayLike | number} dataOrLength 43 | */ 44 | bufferData(dataOrLength: TypedArrayLike | number): void; 45 | activate(): void; 46 | deactivate(): void; 47 | _flush(): void; 48 | /** 49 | * Initializes attributes. 50 | * Do not call this method manually. 51 | * @param {WebGL2RenderingContext} context 52 | * @param {WebGLProgram | null} program 53 | * @param {Attribute[] | null} attributes 54 | * @private 55 | */ 56 | _initAttributes(context: WebGL2RenderingContext, program: WebGLProgram, attributes?: Attribute[] | null): void; 57 | _enableAttributes(): void; 58 | _disableAttributes(): void; 59 | /** 60 | * Initializes the buffer. 61 | * Do not call this method manually. 62 | * @param {WebGL2RenderingContext} context 63 | * @param {WebGLProgram | null} program 64 | * @param {Attribute[] | null} attributes 65 | * @private 66 | */ 67 | _init(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): void; 68 | /** 69 | * Initializes the buffer. 70 | * Do not call this method manually. 71 | * @param {WebGL2RenderingContext} context 72 | * @param {WebGLProgram | null} program 73 | * @param {Attribute[] | null} attributes 74 | * @private 75 | */ 76 | _initOnce(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): void; 77 | /** 78 | * Creates and return `WebGLVertexArrayObject`. 79 | * You don't have to call this method manually. 80 | * @param {WebGL2RenderingContext} context 81 | * @param {WebGLProgram | null} program 82 | * @param {Attribute[] | null} attributes 83 | * @returns {WebGLVertexArrayObject} 84 | * @private 85 | */ 86 | _createWebGLVertexArrayObject(context: WebGL2RenderingContext, program?: WebGLProgram | null, attributes?: Attribute[] | null): WebGLVertexArrayObject; 87 | /** 88 | * Returns data of the buffer. 89 | * @returns {TypedArrayLike | null} 90 | */ 91 | readonly data: TypedArrayLike | null; 92 | /** 93 | * Returns data type of the buffer. 94 | * @returns {number} 95 | */ 96 | readonly dataType: number; 97 | /** 98 | * Returns how many data set stored in the buffer. 99 | * @returns {number} 100 | */ 101 | readonly dataCount: number; 102 | /** 103 | * Returns usage of the buffer. 104 | * @returns {number} 105 | */ 106 | readonly usage: number; 107 | /** 108 | * Returns if the buffer is initialized. 109 | * @returns {boolean} 110 | */ 111 | readonly isInitialized: boolean; 112 | /** 113 | * Returns total size of attributes. 114 | * @returns {number} 115 | */ 116 | readonly totalAttributesSize: number; 117 | /** 118 | * Returns type of the buffer. 119 | * It can be `XenoGL..ARRAY_BUFFER` or `XenoGL..ELEMENT_ARRAY_BUFFER`. 120 | * @returns {number} 121 | */ 122 | readonly bufferType: number; 123 | /** 124 | * Returns `WebGLBuffer` if the buffer is initialized. 125 | * Otherwise, throws an error. 126 | * @returns {WebGLBuffer} 127 | */ 128 | readonly glBuffer: WebGLBuffer; 129 | } 130 | /** 131 | * ArrayBuffer. 132 | */ 133 | export declare class ArrayBuffer extends BufferBase { 134 | constructor(args?: { 135 | dataOrLength?: TypedArrayLike | number | null; 136 | attributes?: Attribute[]; 137 | dataType?: number; 138 | usage?: number; 139 | }); 140 | } 141 | /** 142 | * ElementArrayBuffer. 143 | */ 144 | export declare class ElementArrayBuffer extends BufferBase { 145 | constructor(args?: { 146 | dataOrLength?: TypedArrayLike | number | null; 147 | attributes?: Attribute[]; 148 | dataType?: number; 149 | usage?: number; 150 | }); 151 | } 152 | /** 153 | * UniformBuffer. 154 | */ 155 | export declare class UniformBuffer extends BufferBase { 156 | constructor(args?: { 157 | dataOrLength?: TypedArrayLike | number | null; 158 | dataType?: number; 159 | usage?: number; 160 | }); 161 | } 162 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './webgl2'; 3 | export * from './variable'; 4 | export * from './shader_program'; 5 | export * from './buffer'; 6 | export * from './vertex_array_object'; 7 | export * from './uniform_buffer_object'; 8 | export * from './transform_feedback'; 9 | export * from './texture'; 10 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function __export(m) { 3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 4 | } 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | __export(require("./constants")); 7 | __export(require("./webgl2")); 8 | __export(require("./variable")); 9 | __export(require("./shader_program")); 10 | __export(require("./buffer")); 11 | __export(require("./vertex_array_object")); 12 | __export(require("./uniform_buffer_object")); 13 | __export(require("./transform_feedback")); 14 | __export(require("./texture")); 15 | -------------------------------------------------------------------------------- /lib/shader_program.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Buffer, ElementArrayBuffer } from './buffer'; 3 | import { Uniform } from './variable'; 4 | import { VertexArrayObject } from './vertex_array_object'; 5 | import { UniformBufferObject } from './uniform_buffer_object'; 6 | export declare abstract class ShaderBase { 7 | protected _source: string; 8 | protected _glShader: WebGLShader | null; 9 | protected _isCompiled: boolean; 10 | protected _shaderType: number; 11 | constructor(source: string, shaderType: number); 12 | _compile(context: WebGL2RenderingContext): WebGLShader | null; 13 | /** 14 | * Returns if the shader is compiled. 15 | * @returns {boolean} 16 | */ 17 | readonly isCompiled: boolean; 18 | /** 19 | * Returns `WebGLShader` when the shader is already compiled. 20 | * Otherwise throws an error. 21 | * @returns {WebGLShader} 22 | */ 23 | readonly glShader: WebGLShader; 24 | } 25 | /** 26 | * A vertex shader. 27 | */ 28 | export declare class VertexShader extends ShaderBase { 29 | constructor(source: string); 30 | } 31 | /** 32 | * A fragment shader. 33 | */ 34 | export declare class FragmentShader extends ShaderBase { 35 | constructor(source: string); 36 | } 37 | /** 38 | * A shader program. 39 | */ 40 | export declare class Program { 41 | protected _vertexShader: VertexShader; 42 | protected _fragmentShader: FragmentShader; 43 | protected _feedbackVaryings: string[]; 44 | protected _feedbackBufferMode: number; 45 | protected _isLinked: boolean; 46 | protected _glContext: WebGL2RenderingContext | null; 47 | protected _glProgram: WebGLProgram | null; 48 | protected _initializedBuffers: Buffer[]; 49 | protected _uninitializedBuffers: Buffer[]; 50 | protected _currentIndexBuffer: ElementArrayBuffer | null; 51 | protected _initializedUniforms: Uniform[]; 52 | protected _uninitializedUniforms: Uniform[]; 53 | protected _initializedVertexArrayObjects: VertexArrayObject[]; 54 | protected _uninitializedVertexArrayObject: VertexArrayObject[]; 55 | protected _currentVertexArrayObject: VertexArrayObject | null; 56 | protected _initializedUniformBufferObjects: UniformBufferObject[]; 57 | protected _uninitializedUniformBufferObjects: UniformBufferObject[]; 58 | id: number | null; 59 | constructor(args: { 60 | vertexShader: VertexShader; 61 | fragmentShader: FragmentShader; 62 | feedbackVaryings?: string[]; 63 | feedbackBufferMode?: number; 64 | }); 65 | /** 66 | * Adds a buffer to the program. 67 | * @param {Buffer} buffer 68 | */ 69 | addBuffer(buffer: Buffer): void; 70 | /** 71 | * Activates the `ElementArrayBuffer` as a index buffer. 72 | * @param {ElementArrayBuffer} buffer 73 | */ 74 | activateElementArrayBuffer(buffer: ElementArrayBuffer): void; 75 | /** 76 | * Adds an uniform variable to the program. 77 | * @param {Uniform} uniform 78 | */ 79 | addUniform(uniform: Uniform): void; 80 | /** 81 | * Adds a `VertexArrayObject` to the program. 82 | * @param {VertexArrayObject} vao 83 | */ 84 | addVertexArrayObject(vao: VertexArrayObject): void; 85 | /** 86 | * Activates the `VertexArrayObject`. 87 | * @param {VertexArrayObject} vao 88 | */ 89 | activateVertexArrayObject(vao: VertexArrayObject): void; 90 | /** 91 | * Adds an `UniformBufferObject` to the program. 92 | * @param {UniformBufferObject} ubo 93 | */ 94 | addUniformBufferObject(ubo: UniformBufferObject): void; 95 | /** 96 | * Issues a draw call, which draws graphics. 97 | * @param {number} mode 98 | * @param {number | null} count 99 | */ 100 | draw(mode: number, count?: number | null): void; 101 | activate(): void; 102 | deactivate(): void; 103 | /** 104 | * Links the shader program. 105 | * This method is called internally. So you don't have to call this method manually. 106 | * @param {WebGL2RenderingContext} context 107 | */ 108 | _link(context: WebGL2RenderingContext): void; 109 | /** 110 | * Returns if the program is linked. 111 | * @returns {boolean} 112 | */ 113 | readonly isLinked: boolean; 114 | /** 115 | * Returns `WebGLProgram` when the program is already linked. 116 | * Otherwise throws an error. 117 | * @returns {WebGLProgram} 118 | */ 119 | readonly glProgram: WebGLProgram; 120 | } 121 | -------------------------------------------------------------------------------- /lib/texture.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare type TextureSource = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | ImageData; 3 | export interface Texture { 4 | activate(): void; 5 | _init(context: WebGL2RenderingContext, textureNumber: number): void; 6 | } 7 | export declare abstract class TextureBase implements Texture { 8 | abstract activate(): void; 9 | abstract _init(context: WebGL2RenderingContext, textureNumber: number): void; 10 | protected _getTextureIdFromNumber(n: number): number; 11 | } 12 | export declare class Texture2D extends TextureBase { 13 | protected _source: TextureSource | ArrayBufferView; 14 | protected _glContext: WebGL2RenderingContext | null; 15 | protected _glTexture: WebGLTexture | null; 16 | protected _textureID: number | null; 17 | protected _target: number; 18 | protected _mipmapLevel: number; 19 | protected _internalFormat: number; 20 | protected _format: number; 21 | protected _dataType: number; 22 | protected _width?: number; 23 | protected _height?: number; 24 | protected _flushData: Function; 25 | constructor(dataSource: TextureSource | ArrayBufferView, options?: { 26 | target?: number; 27 | mipmapLevel?: number; 28 | internalFormat?: number; 29 | format?: number; 30 | dataType?: number; 31 | width?: number; 32 | height?: number; 33 | }); 34 | activate(): void; 35 | _init(context: WebGL2RenderingContext, textureNumber: number): void; 36 | _flush(): void; 37 | } 38 | -------------------------------------------------------------------------------- /lib/texture.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __extends = (this && this.__extends) || (function () { 3 | var extendStatics = Object.setPrototypeOf || 4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 6 | return function (d, b) { 7 | extendStatics(d, b); 8 | function __() { this.constructor = d; } 9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 10 | }; 11 | })(); 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | var constants_1 = require("./constants"); 14 | var TextureBase = /** @class */ (function () { 15 | function TextureBase() { 16 | } 17 | TextureBase.prototype._getTextureIdFromNumber = function (n) { 18 | return constants_1.TEXTURE0 + n; 19 | }; 20 | return TextureBase; 21 | }()); 22 | exports.TextureBase = TextureBase; 23 | var Texture2D = /** @class */ (function (_super) { 24 | __extends(Texture2D, _super); 25 | function Texture2D(dataSource, options) { 26 | if (options === void 0) { options = {}; } 27 | var _this = _super.call(this) || this; 28 | _this._source = dataSource; 29 | _this._glContext = null; 30 | _this._glTexture = null; 31 | _this._textureID = null; 32 | _this._target = ('target' in options) ? options.target : constants_1.TEXTURE_2D; 33 | _this._mipmapLevel = ('mipmapLevel' in options) ? options.mipmapLevel : 0; 34 | _this._internalFormat = ('internalFormat' in options) ? options.internalFormat : constants_1.RGBA; 35 | _this._format = ('format' in options) ? options.mipmapLevel : constants_1.RGBA; 36 | _this._dataType = ('dataType' in options) ? options.mipmapLevel : constants_1.UNSIGNED_BYTE; 37 | _this._width = ('width' in options) ? options.width : undefined; 38 | _this._height = ('height' in options) ? options.height : undefined; 39 | _this._flushData = function () { }; 40 | return _this; 41 | } 42 | Texture2D.prototype.activate = function () { 43 | var _this = this; 44 | this._flushData = function (context) { 45 | context.activeTexture(_this._textureID); 46 | }; 47 | }; 48 | Texture2D.prototype._init = function (context, textureNumber) { 49 | this._glContext = context; 50 | this._textureID = this._getTextureIdFromNumber(textureNumber); 51 | context.activeTexture(this._textureID); 52 | this._glTexture = context.createTexture(); 53 | context.bindTexture(this._target, this._glTexture); 54 | if (typeof this._width === 'undefined' || typeof this._height === 'undefined') { 55 | context.texImage2D(this._target, this._mipmapLevel, this._internalFormat, this._format, this._dataType, this._source); 56 | } 57 | else { 58 | context.texImage2D(this._target, this._mipmapLevel, this._internalFormat, this._width, this._height, 0, this._format, this._dataType, this._source); 59 | } 60 | context.generateMipmap(this._target); 61 | this._flush(); 62 | }; 63 | Texture2D.prototype._flush = function () { 64 | if (this._glContext !== null) { 65 | this._flushData(this._glContext); 66 | this._flushData = function () { }; 67 | } 68 | }; 69 | return Texture2D; 70 | }(TextureBase)); 71 | exports.Texture2D = Texture2D; 72 | -------------------------------------------------------------------------------- /lib/transform_feedback.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Buffer } from './buffer'; 3 | export declare class TransformFeedback { 4 | protected _glContext: WebGL2RenderingContext | null; 5 | protected _glTransformFeedback: WebGLTransformFeedback | null; 6 | constructor(); 7 | feedback(args: { 8 | mode: number; 9 | targetBuffers: Buffer[]; 10 | count: number; 11 | }): void; 12 | _init(context: WebGL2RenderingContext): void; 13 | } 14 | -------------------------------------------------------------------------------- /lib/transform_feedback.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var constants_1 = require("./constants"); 4 | var TransformFeedback = /** @class */ (function () { 5 | function TransformFeedback() { 6 | this._glContext = null; 7 | this._glTransformFeedback = null; 8 | } 9 | TransformFeedback.prototype.feedback = function (args) { 10 | if (this._glContext === null) { 11 | throw new Error('This transform feedback is not added to any WebGL2 yet.'); 12 | } 13 | for (var i = 0; i < args.targetBuffers.length; i++) { 14 | this._glContext.bindBufferBase(constants_1.TRANSFORM_FEEDBACK_BUFFER, i, args.targetBuffers[i].glBuffer); 15 | } 16 | this._glContext.beginTransformFeedback(args.mode); 17 | this._glContext.drawArrays(args.mode, 0, args.count); 18 | this._glContext.endTransformFeedback(); 19 | for (var i = 0; i < args.targetBuffers.length; i++) { 20 | this._glContext.bindBufferBase(constants_1.TRANSFORM_FEEDBACK_BUFFER, i, null); 21 | } 22 | }; 23 | TransformFeedback.prototype._init = function (context) { 24 | this._glContext = context; 25 | this._glTransformFeedback = context.createTransformFeedback(); 26 | context.bindTransformFeedback(constants_1.TRANSFORM_FEEDBACK, this._glTransformFeedback); 27 | }; 28 | return TransformFeedback; 29 | }()); 30 | exports.TransformFeedback = TransformFeedback; 31 | -------------------------------------------------------------------------------- /lib/transformfeedback.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Transformfeedback { 2 | } 3 | -------------------------------------------------------------------------------- /lib/transformfeedback.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var Transformfeedback = /** @class */ (function () { 4 | function Transformfeedback() { 5 | } 6 | return Transformfeedback; 7 | }()); 8 | exports.Transformfeedback = Transformfeedback; 9 | -------------------------------------------------------------------------------- /lib/uniform_buffer_object.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { UniformBuffer } from './buffer'; 3 | import { TypedArrayLike } from './variable'; 4 | /** 5 | * An uniform buffer object. 6 | */ 7 | export declare class UniformBufferObject { 8 | protected _buffer: UniformBuffer; 9 | protected _blockName: string; 10 | protected _blockIndex: number | null; 11 | protected _javascriptIndex: number | null; 12 | protected _isInitialized: boolean; 13 | constructor(blockName: string, bufferOrBufferArgs?: UniformBuffer | { 14 | dataOrLength?: TypedArrayLike | number | null; 15 | dataType?: number; 16 | usage?: number; 17 | }); 18 | /** 19 | * Initializes the uniform buffer object. 20 | * Do not call this method manually. 21 | * @param {WebGL2RenderingContext} context 22 | * @param {WebGLProgram} program 23 | * @param {number} jsIndex 24 | * @private 25 | */ 26 | _init(context: WebGL2RenderingContext, program: WebGLProgram, jsIndex: number): void; 27 | } 28 | -------------------------------------------------------------------------------- /lib/uniform_buffer_object.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var buffer_1 = require("./buffer"); 4 | var constants_1 = require("./constants"); 5 | /** 6 | * An uniform buffer object. 7 | */ 8 | var UniformBufferObject = /** @class */ (function () { 9 | function UniformBufferObject(blockName, bufferOrBufferArgs) { 10 | if (bufferOrBufferArgs === void 0) { bufferOrBufferArgs = { dataOrLength: null, dataType: constants_1.FLOAT, usage: constants_1.STATIC_DRAW }; } 11 | this._blockName = blockName; 12 | this._blockIndex = null; 13 | this._javascriptIndex = null; 14 | this._isInitialized = false; 15 | if (bufferOrBufferArgs instanceof buffer_1.UniformBuffer) { 16 | this._buffer = bufferOrBufferArgs; 17 | } 18 | else { 19 | this._buffer = new buffer_1.UniformBuffer(bufferOrBufferArgs); 20 | } 21 | } 22 | /** 23 | * Initializes the uniform buffer object. 24 | * Do not call this method manually. 25 | * @param {WebGL2RenderingContext} context 26 | * @param {WebGLProgram} program 27 | * @param {number} jsIndex 28 | * @private 29 | */ 30 | UniformBufferObject.prototype._init = function (context, program, jsIndex) { 31 | this._blockIndex = context.getUniformBlockIndex(program, this._blockName); 32 | this._javascriptIndex = jsIndex; 33 | context.uniformBlockBinding(program, this._blockIndex, jsIndex); 34 | this._buffer._initOnce(context, program); 35 | context.bindBufferBase(constants_1.UNIFORM_BUFFER, jsIndex, this._buffer.glBuffer); 36 | }; 37 | return UniformBufferObject; 38 | }()); 39 | exports.UniformBufferObject = UniformBufferObject; 40 | -------------------------------------------------------------------------------- /lib/utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare function getBytesPerElementByGlType(type: number): number | null; 2 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var constants_1 = require("./constants"); 4 | function getBytesPerElementByGlType(type) { 5 | if (type === constants_1.FLOAT) { 6 | return 4; 7 | } 8 | else if (type === constants_1.BYTE || type === constants_1.UNSIGNED_BYTE) { 9 | return 1; 10 | } 11 | else if (type === constants_1.SHORT || type === constants_1.UNSIGNED_SHORT || type === constants_1.HALF_FLOAT) { 12 | return 2; 13 | } 14 | else { 15 | return null; 16 | } 17 | } 18 | exports.getBytesPerElementByGlType = getBytesPerElementByGlType; 19 | -------------------------------------------------------------------------------- /lib/variable.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare type TypedArrayLike = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; 3 | /** 4 | * An attribute variable. 5 | */ 6 | export declare class Attribute { 7 | protected _name: string; 8 | protected _size: number; 9 | constructor(name: string, size: number); 10 | equals(other: Attribute): boolean; 11 | readonly name: string; 12 | readonly size: number; 13 | } 14 | /** 15 | * An uniform variable. 16 | */ 17 | export declare class Uniform { 18 | protected _name: string; 19 | protected _location: WebGLUniformLocation | null; 20 | protected _glContext: WebGL2RenderingContext | null; 21 | protected _glProgram: WebGLProgram | null; 22 | protected _flushData: (context: WebGL2RenderingContext, location: WebGLUniformLocation) => void; 23 | constructor(name: string); 24 | /** 25 | * Sets the uniform variable to the value. 26 | * @param {number} value 27 | * @param {number} type 28 | */ 29 | setValue(value: number, type: number): void; 30 | /** 31 | * Sets the uniform variable to the vector. 32 | * @param {TypedArrayLike} value 33 | * @param {number} type 34 | */ 35 | setVector(value: TypedArrayLike, type: number): void; 36 | setVector1(value: TypedArrayLike, type: number): void; 37 | setVector2(value: TypedArrayLike, type: number): void; 38 | setVector3(value: TypedArrayLike, type: number): void; 39 | setVector4(value: TypedArrayLike, type: number): void; 40 | /** 41 | * Sets the uniform variable to the matrix. 42 | * @param {Float32Array} value 43 | */ 44 | setMatrix(value: Float32Array): void; 45 | setMatrix2(value: Float32Array): void; 46 | setMatrix3(value: Float32Array): void; 47 | setMatrix4(value: Float32Array): void; 48 | _flush(): void; 49 | _init(context: WebGL2RenderingContext, program: WebGLProgram): void; 50 | readonly isLocated: boolean; 51 | } 52 | -------------------------------------------------------------------------------- /lib/variable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var constants_1 = require("./constants"); 4 | /** 5 | * An attribute variable. 6 | */ 7 | var Attribute = /** @class */ (function () { 8 | function Attribute(name, size) { 9 | this._name = name; 10 | this._size = size; 11 | } 12 | Attribute.prototype.equals = function (other) { 13 | return this.name === other.name && this.size === other.size; 14 | }; 15 | Object.defineProperty(Attribute.prototype, "name", { 16 | get: function () { 17 | return this._name; 18 | }, 19 | enumerable: true, 20 | configurable: true 21 | }); 22 | Object.defineProperty(Attribute.prototype, "size", { 23 | get: function () { 24 | return this._size; 25 | }, 26 | enumerable: true, 27 | configurable: true 28 | }); 29 | return Attribute; 30 | }()); 31 | exports.Attribute = Attribute; 32 | /** 33 | * An uniform variable. 34 | */ 35 | var Uniform = /** @class */ (function () { 36 | function Uniform(name) { 37 | this._name = name; 38 | this._location = null; 39 | this._glContext = null; 40 | this._glProgram = null; 41 | this._flushData = function (context, location) { }; 42 | } 43 | /** 44 | * Sets the uniform variable to the value. 45 | * @param {number} value 46 | * @param {number} type 47 | */ 48 | Uniform.prototype.setValue = function (value, type) { 49 | if (type === constants_1.FLOAT) { 50 | this._flushData = function (context, location) { 51 | context.uniform1f(location, value); 52 | }; 53 | } 54 | else if (type === constants_1.INT) { 55 | this._flushData = function (context, location) { 56 | context.uniform1i(location, value); 57 | }; 58 | } 59 | else if (type === constants_1.UNSIGNED_INT) { 60 | this._flushData = function (context, location) { 61 | context.uniform1ui(location, value); 62 | }; 63 | } 64 | this._flush(); 65 | }; 66 | /** 67 | * Sets the uniform variable to the vector. 68 | * @param {TypedArrayLike} value 69 | * @param {number} type 70 | */ 71 | Uniform.prototype.setVector = function (value, type) { 72 | var length = value.length; 73 | if (length === 1) { 74 | this.setVector1(value, type); 75 | } 76 | else if (length === 2) { 77 | this.setVector2(value, type); 78 | } 79 | else if (length === 3) { 80 | this.setVector3(value, type); 81 | } 82 | else if (length === 4) { 83 | this.setVector4(value, type); 84 | } 85 | else { 86 | throw new Error("Length of value must be 1, 2, 3 or 4. Your value length is " + length); 87 | } 88 | }; 89 | Uniform.prototype.setVector1 = function (value, type) { 90 | if (type === constants_1.FLOAT) { 91 | this._flushData = function (context, location) { 92 | context.uniform1fv(location, value); 93 | }; 94 | } 95 | else if (type === constants_1.INT) { 96 | this._flushData = function (context, location) { 97 | context.uniform1iv(location, value); 98 | }; 99 | } 100 | else if (type === constants_1.UNSIGNED_INT) { 101 | this._flushData = function (context, location) { 102 | context.uniform1uiv(location, value); 103 | }; 104 | } 105 | this._flush(); 106 | }; 107 | Uniform.prototype.setVector2 = function (value, type) { 108 | if (type === constants_1.FLOAT) { 109 | this._flushData = function (context, location) { 110 | context.uniform2fv(location, value); 111 | }; 112 | } 113 | else if (type === constants_1.INT) { 114 | this._flushData = function (context, location) { 115 | context.uniform2iv(location, value); 116 | }; 117 | } 118 | else if (type === constants_1.UNSIGNED_INT) { 119 | this._flushData = function (context, location) { 120 | context.uniform2uiv(location, value); 121 | }; 122 | } 123 | this._flush(); 124 | }; 125 | Uniform.prototype.setVector3 = function (value, type) { 126 | if (type === constants_1.FLOAT) { 127 | this._flushData = function (context, location) { 128 | context.uniform3fv(location, value); 129 | }; 130 | } 131 | else if (type === constants_1.INT) { 132 | this._flushData = function (context, location) { 133 | context.uniform3iv(location, value); 134 | }; 135 | } 136 | else if (type === constants_1.UNSIGNED_INT) { 137 | this._flushData = function (context, location) { 138 | context.uniform3uiv(location, value); 139 | }; 140 | } 141 | this._flush(); 142 | }; 143 | Uniform.prototype.setVector4 = function (value, type) { 144 | if (type === constants_1.FLOAT) { 145 | this._flushData = function (context, location) { 146 | context.uniform4fv(location, value); 147 | }; 148 | } 149 | else if (type === constants_1.INT) { 150 | this._flushData = function (context, location) { 151 | context.uniform4iv(location, value); 152 | }; 153 | } 154 | else if (type === constants_1.UNSIGNED_INT) { 155 | this._flushData = function (context, location) { 156 | context.uniform4uiv(location, value); 157 | }; 158 | } 159 | this._flush(); 160 | }; 161 | /** 162 | * Sets the uniform variable to the matrix. 163 | * @param {Float32Array} value 164 | */ 165 | Uniform.prototype.setMatrix = function (value) { 166 | var size = value.length; 167 | if (size === 4) { 168 | this.setMatrix2(value); 169 | } 170 | else if (size === 9) { 171 | this.setMatrix3(value); 172 | } 173 | else if (size === 16) { 174 | this.setMatrix4(value); 175 | } 176 | else { 177 | throw new Error("Failed to detect size of the matrix. If you use a non-square matrix, use setMatrixNxN instead."); 178 | } 179 | }; 180 | Uniform.prototype.setMatrix2 = function (value) { 181 | this._flushData = function (context, location) { 182 | context.uniformMatrix2fv(location, false, value); 183 | }; 184 | this._flush(); 185 | }; 186 | Uniform.prototype.setMatrix3 = function (value) { 187 | this._flushData = function (context, location) { 188 | context.uniformMatrix3fv(location, false, value); 189 | }; 190 | this._flush(); 191 | }; 192 | Uniform.prototype.setMatrix4 = function (value) { 193 | this._flushData = function (context, location) { 194 | context.uniformMatrix4fv(location, false, value); 195 | }; 196 | this._flush(); 197 | }; 198 | Uniform.prototype._flush = function () { 199 | if (this.isLocated && this._glContext !== null) { 200 | this._flushData(this._glContext, this._location); 201 | } 202 | }; 203 | Uniform.prototype._init = function (context, program) { 204 | this._location = context.getUniformLocation(program, this._name); 205 | this._glContext = context; 206 | this._glProgram = program; 207 | this._flush(); 208 | }; 209 | Object.defineProperty(Uniform.prototype, "isLocated", { 210 | get: function () { 211 | return this._location !== null; 212 | }, 213 | enumerable: true, 214 | configurable: true 215 | }); 216 | return Uniform; 217 | }()); 218 | exports.Uniform = Uniform; 219 | -------------------------------------------------------------------------------- /lib/vertex_array_object.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Attribute, TypedArrayLike } from './variable'; 3 | import { Buffer } from './buffer'; 4 | export declare class VertexArrayObject { 5 | protected _buffer: Buffer; 6 | protected _glContext: WebGL2RenderingContext | null; 7 | protected _glVertexArrayObject: WebGLVertexArrayObject | null; 8 | protected _enabledAttributes: Attribute[] | null; 9 | protected _mustWriteData: boolean; 10 | protected _dataOrLength?: TypedArrayLike | number; 11 | protected _isInitialized: boolean; 12 | constructor(buffer: Buffer, options?: { 13 | dataOrLength?: TypedArrayLike | number; 14 | attributes?: Attribute[]; 15 | }); 16 | /** 17 | * Initializes the vertex array object. 18 | * Do not call this method manually. 19 | * @param {WebGL2RenderingContext} context 20 | * @param {WebGLProgram} program 21 | * @private 22 | */ 23 | _init(context: WebGL2RenderingContext, program: WebGLProgram): void; 24 | /** 25 | * Returns buffer bound to the vertex array object. 26 | * @returns {Buffer} 27 | */ 28 | readonly buffer: Buffer; 29 | /** 30 | * Returns `WebGLVertexArrayObject` if the vertex array object is initialized. 31 | * Otherwise, throws an error. 32 | * @returns {WebGLVertexArrayObject} 33 | */ 34 | readonly glVertexArrayObject: WebGLVertexArrayObject; 35 | } 36 | -------------------------------------------------------------------------------- /lib/vertex_array_object.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var VertexArrayObject = /** @class */ (function () { 4 | function VertexArrayObject(buffer, options) { 5 | if (options === void 0) { options = {}; } 6 | this._buffer = buffer; 7 | this._glContext = null; 8 | this._glVertexArrayObject = null; 9 | this._enabledAttributes = ('attributes' in options) ? options.attributes : null; 10 | this._mustWriteData = 'dataOrLength' in options; 11 | if (this._mustWriteData) { 12 | this._dataOrLength = options.dataOrLength; 13 | } 14 | this._isInitialized = false; 15 | } 16 | /** 17 | * Initializes the vertex array object. 18 | * Do not call this method manually. 19 | * @param {WebGL2RenderingContext} context 20 | * @param {WebGLProgram} program 21 | * @private 22 | */ 23 | VertexArrayObject.prototype._init = function (context, program) { 24 | if (this._mustWriteData) { 25 | this._buffer.bufferData(this._dataOrLength); 26 | } 27 | this._buffer._initOnce(context, program, this._enabledAttributes); 28 | var vao = this._buffer._createWebGLVertexArrayObject(context, program, this._enabledAttributes); 29 | this._glContext = context; 30 | this._glVertexArrayObject = vao; 31 | this._isInitialized = true; 32 | }; 33 | Object.defineProperty(VertexArrayObject.prototype, "buffer", { 34 | /** 35 | * Returns buffer bound to the vertex array object. 36 | * @returns {Buffer} 37 | */ 38 | get: function () { 39 | return this._buffer; 40 | }, 41 | enumerable: true, 42 | configurable: true 43 | }); 44 | Object.defineProperty(VertexArrayObject.prototype, "glVertexArrayObject", { 45 | /** 46 | * Returns `WebGLVertexArrayObject` if the vertex array object is initialized. 47 | * Otherwise, throws an error. 48 | * @returns {WebGLVertexArrayObject} 49 | */ 50 | get: function () { 51 | if (this._isInitialized) { 52 | return this._glVertexArrayObject; 53 | } 54 | else { 55 | throw new Error('This vertex array object is not added to any program yet.'); 56 | } 57 | }, 58 | enumerable: true, 59 | configurable: true 60 | }); 61 | return VertexArrayObject; 62 | }()); 63 | exports.VertexArrayObject = VertexArrayObject; 64 | -------------------------------------------------------------------------------- /lib/webgl2.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Program } from './shader_program'; 3 | import { TransformFeedback } from './transform_feedback'; 4 | import { Texture } from './texture'; 5 | export declare class WebGL2 { 6 | protected _context: WebGL2RenderingContext; 7 | protected _programs: Array; 8 | protected _activeProgram: Program | null; 9 | protected _transformFeedbacks: Array; 10 | protected _textures: Texture[]; 11 | protected _activeTexture: Texture | null; 12 | constructor(canvas: HTMLCanvasElement); 13 | /** 14 | * Adds the program to the `WebGL2` and returns ID number of the program. 15 | * If any program is activated yet, this method activates the program. 16 | * @param {Program} program 17 | * @returns {number} Program ID 18 | */ 19 | addProgram(program: Program): number; 20 | /** 21 | * Adds the transform feedback to `WebGL2`. 22 | * @param {TransformFeedback} tf 23 | */ 24 | addTransformFeedback(tf: TransformFeedback): void; 25 | addTexture(texture: Texture): void; 26 | /** 27 | * Activates a program and deactivates the previous program. 28 | * Throws an error when the program is not attached to WebGL2. 29 | * @param {Program} program 30 | */ 31 | activateProgram(program: Program): void; 32 | /** 33 | * Activates a program by ID and deactivates the previous program. 34 | * Throws an error when the ID does not exist. 35 | * @param {number} id 36 | */ 37 | activateProgramByID(id: number): void; 38 | /** 39 | * Uses the program as a current program. 40 | * @param {Program} program 41 | */ 42 | useProgram(program: Program): void; 43 | /** 44 | * Uses the program as a current program. 45 | * @param {number} id 46 | */ 47 | useProgramByID(id: number): void; 48 | activateTexture(texture: Texture): void; 49 | /** 50 | * Deactivates the program. 51 | * @param {Program} program 52 | */ 53 | deactivateProgram(program: Program): void; 54 | draw(mode: number, count?: number | null): void; 55 | clear(mask?: number): void; 56 | clearColor(r: number, g: number, b: number, a: number): void; 57 | enable(cap: number): void; 58 | disable(cap: number): void; 59 | viewport(x: number, y: number, width: number, height: number): void; 60 | } 61 | -------------------------------------------------------------------------------- /lib/webgl2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var constants_1 = require("./constants"); 4 | var WebGL2 = /** @class */ (function () { 5 | function WebGL2(canvas) { 6 | this._context = canvas.getContext('webgl2'); 7 | this._programs = []; 8 | this._activeProgram = null; 9 | this._transformFeedbacks = []; 10 | this._textures = []; 11 | this._activeTexture = null; 12 | } 13 | /** 14 | * Adds the program to the `WebGL2` and returns ID number of the program. 15 | * If any program is activated yet, this method activates the program. 16 | * @param {Program} program 17 | * @returns {number} Program ID 18 | */ 19 | WebGL2.prototype.addProgram = function (program) { 20 | if (!program.isLinked) { 21 | program._link(this._context); 22 | } 23 | this._programs.push(program); 24 | if (this._activeProgram === null) { 25 | this._activeProgram = program; 26 | this._context.useProgram(program.glProgram); 27 | } 28 | var id = this._programs.length - 1; 29 | program.id = id; 30 | return id; 31 | }; 32 | /** 33 | * Adds the transform feedback to `WebGL2`. 34 | * @param {TransformFeedback} tf 35 | */ 36 | WebGL2.prototype.addTransformFeedback = function (tf) { 37 | this._transformFeedbacks.push(tf); 38 | tf._init(this._context); 39 | }; 40 | WebGL2.prototype.addTexture = function (texture) { 41 | var id = this._textures.length; 42 | this._textures.push(texture); 43 | texture._init(this._context, id); 44 | if (this._activeTexture === null) { 45 | texture.activate(); 46 | } 47 | }; 48 | /** 49 | * Activates a program and deactivates the previous program. 50 | * Throws an error when the program is not attached to WebGL2. 51 | * @param {Program} program 52 | */ 53 | WebGL2.prototype.activateProgram = function (program) { 54 | if (program.id === null) { 55 | throw new Error("This program is not added to WebGL2 yet. Add it by using addProgram method."); 56 | } 57 | else { 58 | this.activateProgramByID(program.id); 59 | } 60 | }; 61 | /** 62 | * Activates a program by ID and deactivates the previous program. 63 | * Throws an error when the ID does not exist. 64 | * @param {number} id 65 | */ 66 | WebGL2.prototype.activateProgramByID = function (id) { 67 | if (id > this._programs.length) { 68 | throw new Error("ID " + id + " does not exist."); 69 | } 70 | if (this._activeProgram !== null) { 71 | this._activeProgram.deactivate(); 72 | } 73 | var program = this._programs[id]; 74 | this._context.useProgram(program.glProgram); 75 | program.activate(); 76 | this._activeProgram = program; 77 | }; 78 | /** 79 | * Uses the program as a current program. 80 | * @param {Program} program 81 | */ 82 | WebGL2.prototype.useProgram = function (program) { 83 | if (program.id === null) { 84 | throw new Error("This program is not added to WebGL2 yet. Add it by using addProgram method."); 85 | } 86 | else { 87 | this.useProgramByID(program.id); 88 | } 89 | }; 90 | /** 91 | * Uses the program as a current program. 92 | * @param {number} id 93 | */ 94 | WebGL2.prototype.useProgramByID = function (id) { 95 | if (id > this._programs.length) { 96 | throw new Error("ID " + id + " does not exist."); 97 | } 98 | var program = this._programs[id]; 99 | this._context.useProgram(program.glProgram); 100 | this._activeProgram = program; 101 | }; 102 | WebGL2.prototype.activateTexture = function (texture) { 103 | }; 104 | /** 105 | * Deactivates the program. 106 | * @param {Program} program 107 | */ 108 | WebGL2.prototype.deactivateProgram = function (program) { 109 | program.deactivate(); 110 | }; 111 | WebGL2.prototype.draw = function (mode, count) { 112 | if (count === void 0) { count = null; } 113 | if (this._activeProgram !== null) { 114 | this._activeProgram.draw(mode, count); 115 | } 116 | }; 117 | WebGL2.prototype.clear = function (mask) { 118 | if (mask === void 0) { mask = constants_1.COLOR_BUFFER_BIT; } 119 | this._context.clear(mask); 120 | }; 121 | WebGL2.prototype.clearColor = function (r, g, b, a) { 122 | this._context.clearColor(r, b, g, a); 123 | }; 124 | WebGL2.prototype.enable = function (cap) { 125 | this._context.enable(cap); 126 | }; 127 | WebGL2.prototype.disable = function (cap) { 128 | this._context.disable(cap); 129 | }; 130 | WebGL2.prototype.viewport = function (x, y, width, height) { 131 | this._context.viewport(x, y, width, height); 132 | }; 133 | return WebGL2; 134 | }()); 135 | exports.WebGL2 = WebGL2; 136 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xenogl", 3 | "version": "0.1.1", 4 | "description": "A lightweight Object-Oriented wrapper for WebGL2", 5 | "main": "./lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "scripts": { 8 | "typedoc": "typedoc ./src --out ./docs --readme README.md && nodetouch ./docs/.nojekyll", 9 | "test": "jest", 10 | "webpack": "webpack", 11 | "build": "tsc && npm run typedoc && webpack" 12 | }, 13 | "keywords": [ 14 | "webgl" 15 | ], 16 | "author": "Koto Furumiya (https://sbfl.net/)", 17 | "license": "MIT", 18 | "files": [ 19 | "lib/" 20 | ], 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/kotofurumiya/xenogl.git" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/kotofurumiya/xenogl/issues", 27 | "email": "kotofurumiya@gmail.com" 28 | }, 29 | "devDependencies": { 30 | "@types/jest": "^22.1.2", 31 | "@types/webgl2": "0.0.2", 32 | "jest": "^22.2.2", 33 | "touch": "^3.1.0", 34 | "ts-jest": "^22.0.3", 35 | "typedoc": "^0.10.0", 36 | "typescript": "^2.7.1", 37 | "webpack": "^3.10.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './webgl2'; 3 | export * from './variable'; 4 | export * from './shader_program'; 5 | export * from './buffer'; 6 | export * from './vertex_array_object'; 7 | export * from './uniform_buffer_object'; 8 | export * from './transform_feedback'; 9 | export * from './texture'; -------------------------------------------------------------------------------- /src/shader_program.ts: -------------------------------------------------------------------------------- 1 | import { Buffer, ElementArrayBuffer } from './buffer'; 2 | import { Uniform } from './variable'; 3 | import { SEPARATE_ATTRIBS, INTERLEAVED_ATTRIBS, VERTEX_SHADER, FRAGMENT_SHADER, ELEMENT_ARRAY_BUFFER } from './constants'; 4 | import { VertexArrayObject } from './vertex_array_object'; 5 | import { UniformBufferObject } from './uniform_buffer_object'; 6 | 7 | export abstract class ShaderBase { 8 | protected _source: string; 9 | protected _glShader: WebGLShader | null; 10 | protected _isCompiled: boolean; 11 | protected _shaderType: number; 12 | 13 | constructor(source: string, shaderType: number) { 14 | this._source = source; 15 | this._glShader = null; 16 | this._isCompiled = false; 17 | this._shaderType = shaderType; 18 | } 19 | 20 | _compile(context: WebGL2RenderingContext) { 21 | const shader = context.createShader(this._shaderType); 22 | context.shaderSource(shader, this._source); 23 | context.compileShader(shader); 24 | 25 | const compileStatus = context.getShaderParameter(shader, context.COMPILE_STATUS); 26 | if(!compileStatus) { 27 | const info = context.getShaderInfoLog(shader); 28 | throw new Error(info); 29 | } 30 | 31 | this._glShader = shader; 32 | this._isCompiled = true; 33 | return shader; 34 | } 35 | 36 | /** 37 | * Returns if the shader is compiled. 38 | * @returns {boolean} 39 | */ 40 | get isCompiled(): boolean { 41 | return this._isCompiled; 42 | } 43 | 44 | /** 45 | * Returns `WebGLShader` when the shader is already compiled. 46 | * Otherwise throws an error. 47 | * @returns {WebGLShader} 48 | */ 49 | get glShader(): WebGLShader { 50 | if(!this._glShader === null) { 51 | throw new Error('This shader is not compiled yet.'); 52 | } 53 | 54 | return this._glShader; 55 | } 56 | } 57 | 58 | /** 59 | * A vertex shader. 60 | */ 61 | export class VertexShader extends ShaderBase { 62 | constructor(source: string) { 63 | super(source, VERTEX_SHADER); 64 | } 65 | } 66 | 67 | /** 68 | * A fragment shader. 69 | */ 70 | export class FragmentShader extends ShaderBase { 71 | constructor(source: string) { 72 | super(source, FRAGMENT_SHADER); 73 | } 74 | } 75 | 76 | /** 77 | * A shader program. 78 | */ 79 | export class Program { 80 | protected _vertexShader: VertexShader; 81 | protected _fragmentShader: FragmentShader; 82 | protected _feedbackVaryings: string[]; 83 | protected _feedbackBufferMode: number; 84 | protected _isLinked: boolean; 85 | 86 | protected _glContext: WebGL2RenderingContext | null; 87 | protected _glProgram: WebGLProgram | null; 88 | 89 | protected _initializedBuffers: Buffer[]; 90 | protected _uninitializedBuffers: Buffer[]; 91 | protected _currentIndexBuffer: ElementArrayBuffer | null; 92 | 93 | protected _initializedUniforms: Uniform[]; 94 | protected _uninitializedUniforms: Uniform[]; 95 | 96 | protected _initializedVertexArrayObjects: VertexArrayObject[]; 97 | protected _uninitializedVertexArrayObject: VertexArrayObject[]; 98 | protected _currentVertexArrayObject: VertexArrayObject | null; 99 | 100 | protected _initializedUniformBufferObjects: UniformBufferObject[]; 101 | protected _uninitializedUniformBufferObjects: UniformBufferObject[]; 102 | 103 | id: number | null; 104 | 105 | constructor(args: { 106 | vertexShader: VertexShader; 107 | fragmentShader: FragmentShader; 108 | feedbackVaryings?: string[]; 109 | feedbackBufferMode?: number 110 | }) { 111 | this._vertexShader = args.vertexShader; 112 | this._fragmentShader = args.fragmentShader; 113 | this._feedbackVaryings = ('feedbackVaryings' in args) ? args.feedbackVaryings : []; 114 | this._feedbackBufferMode = ('feedbackBufferMode' in args) ? args.feedbackBufferMode : INTERLEAVED_ATTRIBS; 115 | this._isLinked = false; 116 | 117 | this._glContext = null; 118 | this._glProgram = null; 119 | 120 | this._initializedBuffers = []; 121 | this._uninitializedBuffers = []; 122 | 123 | this._initializedUniforms = []; 124 | this._uninitializedUniforms = []; 125 | 126 | this._initializedVertexArrayObjects = []; 127 | this._uninitializedVertexArrayObject = []; 128 | 129 | this._initializedUniformBufferObjects = []; 130 | this._uninitializedUniformBufferObjects = []; 131 | 132 | this._currentIndexBuffer = null; 133 | this._currentVertexArrayObject = null; 134 | 135 | this.id = null; 136 | } 137 | 138 | /** 139 | * Adds a buffer to the program. 140 | * @param {Buffer} buffer 141 | */ 142 | addBuffer(buffer: Buffer): void { 143 | if(buffer.bufferType === ELEMENT_ARRAY_BUFFER) { 144 | this._currentIndexBuffer = buffer; 145 | } 146 | 147 | if(this.isLinked) { 148 | buffer._initOnce(this._glContext, this._glProgram); 149 | if(buffer.bufferType === ELEMENT_ARRAY_BUFFER && this._glContext !== null) { 150 | this._glContext.bindBuffer(ELEMENT_ARRAY_BUFFER, buffer.glBuffer); 151 | } 152 | this._initializedBuffers.push(buffer); 153 | } else { 154 | if(buffer.isInitialized) { 155 | this._initializedBuffers.push(buffer); 156 | } else { 157 | this._uninitializedBuffers.push(buffer); 158 | } 159 | } 160 | } 161 | 162 | /** 163 | * Activates the `ElementArrayBuffer` as a index buffer. 164 | * @param {ElementArrayBuffer} buffer 165 | */ 166 | activateElementArrayBuffer(buffer: ElementArrayBuffer) { 167 | this._currentIndexBuffer = buffer; 168 | 169 | if(this.isLinked && this._glContext !== null) { 170 | this._glContext.bindBuffer(ELEMENT_ARRAY_BUFFER, buffer.glBuffer); 171 | } 172 | } 173 | 174 | /** 175 | * Adds an uniform variable to the program. 176 | * @param {Uniform} uniform 177 | */ 178 | addUniform(uniform: Uniform): void { 179 | if(this.isLinked) { 180 | uniform._init(this._glContext, this._glProgram); 181 | this._initializedUniforms.push(uniform); 182 | } else { 183 | this._uninitializedUniforms.push(uniform); 184 | } 185 | } 186 | 187 | /** 188 | * Adds a `VertexArrayObject` to the program. 189 | * @param {VertexArrayObject} vao 190 | */ 191 | addVertexArrayObject(vao: VertexArrayObject): void { 192 | if(this.isLinked) { 193 | vao._init(this._glContext, this._glProgram); 194 | this._initializedVertexArrayObjects.push(vao); 195 | this._initializedBuffers.push(vao.buffer); 196 | } else { 197 | this._uninitializedVertexArrayObject.push(vao); 198 | } 199 | } 200 | 201 | /** 202 | * Activates the `VertexArrayObject`. 203 | * @param {VertexArrayObject} vao 204 | */ 205 | activateVertexArrayObject(vao: VertexArrayObject): void { 206 | this._currentVertexArrayObject = vao; 207 | if(this.isLinked) { 208 | const context = this._glContext; 209 | context.bindVertexArray(vao.glVertexArrayObject); 210 | } 211 | } 212 | 213 | /** 214 | * Adds an `UniformBufferObject` to the program. 215 | * @param {UniformBufferObject} ubo 216 | */ 217 | addUniformBufferObject(ubo: UniformBufferObject) { 218 | if(this.isLinked) { 219 | const index = this._initializedUniformBufferObjects.length; 220 | ubo._init(this._glContext, this._glProgram, index); 221 | this._initializedUniformBufferObjects.push(ubo); 222 | } else { 223 | this._uninitializedUniformBufferObjects.push(ubo); 224 | } 225 | } 226 | 227 | /** 228 | * Issues a draw call, which draws graphics. 229 | * @param {number} mode 230 | * @param {number | null} count 231 | */ 232 | draw(mode: number, count: number | null = null): void { 233 | if(this._glContext !== null) { 234 | if(this._currentIndexBuffer !== null && this._currentIndexBuffer.data !== null) { 235 | this._glContext.drawElements(mode, this._currentIndexBuffer.data.length, this._currentIndexBuffer.dataType, 0); 236 | } else if(this._initializedBuffers.length > 0){ 237 | const c = (count !== null) ? count : this._initializedBuffers[0].dataCount; 238 | this._glContext.drawArrays(mode, 0, c); 239 | } 240 | } 241 | } 242 | 243 | activate(): void { 244 | this._initializedBuffers.forEach((b) => b.activate()); 245 | } 246 | 247 | deactivate(): void { 248 | this._initializedBuffers.forEach((b) => b.deactivate()); 249 | } 250 | 251 | /** 252 | * Links the shader program. 253 | * This method is called internally. So you don't have to call this method manually. 254 | * @param {WebGL2RenderingContext} context 255 | */ 256 | _link(context: WebGL2RenderingContext) { 257 | // compile shaders. 258 | this._vertexShader._compile(context); 259 | this._fragmentShader._compile(context); 260 | 261 | // create a program. 262 | const program = context.createProgram(); 263 | context.attachShader(program, this._vertexShader.glShader); 264 | context.attachShader(program, this._fragmentShader.glShader); 265 | 266 | if(this._feedbackVaryings.length > 0) { 267 | context.transformFeedbackVaryings(program, this._feedbackVaryings, this._feedbackBufferMode); 268 | } 269 | 270 | context.linkProgram(program); 271 | 272 | const linkStatus = context.getProgramParameter(program, context.LINK_STATUS); 273 | if(!linkStatus) { 274 | const info = context.getProgramInfoLog(program); 275 | throw new Error(info); 276 | } 277 | 278 | this._glContext = context; 279 | this._glProgram = program; 280 | this._isLinked = true; 281 | 282 | // initialize buffers. 283 | let buffer = null; 284 | while(buffer = this._uninitializedBuffers.shift()) { 285 | buffer._init(context, program); 286 | if(buffer.bufferType === ELEMENT_ARRAY_BUFFER && this._currentIndexBuffer === null) { 287 | this._currentIndexBuffer = buffer; 288 | } 289 | this._initializedBuffers.push(buffer); 290 | } 291 | 292 | if(this._currentIndexBuffer !== null) { 293 | context.bindBuffer(ELEMENT_ARRAY_BUFFER, this._currentIndexBuffer); 294 | } 295 | 296 | // initialize uniforms. 297 | let uniform = null; 298 | while(uniform = this._uninitializedUniforms.shift()) { 299 | uniform._init(context, program); 300 | this._initializedUniforms.push(uniform); 301 | } 302 | 303 | // initialize VertexArrayObjects. 304 | let vao = null; 305 | while(vao = this._uninitializedVertexArrayObject.shift()) { 306 | vao._init(context, program); 307 | this._initializedVertexArrayObjects.push(vao); 308 | this._initializedBuffers.push(vao.buffer); 309 | } 310 | 311 | if(this._currentVertexArrayObject !== null) { 312 | context.bindVertexArray(this._currentVertexArrayObject.glVertexArrayObject); 313 | } 314 | 315 | // initialize UniformBufferObjects 316 | let ubo = null; 317 | while(ubo = this._uninitializedUniformBufferObjects.shift()) { 318 | const index = this._initializedUniformBufferObjects.length; 319 | ubo._init(context, program, index); 320 | this._initializedUniformBufferObjects.push(ubo); 321 | } 322 | } 323 | 324 | /** 325 | * Returns if the program is linked. 326 | * @returns {boolean} 327 | */ 328 | get isLinked(): boolean { 329 | return this._isLinked; 330 | } 331 | 332 | /** 333 | * Returns `WebGLProgram` when the program is already linked. 334 | * Otherwise throws an error. 335 | * @returns {WebGLProgram} 336 | */ 337 | get glProgram(): WebGLProgram { 338 | if(this._glProgram === null) { 339 | throw new Error(`This program is not linked yet.`); 340 | } 341 | 342 | return this._glProgram; 343 | } 344 | } -------------------------------------------------------------------------------- /src/texture.ts: -------------------------------------------------------------------------------- 1 | import { TEXTURE_2D, RGBA, UNSIGNED_BYTE, TEXTURE0 } from './constants'; 2 | 3 | export type TextureSource = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | ImageData; 4 | 5 | export interface Texture { 6 | activate(): void; 7 | _init(context: WebGL2RenderingContext, textureNumber: number): void; 8 | } 9 | 10 | export abstract class TextureBase implements Texture { 11 | abstract activate(): void; 12 | abstract _init(context: WebGL2RenderingContext, textureNumber: number): void; 13 | 14 | protected _getTextureIdFromNumber(n: number) { 15 | return TEXTURE0 + n; 16 | } 17 | } 18 | 19 | export class Texture2D extends TextureBase { 20 | protected _source: TextureSource | ArrayBufferView; 21 | protected _glContext: WebGL2RenderingContext | null; 22 | protected _glTexture: WebGLTexture | null; 23 | protected _textureID: number | null; 24 | 25 | protected _target: number; 26 | protected _mipmapLevel: number; 27 | protected _internalFormat: number; 28 | protected _format: number; 29 | protected _dataType: number; 30 | protected _width?: number; 31 | protected _height?: number; 32 | 33 | protected _flushData: Function; 34 | 35 | constructor(dataSource: TextureSource | ArrayBufferView, options: { 36 | target?: number, 37 | mipmapLevel?: number, 38 | internalFormat?: number, 39 | format?: number, 40 | dataType?: number, 41 | width?: number, 42 | height?: number 43 | } = {}) { 44 | super(); 45 | this._source = dataSource; 46 | this._glContext = null; 47 | this._glTexture = null; 48 | this._textureID = null; 49 | 50 | this._target = ('target' in options) ? options.target : TEXTURE_2D; 51 | this._mipmapLevel = ('mipmapLevel' in options) ? options.mipmapLevel : 0; 52 | this._internalFormat = ('internalFormat' in options) ? options.internalFormat : RGBA; 53 | this._format = ('format' in options) ? options.mipmapLevel : RGBA; 54 | this._dataType = ('dataType' in options) ? options.mipmapLevel : UNSIGNED_BYTE; 55 | 56 | this._width = ('width' in options) ? options.width : undefined; 57 | this._height = ('height' in options) ? options.height : undefined; 58 | 59 | this._flushData = () => {}; 60 | } 61 | 62 | activate(): void { 63 | this._flushData = (context: WebGL2RenderingContext) => { 64 | context.activeTexture(this._textureID); 65 | }; 66 | } 67 | 68 | _init(context: WebGL2RenderingContext, textureNumber: number): void { 69 | this._glContext = context; 70 | this._textureID = this._getTextureIdFromNumber(textureNumber); 71 | context.activeTexture(this._textureID); 72 | 73 | this._glTexture = context.createTexture(); 74 | context.bindTexture(this._target, this._glTexture); 75 | 76 | if(typeof this._width === 'undefined' || typeof this._height === 'undefined') { 77 | context.texImage2D(this._target, this._mipmapLevel, this._internalFormat, 78 | this._format, this._dataType, this._source); 79 | } else { 80 | context.texImage2D(this._target, this._mipmapLevel, this._internalFormat, 81 | this._width, this._height, 0, this._format, 82 | this._dataType, this._source); 83 | } 84 | 85 | context.generateMipmap(this._target); 86 | 87 | this._flush(); 88 | } 89 | 90 | _flush() { 91 | if(this._glContext !== null) { 92 | this._flushData(this._glContext); 93 | this._flushData = () => {}; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /src/transform_feedback.ts: -------------------------------------------------------------------------------- 1 | import { TRANSFORM_FEEDBACK, TRANSFORM_FEEDBACK_BUFFER } from './constants'; 2 | import { Buffer } from './buffer'; 3 | 4 | export class TransformFeedback { 5 | protected _glContext: WebGL2RenderingContext | null; 6 | protected _glTransformFeedback: WebGLTransformFeedback | null; 7 | 8 | constructor() { 9 | this._glContext = null; 10 | this._glTransformFeedback = null; 11 | } 12 | 13 | feedback(args: {mode: number, targetBuffers: Buffer[], count: number}) { 14 | if(this._glContext === null) { 15 | throw new Error('This transform feedback is not added to any WebGL2 yet.'); 16 | } 17 | 18 | for(let i = 0; i < args.targetBuffers.length; i++) { 19 | this._glContext.bindBufferBase(TRANSFORM_FEEDBACK_BUFFER, i, args.targetBuffers[i].glBuffer); 20 | } 21 | 22 | this._glContext.beginTransformFeedback(args.mode); 23 | this._glContext.drawArrays(args.mode, 0, args.count); 24 | this._glContext.endTransformFeedback(); 25 | 26 | for(let i = 0; i < args.targetBuffers.length; i++) { 27 | this._glContext.bindBufferBase(TRANSFORM_FEEDBACK_BUFFER, i, null); 28 | } 29 | } 30 | 31 | _init(context: WebGL2RenderingContext) { 32 | this._glContext = context; 33 | this._glTransformFeedback = context.createTransformFeedback(); 34 | context.bindTransformFeedback(TRANSFORM_FEEDBACK, this._glTransformFeedback); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/uniform_buffer_object.ts: -------------------------------------------------------------------------------- 1 | import { UniformBuffer } from './buffer' 2 | import { FLOAT, STATIC_DRAW, UNIFORM_BUFFER } from './constants'; 3 | import { Attribute, TypedArrayLike } from './variable'; 4 | 5 | /** 6 | * An uniform buffer object. 7 | */ 8 | export class UniformBufferObject { 9 | protected _buffer: UniformBuffer; 10 | protected _blockName: string; 11 | protected _blockIndex: number | null; 12 | protected _javascriptIndex: number | null; 13 | protected _isInitialized: boolean; 14 | 15 | constructor(blockName: string, bufferOrBufferArgs: UniformBuffer | { 16 | dataOrLength?: TypedArrayLike | number | null, 17 | dataType?: number, 18 | usage?: number 19 | } = {dataOrLength: null, dataType: FLOAT, usage: STATIC_DRAW}) { 20 | this._blockName = blockName; 21 | this._blockIndex = null; 22 | this._javascriptIndex = null; 23 | this._isInitialized = false; 24 | 25 | if(bufferOrBufferArgs instanceof UniformBuffer) { 26 | this._buffer = bufferOrBufferArgs; 27 | } else { 28 | this._buffer = new UniformBuffer(bufferOrBufferArgs); 29 | } 30 | } 31 | 32 | /** 33 | * Initializes the uniform buffer object. 34 | * Do not call this method manually. 35 | * @param {WebGL2RenderingContext} context 36 | * @param {WebGLProgram} program 37 | * @param {number} jsIndex 38 | * @private 39 | */ 40 | _init(context: WebGL2RenderingContext, program: WebGLProgram, jsIndex: number) { 41 | this._blockIndex = context.getUniformBlockIndex(program, this._blockName); 42 | this._javascriptIndex = jsIndex; 43 | 44 | context.uniformBlockBinding(program, this._blockIndex, jsIndex); 45 | 46 | this._buffer._initOnce(context, program); 47 | 48 | context.bindBufferBase(UNIFORM_BUFFER, jsIndex, this._buffer.glBuffer); 49 | } 50 | } -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import {FLOAT, SHORT, UNSIGNED_SHORT, BYTE, UNSIGNED_BYTE, HALF_FLOAT} from './constants'; 2 | 3 | export function getBytesPerElementByGlType(type: number): number | null { 4 | if (type === FLOAT) { 5 | return 4; 6 | } else if (type === BYTE || type === UNSIGNED_BYTE) { 7 | return 1; 8 | } else if (type === SHORT || type === UNSIGNED_SHORT || type === HALF_FLOAT) { 9 | return 2; 10 | } else { 11 | return null; 12 | } 13 | } -------------------------------------------------------------------------------- /src/variable.ts: -------------------------------------------------------------------------------- 1 | import { FLOAT, INT, UNSIGNED_INT } from './constants'; 2 | 3 | export type TypedArrayLike = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; 4 | 5 | /** 6 | * An attribute variable. 7 | */ 8 | export class Attribute { 9 | protected _name: string; 10 | protected _size: number; 11 | 12 | constructor(name: string, size: number) { 13 | this._name = name; 14 | this._size = size; 15 | } 16 | 17 | equals(other: Attribute): boolean { 18 | return this.name === other.name && this.size === other.size; 19 | } 20 | 21 | get name(): string { 22 | return this._name; 23 | } 24 | 25 | get size(): number { 26 | return this._size; 27 | } 28 | } 29 | 30 | /** 31 | * An uniform variable. 32 | */ 33 | export class Uniform { 34 | protected _name: string; 35 | protected _location: WebGLUniformLocation | null; 36 | protected _glContext: WebGL2RenderingContext | null; 37 | protected _glProgram: WebGLProgram | null; 38 | protected _flushData: (context: WebGL2RenderingContext, location: WebGLUniformLocation) => void; 39 | 40 | constructor(name: string) { 41 | this._name = name; 42 | this._location = null; 43 | this._glContext = null; 44 | this._glProgram = null; 45 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => {}; 46 | } 47 | 48 | /** 49 | * Sets the uniform variable to the value. 50 | * @param {number} value 51 | * @param {number} type 52 | */ 53 | setValue(value: number, type: number) { 54 | if(type === FLOAT) { 55 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 56 | context.uniform1f(location, value); 57 | }; 58 | } else if (type === INT) { 59 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 60 | context.uniform1i(location, value); 61 | }; 62 | } else if (type === UNSIGNED_INT) { 63 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 64 | context.uniform1ui(location, value); 65 | }; 66 | } 67 | 68 | this._flush(); 69 | } 70 | 71 | /** 72 | * Sets the uniform variable to the vector. 73 | * @param {TypedArrayLike} value 74 | * @param {number} type 75 | */ 76 | setVector(value: TypedArrayLike, type: number) { 77 | const length = value.length; 78 | 79 | if(length === 1) { 80 | this.setVector1(value, type); 81 | } else if(length === 2) { 82 | this.setVector2(value, type); 83 | } else if(length === 3) { 84 | this.setVector3(value, type); 85 | } else if(length === 4) { 86 | this.setVector4(value, type); 87 | } else { 88 | throw new Error(`Length of value must be 1, 2, 3 or 4. Your value length is ${length}`); 89 | } 90 | } 91 | 92 | setVector1(value: TypedArrayLike, type: number) { 93 | if(type === FLOAT) { 94 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 95 | context.uniform1fv(location, value); 96 | }; 97 | } else if (type === INT) { 98 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 99 | context.uniform1iv(location, value); 100 | }; 101 | } else if (type === UNSIGNED_INT) { 102 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 103 | context.uniform1uiv(location, value); 104 | }; 105 | } 106 | 107 | this._flush(); 108 | } 109 | 110 | setVector2(value: TypedArrayLike, type: number) { 111 | if(type === FLOAT) { 112 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 113 | context.uniform2fv(location, value); 114 | }; 115 | } else if (type === INT) { 116 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 117 | context.uniform2iv(location, value); 118 | }; 119 | } else if (type === UNSIGNED_INT) { 120 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 121 | context.uniform2uiv(location, value); 122 | }; 123 | } 124 | 125 | this._flush(); 126 | } 127 | 128 | setVector3(value: TypedArrayLike, type: number) { 129 | if(type === FLOAT) { 130 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 131 | context.uniform3fv(location, value); 132 | }; 133 | } else if (type === INT) { 134 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 135 | context.uniform3iv(location, value); 136 | }; 137 | } else if (type === UNSIGNED_INT) { 138 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 139 | context.uniform3uiv(location, value); 140 | }; 141 | } 142 | 143 | this._flush(); 144 | } 145 | 146 | setVector4(value: TypedArrayLike, type: number) { 147 | if(type === FLOAT) { 148 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 149 | context.uniform4fv(location, value); 150 | }; 151 | } else if (type === INT) { 152 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 153 | context.uniform4iv(location, value); 154 | }; 155 | } else if (type === UNSIGNED_INT) { 156 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 157 | context.uniform4uiv(location, value); 158 | }; 159 | } 160 | 161 | this._flush(); 162 | } 163 | 164 | /** 165 | * Sets the uniform variable to the matrix. 166 | * @param {Float32Array} value 167 | */ 168 | setMatrix(value: Float32Array) { 169 | const size = value.length; 170 | if(size === 4) { 171 | this.setMatrix2(value); 172 | } else if(size === 9) { 173 | this.setMatrix3(value); 174 | } else if(size === 16) { 175 | this.setMatrix4(value); 176 | } else { 177 | throw new Error(`Failed to detect size of the matrix. If you use a non-square matrix, use setMatrixNxN instead.`); 178 | } 179 | } 180 | 181 | setMatrix2(value: Float32Array): void { 182 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 183 | context.uniformMatrix2fv(location, false, value); 184 | }; 185 | 186 | this._flush(); 187 | } 188 | 189 | setMatrix3(value: Float32Array): void { 190 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 191 | context.uniformMatrix3fv(location, false, value); 192 | }; 193 | 194 | this._flush(); 195 | } 196 | 197 | setMatrix4(value: Float32Array): void { 198 | this._flushData = (context: WebGL2RenderingContext, location: WebGLUniformLocation) => { 199 | context.uniformMatrix4fv(location, false, value); 200 | }; 201 | 202 | this._flush(); 203 | } 204 | 205 | _flush() { 206 | if(this.isLocated && this._glContext !== null) { 207 | this._flushData(this._glContext, this._location); 208 | } 209 | } 210 | 211 | _init(context: WebGL2RenderingContext, program: WebGLProgram) { 212 | this._location = context.getUniformLocation(program, this._name); 213 | this._glContext = context; 214 | this._glProgram = program; 215 | this._flush(); 216 | } 217 | 218 | get isLocated(): boolean { 219 | return this._location !== null; 220 | } 221 | } -------------------------------------------------------------------------------- /src/vertex_array_object.ts: -------------------------------------------------------------------------------- 1 | import { Attribute, TypedArrayLike } from './variable'; 2 | import { Buffer } from './buffer'; 3 | import { ARRAY_BUFFER, STATIC_DRAW } from './constants'; 4 | import { getBytesPerElementByGlType } from './utils'; 5 | 6 | export class VertexArrayObject { 7 | protected _buffer: Buffer; 8 | protected _glContext: WebGL2RenderingContext | null; 9 | protected _glVertexArrayObject: WebGLVertexArrayObject | null; 10 | protected _enabledAttributes: Attribute[] | null; 11 | 12 | protected _mustWriteData: boolean; 13 | protected _dataOrLength?: TypedArrayLike | number; 14 | 15 | protected _isInitialized: boolean; 16 | 17 | constructor(buffer: Buffer, options: { 18 | dataOrLength?: TypedArrayLike | number, 19 | attributes?: Attribute[] 20 | } = {}) { 21 | this._buffer = buffer; 22 | this._glContext = null; 23 | this._glVertexArrayObject = null; 24 | this._enabledAttributes = ('attributes' in options) ? options.attributes : null; 25 | this._mustWriteData = 'dataOrLength' in options; 26 | 27 | if(this._mustWriteData) { 28 | this._dataOrLength = options.dataOrLength; 29 | } 30 | 31 | this._isInitialized = false; 32 | } 33 | 34 | /** 35 | * Initializes the vertex array object. 36 | * Do not call this method manually. 37 | * @param {WebGL2RenderingContext} context 38 | * @param {WebGLProgram} program 39 | * @private 40 | */ 41 | _init(context: WebGL2RenderingContext, program: WebGLProgram) { 42 | if(this._mustWriteData) { 43 | this._buffer.bufferData(this._dataOrLength); 44 | } 45 | 46 | this._buffer._initOnce(context, program, this._enabledAttributes); 47 | 48 | const vao = this._buffer._createWebGLVertexArrayObject(context, program, this._enabledAttributes); 49 | 50 | this._glContext = context; 51 | this._glVertexArrayObject = vao; 52 | 53 | this._isInitialized = true; 54 | } 55 | 56 | /** 57 | * Returns buffer bound to the vertex array object. 58 | * @returns {Buffer} 59 | */ 60 | get buffer(): Buffer { 61 | return this._buffer; 62 | } 63 | 64 | /** 65 | * Returns `WebGLVertexArrayObject` if the vertex array object is initialized. 66 | * Otherwise, throws an error. 67 | * @returns {WebGLVertexArrayObject} 68 | */ 69 | get glVertexArrayObject(): WebGLVertexArrayObject { 70 | if(this._isInitialized) { 71 | return this._glVertexArrayObject; 72 | } else { 73 | throw new Error('This vertex array object is not added to any program yet.'); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/webgl2.ts: -------------------------------------------------------------------------------- 1 | import { Program } from './shader_program'; 2 | import { COLOR_BUFFER_BIT } from './constants'; 3 | import { TransformFeedback } from './transform_feedback'; 4 | import { Texture } from './texture'; 5 | 6 | export class WebGL2 { 7 | protected _context: WebGL2RenderingContext; 8 | protected _programs: Array; 9 | protected _activeProgram: Program | null; 10 | protected _transformFeedbacks: Array; 11 | protected _textures: Texture[]; 12 | protected _activeTexture: Texture | null; 13 | 14 | constructor(canvas: HTMLCanvasElement) { 15 | this._context = canvas.getContext('webgl2'); 16 | this._programs = []; 17 | this._activeProgram = null; 18 | this._transformFeedbacks = []; 19 | this._textures = []; 20 | this._activeTexture = null; 21 | } 22 | 23 | /** 24 | * Adds the program to the `WebGL2` and returns ID number of the program. 25 | * If any program is activated yet, this method activates the program. 26 | * @param {Program} program 27 | * @returns {number} Program ID 28 | */ 29 | addProgram(program: Program): number { 30 | if(!program.isLinked) { 31 | program._link(this._context); 32 | } 33 | 34 | this._programs.push(program); 35 | 36 | if(this._activeProgram === null) { 37 | this._activeProgram = program; 38 | this._context.useProgram(program.glProgram); 39 | } 40 | 41 | const id = this._programs.length - 1; 42 | program.id = id; 43 | 44 | return id; 45 | } 46 | 47 | /** 48 | * Adds the transform feedback to `WebGL2`. 49 | * @param {TransformFeedback} tf 50 | */ 51 | addTransformFeedback(tf: TransformFeedback) { 52 | this._transformFeedbacks.push(tf); 53 | tf._init(this._context); 54 | } 55 | 56 | addTexture(texture: Texture) { 57 | const id = this._textures.length; 58 | this._textures.push(texture); 59 | texture._init(this._context, id); 60 | 61 | if(this._activeTexture === null) { 62 | texture.activate(); 63 | } 64 | } 65 | 66 | /** 67 | * Activates a program and deactivates the previous program. 68 | * Throws an error when the program is not attached to WebGL2. 69 | * @param {Program} program 70 | */ 71 | activateProgram(program: Program) { 72 | if(program.id === null) { 73 | throw new Error(`This program is not added to WebGL2 yet. Add it by using addProgram method.`); 74 | } else { 75 | this.activateProgramByID(program.id); 76 | } 77 | } 78 | 79 | /** 80 | * Activates a program by ID and deactivates the previous program. 81 | * Throws an error when the ID does not exist. 82 | * @param {number} id 83 | */ 84 | activateProgramByID(id: number): void { 85 | if(id > this._programs.length) { 86 | throw new Error(`ID ${id} does not exist.`); 87 | } 88 | 89 | if(this._activeProgram !== null) { 90 | this._activeProgram.deactivate(); 91 | } 92 | 93 | const program = this._programs[id]; 94 | this._context.useProgram(program.glProgram); 95 | program.activate(); 96 | 97 | this._activeProgram = program; 98 | } 99 | 100 | /** 101 | * Uses the program as a current program. 102 | * @param {Program} program 103 | */ 104 | useProgram(program: Program) { 105 | if(program.id === null) { 106 | throw new Error(`This program is not added to WebGL2 yet. Add it by using addProgram method.`); 107 | } else { 108 | this.useProgramByID(program.id); 109 | } 110 | } 111 | 112 | /** 113 | * Uses the program as a current program. 114 | * @param {number} id 115 | */ 116 | useProgramByID(id: number) { 117 | if(id > this._programs.length) { 118 | throw new Error(`ID ${id} does not exist.`); 119 | } 120 | 121 | const program = this._programs[id]; 122 | this._context.useProgram(program.glProgram); 123 | 124 | this._activeProgram = program; 125 | } 126 | 127 | activateTexture(texture: Texture) { 128 | 129 | } 130 | 131 | /** 132 | * Deactivates the program. 133 | * @param {Program} program 134 | */ 135 | deactivateProgram(program: Program): void { 136 | program.deactivate(); 137 | } 138 | 139 | draw(mode: number, count: number | null = null): void { 140 | if(this._activeProgram !== null) { 141 | this._activeProgram.draw(mode, count); 142 | } 143 | } 144 | 145 | clear(mask: number = COLOR_BUFFER_BIT): void { 146 | this._context.clear(mask); 147 | } 148 | 149 | clearColor(r: number, g: number, b: number, a: number) { 150 | this._context.clearColor(r, b, g, a); 151 | } 152 | 153 | enable(cap: number): void { 154 | this._context.enable(cap); 155 | } 156 | 157 | disable(cap: number): void { 158 | this._context.disable(cap); 159 | } 160 | 161 | viewport(x: number, y: number, width: number, height: number): void { 162 | this._context.viewport(x, y, width, height); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "outDir": "lib", 6 | "newLine": "LF", 7 | "sourceMap": false, 8 | "declaration": true, 9 | "strict": true, 10 | "suppressImplicitAnyIndexErrors": true, 11 | 12 | "lib": [ "dom", "es2016" ] 13 | }, 14 | 15 | "include": [ "src/**/*" ], 16 | 17 | "exclude": [ "node_modules" ] 18 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: './lib/index.js', 6 | output: { 7 | filename: 'xenogl.min.js', 8 | path: path.resolve('build'), 9 | library: "XenoGL", 10 | libraryTarget: "window", 11 | }, 12 | plugins: [ 13 | new webpack.DefinePlugin({'process.env': { NODE_ENV: JSON.stringify('production') }}), 14 | new webpack.optimize.UglifyJsPlugin() 15 | ] 16 | }; --------------------------------------------------------------------------------