0

In the browser there is not a gl object until you make one:

const gl = canvas.getContext('webgl2')

This means that there it is challenging to reference any of the gl properties (like gl.createBuffer or gl.ARRAY_BUFFER) in something like a class.

In C++ these objects are included and therefore accessible without a a particular instance of gl.

How can I create a class which has a member variable whose value is set to some property of a gl object?

For instance:

class App {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

I think the most common way is to pass in a gl instance into the constructor (i.e.):

class App {
  constructor (gl) {
     this.VBO = gl.createBuffer() // gl is passed in
  }
}

but this seems like it would get annoying if I have to make hundreds of different calls and pass in a gl object each time.

Additionally I guess I could define some sort of global gl object: gl = canvas.getContext('webgl2') and then just assume that there is some global gl object everywhere it needs to be accessed, but this seems like a very bad idea.

I would appreciate any ideas on a good, clean design paradigm to get around these issues.

4
  • 1
    add that variable to that class prototype. Then you can access it like this.g1 Commented May 1, 2017 at 6:56
  • But if I have 100 classes, I would have to add it each of those classes too right? Is this better than just passing it to every function? Commented May 1, 2017 at 7:02
  • What is the problem? The class constructor is only executed when you create an object of that class.... so just make sure you define gl before instantiating those class objects. Commented May 1, 2017 at 7:17
  • @Startec use extends keyword otherwise. See my answer below Commented May 1, 2017 at 7:29

4 Answers 4

1

The only thing you need to do is make sure you don't execute any of your class instantiating code before you have assigned a value to gl, and then define gl in the same context as the classes. For example:

document.addEventListener('DOMContentLoaded', function() {
    class App {
        constructor () {
             this.VBO = gl.createBuffer() // gl is defined when getting here
        }
    }

    const canvas = document.getElementById('mycanvas'),
          gl = canvas.getContext('webgl2'),
          app = new App();
    // ... etc
});

If your classes are defined outside of a function context and this cannot be changed, then define gl on the global object:

class App {
    constructor () {
         this.VBO = window.gl.createBuffer() // gl is defined when getting here
    }
}

document.addEventListener('DOMContentLoaded', function() {
    var canvas = document.getElementById('mycanvas');
    window.gl = canvas.getContext('webgl2');
    var app = new App();
    // ...etc
});
Sign up to request clarification or add additional context in comments.

2 Comments

I like this. I would be concerned about the global variables but I guess I could also wrap it inside an anonymous function
The first solution uses the event callback as such an anonymous function. The second solution should only be used if you cannot move your classes inside such a function for some reason. NB: the window. prefix is optional of course, I just added it to clarify that in the second fall-back solution gl is global.
1

I think the most common way is to pass in a gl instance into the constructor (i.e.):

class App {
  constructor (gl) {
     this.VBO = gl.createBuffer() // gl is passed in
  }
}

but this seems like it would get annoying if I have to make hundreds of different calls and pass in a gl object each time.

Thats the common way for good reason. Searching the scope-chain until you reach a "gl" object on global scope is much slower, especially if you call it a hundred times in different functions per frame.

It is better to pass the "gl"-object to a class and create an instance-property-reference - so you can access "this.gl" in prototype-Functions, too - without any performance-critical scope-chain-lookups outside the class.

class App {
  constructor(gl) { //pass gl
     this.gl = gl; // always create a instance-property for fast access
     this.VBO = this.gl.createBuffer(); // access methods through "this.gl"
     this.foo = new FooGL(gl); // pass "gl" to other classes
  }

  abc() {
     this.gl.doSomeThingABC(); // access methods through "this.gl"
     this.foo.doSomething(); // FooGL has his own "gl" instance-property
                             // to access methods through its own "this.gl"
  }
}
// or
App.prototype.xyz = function()
{
    return this.gl.doSomeThingXYZ(); // access methods through "this.gl"
}

const gl = document.createElement('canvas').getContext('webgl2');
const app = new App(gl);

Thats the best method for high performance, even if its more code to write. If you work with WebGL, good performance is the most important to achieve a high framerate.

Of course you can do anything else like extending classes, create singletons or access global properties. But if you want "good, clean [and performant] design", always pass the object-references and create a local property for fast access. Don't save on the wrong place.

Comments

0

One thing you can do to access that property inside all the instance is to assign that variable to that class's prototype.

Also you can use extends keyword to extend the properties from parent class. In the below code App and App2 use the same function fun2 from Parent protype.

class Parent{
  constructor() {
    this.fun = function(){
     return 'An instance property '
    }
  } 
}

Parent.prototype.fun2 = function(){
  return 'not an instance property'
}

class App extends Parent{
 
  constructor () {
     super();
     this.VBO = App.gl.createBuffer() 
  }
}

App.gl = {
 createBuffer : function(){
   console.log('from App prototype ')
 }
}

var a = new App();
console.log(a.fun())

class App2 extends Parent{

}

var a2 = new App2();
console.log(a2.fun())
console.log(a2.fun2())

3 Comments

fun is not a property on the prototype, it is an instance property because you set it on the current instance which is referenced by this. Instance properties !== prototype properties, instance properties shadow prototype properties of the same names. Don't believe me?, run this Object.getOwnPropertyNames(Parent.prototype) you won't see fun
@Dummy how about now?? seting fun2 in Parent prototye.
You got it. Hope you discover something new. Also, with typescript just create a function inside the class like how define the constructor, that way the function is added on the prototype, instead of doing MyClass.prototype.function
0

You can create a singleton, and every time you import that singleton, it will import the same gl.

// gl.js    
const gl = canvas.getContext('webgl');

export default gl;

// class1.js
import gl from './gl.js';
class App {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

// class2.js
import gl from './gl.js'; // exactly the same gl
class B {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

You can read more about singletones in this book.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.