// Class: openfl._internal.stage3D.opengl.GLProgram3D

var $global = typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this

$global.Object.defineProperty(exports, "__esModule", {value: true});

var __map_reserved = {};

// Imports

var $hxClasses = require("./../../../../hxClasses_stub").default;
var $import = require("./../../../../import_stub").default;
function lime_utils__$DataPointer_DataPointer_$Impl_$() {return require("./../../../../lime/utils/_DataPointer/DataPointer_Impl_");}
function openfl__$internal_stage3D_GLUtils() {return require("./../../../../openfl/_internal/stage3D/GLUtils");}
function openfl__$internal_stage3D_AGALConverter() {return require("./../../../../openfl/_internal/stage3D/AGALConverter");}
function js__$Boot_HaxeError() {return require("./../../../../js/_Boot/HaxeError");}
function openfl_errors_IllegalOperationError() {return require("./../../../../openfl/errors/IllegalOperationError");}
function List() {return require("./../../../../List");}
function openfl_display3D_Uniform() {return require("./../../../../openfl/display3D/Uniform");}
function StringTools() {return require("./../../../../StringTools");}
function Std() {return require("./../../../../Std");}
function lime_utils_Log() {return require("./../../../../lime/utils/Log");}
function haxe_Log() {return require("./../../../../haxe/Log");}
function Lambda() {return require("./../../../../Lambda");}
function openfl_display3D_UniformMap() {return require("./../../../../openfl/display3D/UniformMap");}
function openfl_errors_Error() {return require("./../../../../openfl/errors/Error");}

// Constructor

var GLProgram3D = function(){}

// Meta

GLProgram3D.__name__ = ["openfl","_internal","stage3D","opengl","GLProgram3D"];
GLProgram3D.prototype = {
	
};
GLProgram3D.prototype.__class__ = $hxClasses["openfl._internal.stage3D.opengl.GLProgram3D"] = GLProgram3D;

// Init



// Statics

GLProgram3D.dispose = function(program,renderSession) {
	GLProgram3D.program = program;
	GLProgram3D.renderSession = renderSession;
	GLProgram3D.__deleteShaders();
}
GLProgram3D.flushUniform = function(uniform,gl) {
	var index = uniform.regIndex * 4;
	var _g = uniform.type;
	switch(_g) {
	case 35664:
		gl.uniform2fv(uniform.location,uniform.regCount,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.regCount * 2)));
		break;
	case 35665:
		gl.uniform3fv(uniform.location,uniform.regCount,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.regCount * 3)));
		break;
	case 35666:
		gl.uniform4fv(uniform.location,uniform.regCount,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.regCount * 4)));
		break;
	case 35674:
		gl.uniformMatrix2fv(uniform.location,uniform.size,false,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.size * 2 * 2)));
		break;
	case 35675:
		gl.uniformMatrix3fv(uniform.location,uniform.size,false,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.size * 3 * 3)));
		break;
	case 35676:
		gl.uniformMatrix4fv(uniform.location,uniform.size,false,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.size * 4 * 4)));
		break;
	default:
		gl.uniform4fv(uniform.location,uniform.regCount,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(GLProgram3D.__getUniformRegisters(uniform,index,uniform.regCount * 4)));
	}
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
}
GLProgram3D.setPositionScale = function(program,renderSession,positionScale) {
	var gl = renderSession.gl;
	gl.uniform4fv(program.__positionScale.location,1,(lime_utils__$DataPointer_DataPointer_$Impl_$().default).fromArrayBufferView(positionScale));
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
}
GLProgram3D.upload = function(program,renderSession,vertexProgram,fragmentProgram) {
	GLProgram3D.program = program;
	GLProgram3D.renderSession = renderSession;
	var samplerStates = [];
	var glslVertex = (openfl__$internal_stage3D_AGALConverter().default).convertToGLSL(vertexProgram,null);
	var glslFragment = (openfl__$internal_stage3D_AGALConverter().default).convertToGLSL(fragmentProgram,samplerStates);
	GLProgram3D.__uploadFromGLSL(glslVertex,glslFragment);
	var _g1 = 0;
	var _g = samplerStates.length;
	while(_g1 < _g) {
		var i = _g1++;
		program.__samplerStates.set(i,samplerStates[i]);
	}
}
GLProgram3D.use = function(program,renderSession) {
	var gl = renderSession.gl;
	gl.useProgram(program.__programID);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	program.__vertexUniformMap.markAllDirty();
	program.__fragmentUniformMap.markAllDirty();
	var sampler = program.__samplerUniforms.iterator();
	while(sampler.hasNext()) {
		var sampler1 = sampler.next();
		if(sampler1.regCount == 1) {
			gl.uniform1i(sampler1.location,sampler1.regIndex);
			(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		} else {
			throw new (js__$Boot_HaxeError().default)(new (openfl_errors_IllegalOperationError().default)("!!! TODO: uniform location on webgl"));
		}
	}
	var sampler2 = program.__alphaSamplerUniforms.iterator();
	while(sampler2.hasNext()) {
		var sampler3 = sampler2.next();
		if(sampler3.regCount == 1) {
			gl.uniform1i(sampler3.location,sampler3.regIndex);
			(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		} else {
			throw new (js__$Boot_HaxeError().default)(new (openfl_errors_IllegalOperationError().default)("!!! TODO: uniform location on webgl"));
		}
	}
}
GLProgram3D.__buildUniformList = function() {
	var gl = GLProgram3D.renderSession.gl;
	GLProgram3D.program.__uniforms.clear();
	GLProgram3D.program.__samplerUniforms.clear();
	GLProgram3D.program.__alphaSamplerUniforms.clear();
	GLProgram3D.program.__alphaSamplerEnabled = [];
	GLProgram3D.program.__samplerUsageMask = 0;
	var numActive = 0;
	numActive = gl.getProgramParameter(GLProgram3D.program.__programID,gl.ACTIVE_UNIFORMS);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	var vertexUniforms = new (List().default)();
	var fragmentUniforms = new (List().default)();
	var _g1 = 0;
	var _g = numActive;
	while(_g1 < _g) {
		var i = _g1++;
		var info = gl.getActiveUniform(GLProgram3D.program.__programID,i);
		var name = info.name;
		var size = info.size;
		var uniformType = info.type;
		(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		var uniform = new (openfl_display3D_Uniform().default)(gl);
		uniform.name = name;
		uniform.size = size;
		uniform.type = uniformType;
		uniform.location = gl.getUniformLocation(GLProgram3D.program.__programID,uniform.name);
		(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		var indexBracket = uniform.name.indexOf("[");
		if(indexBracket >= 0) {
			uniform.name = uniform.name.substring(0,indexBracket);
		}
		var _g2 = uniform.type;
		switch(_g2) {
		case 35674:
			uniform.regCount = 2;
			break;
		case 35675:
			uniform.regCount = 3;
			break;
		case 35676:
			uniform.regCount = 4;
			break;
		default:
			uniform.regCount = 1;
		}
		uniform.regCount *= uniform.size;
		GLProgram3D.program.__uniforms.add(uniform);
		if(uniform.name == "vcPositionScale") {
			GLProgram3D.program.__positionScale = uniform;
		} else if((StringTools().default).startsWith(uniform.name,"vc")) {
			uniform.regIndex = (Std().default).parseInt(uniform.name.substring(2));
			uniform.regData = GLProgram3D.program.__context.__vertexConstants;
			vertexUniforms.add(uniform);
		} else if((StringTools().default).startsWith(uniform.name,"fc")) {
			uniform.regIndex = (Std().default).parseInt(uniform.name.substring(2));
			uniform.regData = GLProgram3D.program.__context.__fragmentConstants;
			fragmentUniforms.add(uniform);
		} else if((StringTools().default).startsWith(uniform.name,"sampler") && uniform.name.indexOf("alpha") == -1) {
			uniform.regIndex = (Std().default).parseInt(uniform.name.substring(7));
			GLProgram3D.program.__samplerUniforms.add(uniform);
			var _g4 = 0;
			var _g3 = uniform.regCount;
			while(_g4 < _g3) {
				var reg = _g4++;
				GLProgram3D.program.__samplerUsageMask |= 1 << uniform.regIndex + reg;
			}
		} else if((StringTools().default).startsWith(uniform.name,"sampler") && (StringTools().default).endsWith(uniform.name,"_alpha")) {
			var len = uniform.name.indexOf("_") - 7;
			uniform.regIndex = (Std().default).parseInt(uniform.name.substring(7,7 + len)) + 4;
			GLProgram3D.program.__alphaSamplerUniforms.add(uniform);
		} else if((StringTools().default).startsWith(uniform.name,"sampler") && (StringTools().default).endsWith(uniform.name,"_alphaEnabled")) {
			uniform.regIndex = (Std().default).parseInt(uniform.name.substring(7));
			GLProgram3D.program.__alphaSamplerEnabled[uniform.regIndex] = uniform;
		}
		if((lime_utils_Log().default).level == 5) {
			(haxe_Log().default).trace("" + i + " name:" + uniform.name + " type:" + uniform.type + " size:" + uniform.size + " location:" + (Std().default).string(uniform.location),{ fileName : "GLProgram3D.hx", lineNumber : 253, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__buildUniformList"});
		}
	}
	var tmp = (Lambda().default).array(vertexUniforms);
	GLProgram3D.program.__vertexUniformMap = new (openfl_display3D_UniformMap().default)(tmp);
	var tmp1 = (Lambda().default).array(fragmentUniforms);
	GLProgram3D.program.__fragmentUniformMap = new (openfl_display3D_UniformMap().default)(tmp1);
}
GLProgram3D.__deleteShaders = function() {
	var gl = GLProgram3D.renderSession.gl;
	if(GLProgram3D.program.__programID != null) {
		GLProgram3D.program.__programID = null;
	}
	if(GLProgram3D.program.__vertexShaderID != null) {
		gl.deleteShader(GLProgram3D.program.__vertexShaderID);
		(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		GLProgram3D.program.__vertexShaderID = null;
	}
	if(GLProgram3D.program.__fragmentShaderID != null) {
		gl.deleteShader(GLProgram3D.program.__fragmentShaderID);
		(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
		GLProgram3D.program.__fragmentShaderID = null;
	}
}
GLProgram3D.__getUniformRegisters = function(uniform,index,size) {
	return uniform.regData.subarray(index,index + size);
}
GLProgram3D.__uploadFromGLSL = function(vertexShaderSource,fragmentShaderSource) {
	var gl = GLProgram3D.renderSession.gl;
	GLProgram3D.__deleteShaders();
	if((lime_utils_Log().default).level == 5) {
		(lime_utils_Log().default).info(vertexShaderSource,{ fileName : "GLProgram3D.hx", lineNumber : 328, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__uploadFromGLSL"});
		(lime_utils_Log().default).info(fragmentShaderSource,{ fileName : "GLProgram3D.hx", lineNumber : 329, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__uploadFromGLSL"});
	}
	GLProgram3D.program.__vertexSource = vertexShaderSource;
	GLProgram3D.program.__fragmentSource = fragmentShaderSource;
	GLProgram3D.program.__vertexShaderID = gl.createShader(gl.VERTEX_SHADER);
	gl.shaderSource(GLProgram3D.program.__vertexShaderID,vertexShaderSource);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	gl.compileShader(GLProgram3D.program.__vertexShaderID);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	var shaderCompiled = gl.getShaderParameter(GLProgram3D.program.__vertexShaderID,gl.COMPILE_STATUS);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	if(shaderCompiled == 0) {
		var vertexInfoLog = gl.getShaderInfoLog(GLProgram3D.program.__vertexShaderID);
		if(vertexInfoLog != null && vertexInfoLog.length != 0) {
			(haxe_Log().default).trace("vertex: " + vertexInfoLog,{ fileName : "GLProgram3D.hx", lineNumber : 353, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__uploadFromGLSL"});
		}
		throw new (js__$Boot_HaxeError().default)(new (openfl_errors_Error().default)("Error compiling vertex shader: " + vertexInfoLog));
	}
	GLProgram3D.program.__fragmentShaderID = gl.createShader(gl.FRAGMENT_SHADER);
	gl.shaderSource(GLProgram3D.program.__fragmentShaderID,fragmentShaderSource);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	gl.compileShader(GLProgram3D.program.__fragmentShaderID);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	var fragmentCompiled = gl.getShaderParameter(GLProgram3D.program.__fragmentShaderID,gl.COMPILE_STATUS);
	if(fragmentCompiled == 0) {
		var fragmentInfoLog = gl.getShaderInfoLog(GLProgram3D.program.__fragmentShaderID);
		if(fragmentInfoLog != null && fragmentInfoLog.length != 0) {
			(haxe_Log().default).trace("fragment: " + fragmentInfoLog,{ fileName : "GLProgram3D.hx", lineNumber : 376, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__uploadFromGLSL"});
		}
		throw new (js__$Boot_HaxeError().default)(new (openfl_errors_Error().default)("Error compiling fragment shader: " + fragmentInfoLog));
	}
	GLProgram3D.program.__programID = gl.createProgram();
	gl.attachShader(GLProgram3D.program.__programID,GLProgram3D.program.__vertexShaderID);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	gl.attachShader(GLProgram3D.program.__programID,GLProgram3D.program.__fragmentShaderID);
	(openfl__$internal_stage3D_GLUtils().default).CheckGLError();
	var _g = 0;
	while(_g < 16) {
		var i = _g++;
		var name = "va" + i;
		if(vertexShaderSource.indexOf(" " + name) != -1) {
			gl.bindAttribLocation(GLProgram3D.program.__programID,i,name);
		}
	}
	gl.linkProgram(GLProgram3D.program.__programID);
	var infoLog = gl.getProgramInfoLog(GLProgram3D.program.__programID);
	if(infoLog != null && infoLog.length != 0 && (StringTools().default).trim(infoLog) != "") {
		(haxe_Log().default).trace("program: " + infoLog,{ fileName : "GLProgram3D.hx", lineNumber : 409, className : "openfl._internal.stage3D.opengl.GLProgram3D", methodName : "__uploadFromGLSL"});
	}
	GLProgram3D.__buildUniformList();
}


// Export

exports.default = GLProgram3D;