|
@@ -12,6 +12,7 @@ class WebglDriver extends Driver {
|
|
|
var gl : js.html.webgl.RenderingContext;
|
|
|
|
|
|
var curAttribs : Int;
|
|
|
+ var curShader : Shader.ShaderInstance;
|
|
|
|
|
|
public function new() {
|
|
|
canvas = cast js.Browser.document.getElementById("webgl");
|
|
@@ -23,6 +24,11 @@ class WebglDriver extends Driver {
|
|
|
gl.enable(GL.DEPTH_TEST);
|
|
|
}
|
|
|
|
|
|
+ override function reset() {
|
|
|
+ curShader = null;
|
|
|
+ gl.useProgram(null);
|
|
|
+ }
|
|
|
+
|
|
|
override function selectMaterial( mbits : Int ) {
|
|
|
gl.depthFunc(GL.LESS);
|
|
|
gl.cullFace(GL.BACK);
|
|
@@ -113,74 +119,167 @@ class WebglDriver extends Driver {
|
|
|
gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice * 2, new js.html.Uint8Array(buf.buffer, bufPos, indiceCount * 2));
|
|
|
gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
|
|
|
}
|
|
|
-
|
|
|
- override function selectShader( shader : Shader ) : Bool {
|
|
|
+
|
|
|
+ function decodeType( t : String ) : Shader.ShaderType {
|
|
|
+ return switch( t ) {
|
|
|
+ case "float": Float;
|
|
|
+ case "vec2": Vec2;
|
|
|
+ case "vec3": Vec3;
|
|
|
+ case "vec4": Vec4;
|
|
|
+ case "mat4": Mat4;
|
|
|
+ default: throw "Unknown type " + t;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function decodeTypeInt( t : Int ) : Shader.ShaderType {
|
|
|
+ return switch( t ) {
|
|
|
+ case GL.SAMPLER_2D: Tex2d;
|
|
|
+ case GL.SAMPLER_CUBE: TexCube;
|
|
|
+ case GL.FLOAT: Float;
|
|
|
+ case GL.FLOAT_VEC2: Vec2;
|
|
|
+ case GL.FLOAT_VEC3: Vec3;
|
|
|
+ case GL.FLOAT_VEC4: Vec4;
|
|
|
+ case GL.FLOAT_MAT2: Mat2;
|
|
|
+ case GL.FLOAT_MAT3: Mat3;
|
|
|
+ case GL.FLOAT_MAT4: Mat4;
|
|
|
+ default:
|
|
|
+ gl.pixelStorei(t, 0); // get DEBUG value
|
|
|
+ throw "Unknown type " + t;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function typeSize( t : Shader.ShaderType ) {
|
|
|
+ return switch( t ) {
|
|
|
+ case Float: 1;
|
|
|
+ case Vec2: 2;
|
|
|
+ case Vec3: 3;
|
|
|
+ case Vec4: 4;
|
|
|
+ case Mat2: 4;
|
|
|
+ case Mat3: 9;
|
|
|
+ case Mat4: 16;
|
|
|
+ case Tex2d, TexCube: throw "Unexpected " + t;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function buildShaderInstance( shader : Shader ) {
|
|
|
+ var cl = Type.getClass(shader);
|
|
|
+ function compileShader(name, type) {
|
|
|
+ var code = Reflect.field(cl, name);
|
|
|
+ if( code == null ) throw "Missing " + Type.getClassName(cl) + "." + name + " shader source";
|
|
|
+ var s = gl.createShader(type);
|
|
|
+ gl.shaderSource(s, code);
|
|
|
+ gl.compileShader(s);
|
|
|
+ if( !gl.getShaderParameter(s, GL.COMPILE_STATUS) )
|
|
|
+ throw "An error occurred compiling the shaders: " + gl.getShaderInfoLog(s);
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+ var vs = compileShader("VERTEX", GL.VERTEX_SHADER);
|
|
|
+ var fs = compileShader("FRAGMENT", GL.FRAGMENT_SHADER);
|
|
|
|
|
|
- if( shader.program == null ) {
|
|
|
- var cl = Type.getClass(shader);
|
|
|
- function compileShader(name, type) {
|
|
|
- var code = Reflect.field(cl, name);
|
|
|
- if( code == null ) throw "Missing " + Type.getClassName(cl) + "." + name + " shader source";
|
|
|
- var s = gl.createShader(type);
|
|
|
- gl.shaderSource(s, code);
|
|
|
- gl.compileShader(s);
|
|
|
- if( !gl.getShaderParameter(s, GL.COMPILE_STATUS) )
|
|
|
- throw "An error occurred compiling the shaders: " + gl.getShaderInfoLog(s);
|
|
|
- return s;
|
|
|
- }
|
|
|
- var vs = compileShader("VERTEX", GL.VERTEX_SHADER);
|
|
|
- var fs = compileShader("FRAGMENT", GL.FRAGMENT_SHADER);
|
|
|
-
|
|
|
- var p = gl.createProgram();
|
|
|
- gl.attachShader(p, vs);
|
|
|
- gl.attachShader(p, fs);
|
|
|
- gl.linkProgram(p);
|
|
|
- if( !gl.getProgramParameter(p, GL.LINK_STATUS) )
|
|
|
- throw "Program linkage failure";
|
|
|
+ var p = gl.createProgram();
|
|
|
+ gl.attachShader(p, vs);
|
|
|
+ gl.attachShader(p, fs);
|
|
|
+ gl.linkProgram(p);
|
|
|
+ if( !gl.getProgramParameter(p, GL.LINK_STATUS) )
|
|
|
+ throw "Program linkage failure";
|
|
|
+
|
|
|
+ var inst = new Shader.ShaderInstance();
|
|
|
|
|
|
- var nattr = gl.getProgramParameter(p, GL.ACTIVE_ATTRIBUTES);
|
|
|
- var nuni = gl.getProgramParameter(p, GL.ACTIVE_UNIFORMS);
|
|
|
- shader.attribs = [];
|
|
|
- for( k in 0...nattr )
|
|
|
- shader.attribs.push(gl.getActiveAttrib(p, k));
|
|
|
- shader.uniforms = [];
|
|
|
- for( k in 0...nuni )
|
|
|
- shader.uniforms.push(gl.getActiveUniform(p, k));
|
|
|
- shader.program = p;
|
|
|
+ var nattr = gl.getProgramParameter(p, GL.ACTIVE_ATTRIBUTES);
|
|
|
+ inst.attribs = [];
|
|
|
+
|
|
|
+ var amap = new Map();
|
|
|
+ for( k in 0...nattr ) {
|
|
|
+ var inf = gl.getActiveAttrib(p, k);
|
|
|
+ amap.set(inf.name, { index : k, inf : inf });
|
|
|
}
|
|
|
|
|
|
- gl.useProgram(shader.program);
|
|
|
- for( i in curAttribs...shader.attribs.length ) {
|
|
|
- gl.enableVertexAttribArray(i);
|
|
|
- curAttribs++;
|
|
|
+ var r = ~/attribute[ \t\r\n]+([A-Za-z0-9_]+)[ \t\r\n]+([A-Za-z0-9_]+)/;
|
|
|
+ var code : String = Reflect.field(cl, "VERTEX");
|
|
|
+ var offset = 0;
|
|
|
+ while( r.match(code) ) {
|
|
|
+ var aname = r.matched(2);
|
|
|
+ var atype = decodeType(r.matched(1));
|
|
|
+ var a = amap.get(aname);
|
|
|
+ var size = typeSize(atype);
|
|
|
+ if( a != null )
|
|
|
+ inst.attribs.push( { name : aname, type : atype, etype : GL.FLOAT, size : size, index : a.index, offset : offset } );
|
|
|
+ offset += size;
|
|
|
+ code = r.matchedRight();
|
|
|
+ }
|
|
|
+ inst.stride = offset;
|
|
|
+
|
|
|
+ var nuni = gl.getProgramParameter(p, GL.ACTIVE_UNIFORMS);
|
|
|
+ inst.uniforms = [];
|
|
|
+ var texIndex = 0;
|
|
|
+ for( k in 0...nuni ) {
|
|
|
+ var inf = gl.getActiveUniform(p, k);
|
|
|
+ var t = decodeTypeInt(inf.type);
|
|
|
+ inst.uniforms.push( {
|
|
|
+ name : inf.name,
|
|
|
+ type : t,
|
|
|
+ loc : gl.getUniformLocation(p, inf.name),
|
|
|
+ index : texIndex,
|
|
|
+ });
|
|
|
+ switch( t ) {
|
|
|
+ case Tex2d, TexCube:
|
|
|
+ texIndex++;
|
|
|
+ default:
|
|
|
+ }
|
|
|
}
|
|
|
- while( curAttribs > shader.attribs.length )
|
|
|
- gl.disableVertexAttribArray(--curAttribs);
|
|
|
|
|
|
- var mpos = gl.getUniformLocation(shader.program, "mpos");
|
|
|
- var mat : Matrix = shader.mpos;
|
|
|
- gl.uniformMatrix4fv(mpos, false, new js.html.Float32Array(mat.getFloats()));
|
|
|
+ inst.program = p;
|
|
|
+ return inst;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- var mproj = gl.getUniformLocation(shader.program, "mproj");
|
|
|
- var mat : Matrix = shader.mproj;
|
|
|
- gl.uniformMatrix4fv(mproj, false, new js.html.Float32Array(mat.getFloats()));
|
|
|
+ override function selectShader( shader : Shader ) : Bool {
|
|
|
+ var change = false;
|
|
|
+ if( shader.instance == null )
|
|
|
+ shader.instance = buildShaderInstance(shader);
|
|
|
+ if( shader.instance != curShader ) {
|
|
|
+ curShader = shader.instance;
|
|
|
+ gl.useProgram(curShader.program);
|
|
|
+ for( i in curAttribs...curShader.attribs.length ) {
|
|
|
+ gl.enableVertexAttribArray(i);
|
|
|
+ curAttribs++;
|
|
|
+ }
|
|
|
+ while( curAttribs > curShader.attribs.length )
|
|
|
+ gl.disableVertexAttribArray(--curAttribs);
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- var tex : h3d.mat.Texture = shader.tex;
|
|
|
- gl.activeTexture(GL.TEXTURE0);
|
|
|
- gl.bindTexture(GL.TEXTURE_2D, tex.t);
|
|
|
- var flags = TFILTERS[Type.enumIndex(tex.mipMap)][Type.enumIndex(tex.filter)];
|
|
|
- gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, flags[0]);
|
|
|
- gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, flags[1]);
|
|
|
- gl.uniform1i(gl.getUniformLocation(shader.program, "tex"), 0);
|
|
|
+ for( u in curShader.uniforms ) {
|
|
|
+ var val : Dynamic = Reflect.field(shader, u.name);
|
|
|
+ if( val == null ) throw "Missing shader value " + u.name;
|
|
|
+ switch( u.type ) {
|
|
|
+ case Mat4:
|
|
|
+ var m : Matrix = val;
|
|
|
+ gl.uniformMatrix4fv(u.loc, false, new js.html.Float32Array(m.getFloats()));
|
|
|
+ case Tex2d:
|
|
|
+ var t : h3d.mat.Texture = val;
|
|
|
+ gl.activeTexture(GL.TEXTURE0 + u.index);
|
|
|
+ gl.bindTexture(GL.TEXTURE_2D, t.t);
|
|
|
+ var flags = TFILTERS[Type.enumIndex(t.mipMap)][Type.enumIndex(t.filter)];
|
|
|
+ gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, flags[0]);
|
|
|
+ gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, flags[1]);
|
|
|
+ gl.uniform1i(u.loc, u.index);
|
|
|
+ default:
|
|
|
+ throw "Unsupported uniform " + u.type;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return true;
|
|
|
+ return change;
|
|
|
}
|
|
|
|
|
|
override function selectBuffer( v : VertexBuffer ) {
|
|
|
var stride : Int = untyped v.stride;
|
|
|
+ if( stride < curShader.stride )
|
|
|
+ throw "Buffer stride (" + stride + ") and shader stride (" + curShader.stride + ") mismatch";
|
|
|
gl.bindBuffer(GL.ARRAY_BUFFER, v);
|
|
|
- gl.vertexAttribPointer(1, 3, GL.FLOAT, false, stride * 4, 0);
|
|
|
- gl.vertexAttribPointer(0, 2, GL.FLOAT, false, stride * 4, 3 * 4);
|
|
|
+ for( a in curShader.attribs )
|
|
|
+ gl.vertexAttribPointer(a.index, a.size, a.etype, false, stride * 4, a.offset * 4);
|
|
|
}
|
|
|
|
|
|
override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
|