forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			739 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			739 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.js.graphics4; | ||
|  | 
 | ||
|  | import js.html.webgl.GL2; | ||
|  | import kha.graphics4.StencilValue; | ||
|  | import kha.arrays.Float32Array; | ||
|  | import kha.arrays.Int32Array; | ||
|  | import js.html.webgl.GL; | ||
|  | import kha.graphics4.BlendingFactor; | ||
|  | import kha.graphics4.BlendingOperation; | ||
|  | import kha.graphics4.CompareMode; | ||
|  | import kha.graphics4.CubeMap; | ||
|  | import kha.graphics4.CullMode; | ||
|  | import kha.graphics4.IndexBuffer; | ||
|  | import kha.graphics4.MipMapFilter; | ||
|  | import kha.graphics4.PipelineState; | ||
|  | import kha.graphics4.StencilAction; | ||
|  | import kha.graphics4.TextureAddressing; | ||
|  | import kha.graphics4.TextureFilter; | ||
|  | import kha.graphics4.Usage; | ||
|  | import kha.graphics4.VertexBuffer; | ||
|  | import kha.graphics4.VertexStructure; | ||
|  | import kha.Image; | ||
|  | import kha.math.FastMatrix3; | ||
|  | import kha.math.FastMatrix4; | ||
|  | import kha.math.FastVector2; | ||
|  | import kha.math.FastVector3; | ||
|  | import kha.math.FastVector4; | ||
|  | import kha.WebGLImage; | ||
|  | 
 | ||
|  | class Graphics implements kha.graphics4.Graphics { | ||
|  | 	var currentPipeline: PipelineState = null; | ||
|  | 	var depthTest: Bool = false; | ||
|  | 	var depthMask: Bool = false; | ||
|  | 	var colorMaskRed: Bool = true; | ||
|  | 	var colorMaskGreen: Bool = true; | ||
|  | 	var colorMaskBlue: Bool = true; | ||
|  | 	var colorMaskAlpha: Bool = true; | ||
|  | 	var indicesCount: Int; | ||
|  | 	var renderTarget: Canvas; | ||
|  | 	var renderTargetFrameBuffer: Dynamic; | ||
|  | 	var renderTargetMSAA: Dynamic; | ||
|  | 	var renderTargetTexture: Dynamic; | ||
|  | 	var isCubeMap: Bool = false; | ||
|  | 	var isDepthAttachment: Bool = false; | ||
|  | 	var instancedExtension: Dynamic; | ||
|  | 	var blendMinMaxExtension: Dynamic; | ||
|  | 
 | ||
|  | 	static var current: Graphics = null; | ||
|  | 	static var useVertexAttributes: Int = 0; | ||
|  | 
 | ||
|  | 	public function new(renderTarget: Canvas = null) { | ||
|  | 		this.renderTarget = renderTarget; | ||
|  | 		init(); | ||
|  | 		if (SystemImpl.gl2) { | ||
|  | 			instancedExtension = true; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			instancedExtension = SystemImpl.gl.getExtension("ANGLE_instanced_arrays"); | ||
|  | 			blendMinMaxExtension = SystemImpl.gl.getExtension("EXT_blend_minmax"); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function init() { | ||
|  | 		if (renderTarget == null) | ||
|  | 			return; | ||
|  | 		isCubeMap = Std.isOfType(renderTarget, CubeMap); | ||
|  | 		if (isCubeMap) { | ||
|  | 			var cubeMap: CubeMap = cast(renderTarget, CubeMap); | ||
|  | 			renderTargetFrameBuffer = cubeMap.frameBuffer; | ||
|  | 			renderTargetTexture = cubeMap.texture; | ||
|  | 			isDepthAttachment = cubeMap.isDepthAttachment; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			var image: WebGLImage = cast(renderTarget, WebGLImage); | ||
|  | 			renderTargetFrameBuffer = image.frameBuffer; | ||
|  | 			renderTargetMSAA = image.MSAAFrameBuffer; | ||
|  | 			renderTargetTexture = image.texture; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function begin(additionalRenderTargets: Array<Canvas> = null): Void { | ||
|  | 		if (current == null) { | ||
|  | 			current = this; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			throw "End before you begin"; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		SystemImpl.gl.enable(GL.BLEND); | ||
|  | 		SystemImpl.gl.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA); | ||
|  | 		if (renderTarget == null) { | ||
|  | 			SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null); | ||
|  | 			SystemImpl.gl.viewport(0, 0, System.windowWidth(), System.windowHeight()); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, renderTargetFrameBuffer); | ||
|  | 			// if (isCubeMap) SystemImpl.gl.framebufferTexture(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_CUBE_MAP, renderTargetTexture, 0); // Layered | ||
|  | 			SystemImpl.gl.viewport(0, 0, renderTarget.width, renderTarget.height); | ||
|  | 			if (additionalRenderTargets != null) { | ||
|  | 				SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, SystemImpl.drawBuffers.COLOR_ATTACHMENT0_WEBGL, GL.TEXTURE_2D, renderTargetTexture, 0); | ||
|  | 				for (i in 0...additionalRenderTargets.length) { | ||
|  | 					SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, SystemImpl.drawBuffers.COLOR_ATTACHMENT0_WEBGL + i + 1, GL.TEXTURE_2D, | ||
|  | 						cast(additionalRenderTargets[i], WebGLImage).texture, 0); | ||
|  | 				} | ||
|  | 				var attachments = [SystemImpl.drawBuffers.COLOR_ATTACHMENT0_WEBGL]; | ||
|  | 				for (i in 0...additionalRenderTargets.length) { | ||
|  | 					attachments.push(SystemImpl.drawBuffers.COLOR_ATTACHMENT0_WEBGL + i + 1); | ||
|  | 				} | ||
|  | 				SystemImpl.gl2 ? untyped SystemImpl.gl.drawBuffers(attachments) : SystemImpl.drawBuffers.drawBuffersWEBGL(attachments); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function beginFace(face: Int): Void { | ||
|  | 		if (current == null) { | ||
|  | 			current = this; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			throw "End before you begin"; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		SystemImpl.gl.enable(GL.BLEND); | ||
|  | 		SystemImpl.gl.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA); | ||
|  | 		SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, renderTargetFrameBuffer); | ||
|  | 		SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, isDepthAttachment ? GL.DEPTH_ATTACHMENT : GL.COLOR_ATTACHMENT0, | ||
|  | 			GL.TEXTURE_CUBE_MAP_POSITIVE_X + face, renderTargetTexture, 0); | ||
|  | 		SystemImpl.gl.viewport(0, 0, renderTarget.width, renderTarget.height); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function beginEye(eye: Int): Void { | ||
|  | 		if (current == null) { | ||
|  | 			current = this; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			throw "End before you begin"; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		SystemImpl.gl.enable(GL.BLEND); | ||
|  | 		SystemImpl.gl.blendFunc(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA); | ||
|  | 		SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null); | ||
|  | 		if (eye == 0) { | ||
|  | 			SystemImpl.gl.viewport(0, 0, Std.int(System.windowWidth() * 0.5), System.windowHeight()); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.viewport(Std.int(System.windowWidth() * 0.5), 0, Std.int(System.windowWidth() * 0.5), System.windowHeight()); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function end(): Void { | ||
|  | 		if (current == this) { | ||
|  | 			current = null; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			throw "Begin before you end"; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (renderTargetMSAA != null) { | ||
|  | 			untyped SystemImpl.gl.bindFramebuffer(SystemImpl.gl.READ_FRAMEBUFFER, renderTargetFrameBuffer); | ||
|  | 			untyped SystemImpl.gl.bindFramebuffer(SystemImpl.gl.DRAW_FRAMEBUFFER, renderTargetMSAA); | ||
|  | 			untyped SystemImpl.gl.blitFramebuffer(0, 0, renderTarget.width, renderTarget.height, 0, 0, renderTarget.width, renderTarget.height, | ||
|  | 				GL.COLOR_BUFFER_BIT, GL.NEAREST); | ||
|  | 		} | ||
|  | 		#if (debug || kha_debug_html5) | ||
|  | 		var error = SystemImpl.gl.getError(); | ||
|  | 		switch (error) { | ||
|  | 			case GL.NO_ERROR: | ||
|  | 
 | ||
|  | 			case GL.INVALID_ENUM: | ||
|  | 				trace("WebGL error: Invalid enum"); | ||
|  | 			case GL.INVALID_VALUE: | ||
|  | 				trace("WebGL error: Invalid value"); | ||
|  | 			case GL.INVALID_OPERATION: | ||
|  | 				trace("WebGL error: Invalid operation"); | ||
|  | 			case GL.INVALID_FRAMEBUFFER_OPERATION: | ||
|  | 				trace("WebGL error: Invalid framebuffer operation"); | ||
|  | 			case GL.OUT_OF_MEMORY: | ||
|  | 				trace("WebGL error: Out of memory"); | ||
|  | 			case GL.CONTEXT_LOST_WEBGL: | ||
|  | 				trace("WebGL error: Context lost"); | ||
|  | 			default: | ||
|  | 				trace("Unknown WebGL error"); | ||
|  | 		} | ||
|  | 		#end | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function flush(): Void {} | ||
|  | 
 | ||
|  | 	public function vsynced(): Bool { | ||
|  | 		return true; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function refreshRate(): Int { | ||
|  | 		return 60; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void { | ||
|  | 		var clearMask: Int = 0; | ||
|  | 		if (color != null) { | ||
|  | 			clearMask |= GL.COLOR_BUFFER_BIT; | ||
|  | 			SystemImpl.gl.colorMask(true, true, true, true); | ||
|  | 			SystemImpl.gl.clearColor(color.R, color.G, color.B, color.A); | ||
|  | 		} | ||
|  | 		if (depth != null) { | ||
|  | 			clearMask |= GL.DEPTH_BUFFER_BIT; | ||
|  | 			SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 			SystemImpl.gl.depthMask(true); | ||
|  | 			SystemImpl.gl.clearDepth(depth); | ||
|  | 		} | ||
|  | 		if (stencil != null) { | ||
|  | 			clearMask |= GL.STENCIL_BUFFER_BIT; | ||
|  | 			SystemImpl.gl.enable(GL.STENCIL_TEST); | ||
|  | 			SystemImpl.gl.stencilMask(0xff); | ||
|  | 			SystemImpl.gl.clearStencil(stencil); | ||
|  | 		} | ||
|  | 		SystemImpl.gl.clear(clearMask); | ||
|  | 		SystemImpl.gl.colorMask(colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha); | ||
|  | 		if (depthTest) { | ||
|  | 			SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.disable(GL.DEPTH_TEST); | ||
|  | 		} | ||
|  | 		SystemImpl.gl.depthMask(depthMask); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function viewport(x: Int, y: Int, width: Int, height: Int): Void { | ||
|  | 		if (renderTarget == null) { | ||
|  | 			SystemImpl.gl.viewport(x, System.windowHeight(0) - y - height, width, height); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.viewport(x, y, width, height); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function scissor(x: Int, y: Int, width: Int, height: Int): Void { | ||
|  | 		SystemImpl.gl.enable(GL.SCISSOR_TEST); | ||
|  | 		if (renderTarget == null) { | ||
|  | 			SystemImpl.gl.scissor(x, System.windowHeight(0) - y - height, width, height); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.scissor(x, y, width, height); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function disableScissor(): Void { | ||
|  | 		SystemImpl.gl.disable(GL.SCISSOR_TEST); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setDepthMode(write: Bool, mode: CompareMode): Void { | ||
|  | 		switch (mode) { | ||
|  | 			case Always: | ||
|  | 				write ? SystemImpl.gl.enable(GL.DEPTH_TEST) : SystemImpl.gl.disable(GL.DEPTH_TEST); | ||
|  | 				depthTest = write; | ||
|  | 				SystemImpl.gl.depthFunc(GL.ALWAYS); | ||
|  | 			case Never: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.NEVER); | ||
|  | 			case Equal: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.EQUAL); | ||
|  | 			case NotEqual: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.NOTEQUAL); | ||
|  | 			case Less: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.LESS); | ||
|  | 			case LessEqual: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.LEQUAL); | ||
|  | 			case Greater: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.GREATER); | ||
|  | 			case GreaterEqual: | ||
|  | 				SystemImpl.gl.enable(GL.DEPTH_TEST); | ||
|  | 				depthTest = true; | ||
|  | 				SystemImpl.gl.depthFunc(GL.GEQUAL); | ||
|  | 		} | ||
|  | 		SystemImpl.gl.depthMask(write); | ||
|  | 		depthMask = write; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function getBlendFunc(factor: BlendingFactor): Int { | ||
|  | 		switch (factor) { | ||
|  | 			case BlendZero, Undefined: | ||
|  | 				return GL.ZERO; | ||
|  | 			case BlendOne: | ||
|  | 				return GL.ONE; | ||
|  | 			case SourceAlpha: | ||
|  | 				return GL.SRC_ALPHA; | ||
|  | 			case DestinationAlpha: | ||
|  | 				return GL.DST_ALPHA; | ||
|  | 			case InverseSourceAlpha: | ||
|  | 				return GL.ONE_MINUS_SRC_ALPHA; | ||
|  | 			case InverseDestinationAlpha: | ||
|  | 				return GL.ONE_MINUS_DST_ALPHA; | ||
|  | 			case SourceColor: | ||
|  | 				return GL.SRC_COLOR; | ||
|  | 			case DestinationColor: | ||
|  | 				return GL.DST_COLOR; | ||
|  | 			case InverseSourceColor: | ||
|  | 				return GL.ONE_MINUS_SRC_COLOR; | ||
|  | 			case InverseDestinationColor: | ||
|  | 				return GL.ONE_MINUS_DST_COLOR; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function getBlendOp(op: BlendingOperation): Int { | ||
|  | 		switch (op) { | ||
|  | 			case Add: | ||
|  | 				return GL.FUNC_ADD; | ||
|  | 			case Subtract: | ||
|  | 				return GL.FUNC_SUBTRACT; | ||
|  | 			case ReverseSubtract: | ||
|  | 				return GL.FUNC_REVERSE_SUBTRACT; | ||
|  | 			case Min: | ||
|  | 				return 0x8007; | ||
|  | 			case Max: | ||
|  | 				return 0x8008; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setBlendingMode(source: BlendingFactor, destination: BlendingFactor, operation: BlendingOperation, alphaSource: BlendingFactor, | ||
|  | 			alphaDestination: BlendingFactor, alphaOperation: BlendingOperation): Void { | ||
|  | 		if (source == BlendOne && destination == BlendZero) { | ||
|  | 			SystemImpl.gl.disable(GL.BLEND); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.enable(GL.BLEND); | ||
|  | 			SystemImpl.gl.blendFuncSeparate(getBlendFunc(source), getBlendFunc(destination), getBlendFunc(alphaSource), getBlendFunc(alphaDestination)); | ||
|  | 			SystemImpl.gl.blendEquationSeparate(getBlendOp(operation), getBlendOp(alphaOperation)); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function createVertexBuffer(vertexCount: Int, structure: VertexStructure, usage: Usage, canRead: Bool = false): kha.graphics4.VertexBuffer { | ||
|  | 		return new VertexBuffer(vertexCount, structure, usage); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVertexBuffer(vertexBuffer: kha.graphics4.VertexBuffer): Void { | ||
|  | 		for (i in 0...useVertexAttributes) { | ||
|  | 			SystemImpl.gl.disableVertexAttribArray(i); | ||
|  | 		} | ||
|  | 		useVertexAttributes = vertexBuffer.set(0); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVertexBuffers(vertexBuffers: Array<kha.graphics4.VertexBuffer>): Void { | ||
|  | 		for (i in 0...useVertexAttributes) { | ||
|  | 			SystemImpl.gl.disableVertexAttribArray(i); | ||
|  | 		} | ||
|  | 		var offset: Int = 0; | ||
|  | 		for (vertexBuffer in vertexBuffers) { | ||
|  | 			offset += vertexBuffer.set(offset); | ||
|  | 		} | ||
|  | 		useVertexAttributes = offset; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function createIndexBuffer(indexCount: Int, usage: Usage, canRead: Bool = false): kha.graphics4.IndexBuffer { | ||
|  | 		return new IndexBuffer(indexCount, usage); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setIndexBuffer(indexBuffer: kha.graphics4.IndexBuffer): Void { | ||
|  | 		indicesCount = indexBuffer.count(); | ||
|  | 		indexBuffer.set(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// public function maxTextureSize(): Int { | ||
|  | 	//	return Sys.gl == null ? 8192 : Sys.gl.getParameter(Sys.gl.MAX_TEXTURE_SIZE); | ||
|  | 	// } | ||
|  | 	// public function supportsNonPow2Textures(): Bool { | ||
|  | 	//	return false; | ||
|  | 	// } | ||
|  | 
 | ||
|  | 	public function setTexture(stage: kha.graphics4.TextureUnit, texture: kha.Image): Void { | ||
|  | 		if (texture == null) { | ||
|  | 			SystemImpl.gl.activeTexture(GL.TEXTURE0 + (cast stage : TextureUnit).value); | ||
|  | 			SystemImpl.gl.bindTexture(GL.TEXTURE_2D, null); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			cast(texture, WebGLImage).set((cast stage : TextureUnit).value); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setTextureDepth(stage: kha.graphics4.TextureUnit, texture: kha.Image): Void { | ||
|  | 		cast(texture, WebGLImage).setDepth((cast stage : TextureUnit).value); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setTextureArray(unit: kha.graphics4.TextureUnit, texture: kha.Image): Void { | ||
|  | 		// not implemented yet. | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVideoTexture(unit: kha.graphics4.TextureUnit, texture: kha.Video): Void { | ||
|  | 		if (texture == null) { | ||
|  | 			SystemImpl.gl.activeTexture(GL.TEXTURE0 + (cast unit : TextureUnit).value); | ||
|  | 			SystemImpl.gl.bindTexture(GL.TEXTURE_2D, null); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			cast((cast texture : kha.js.Video).texture, WebGLImage).set((cast unit : TextureUnit).value); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setImageTexture(unit: kha.graphics4.TextureUnit, texture: kha.Image): Void {} | ||
|  | 
 | ||
|  | 	public function setTextureParameters(texunit: kha.graphics4.TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing, | ||
|  | 			minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void { | ||
|  | 		SystemImpl.gl.activeTexture(GL.TEXTURE0 + (cast texunit : TextureUnit).value); | ||
|  | 
 | ||
|  | 		switch (uAddressing) { | ||
|  | 			case Clamp: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); | ||
|  | 			case Repeat: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.REPEAT); | ||
|  | 			case Mirror: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.MIRRORED_REPEAT); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		switch (vAddressing) { | ||
|  | 			case Clamp: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); | ||
|  | 			case Repeat: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.REPEAT); | ||
|  | 			case Mirror: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.MIRRORED_REPEAT); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		switch (minificationFilter) { | ||
|  | 			case PointFilter: | ||
|  | 				switch (mipmapFilter) { | ||
|  | 					case NoMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST); | ||
|  | 					case PointMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST_MIPMAP_NEAREST); | ||
|  | 					case LinearMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST_MIPMAP_LINEAR); | ||
|  | 				} | ||
|  | 			case LinearFilter, AnisotropicFilter: | ||
|  | 				switch (mipmapFilter) { | ||
|  | 					case NoMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR); | ||
|  | 					case PointMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_NEAREST); | ||
|  | 					case LinearMipFilter: | ||
|  | 						SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR_MIPMAP_LINEAR); | ||
|  | 				} | ||
|  | 				if (minificationFilter == AnisotropicFilter) { | ||
|  | 					SystemImpl.gl.texParameteri(GL.TEXTURE_2D, SystemImpl.anisotropicFilter.TEXTURE_MAX_ANISOTROPY_EXT, 4); | ||
|  | 				} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		switch (magnificationFilter) { | ||
|  | 			case PointFilter: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST); | ||
|  | 			case LinearFilter, AnisotropicFilter: | ||
|  | 				SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setTexture3DParameters(texunit: kha.graphics4.TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing, | ||
|  | 		wAddressing: TextureAddressing, minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void {} | ||
|  | 
 | ||
|  | 	public function setTextureCompareMode(texunit: kha.graphics4.TextureUnit, enabled: Bool) { | ||
|  | 		if (enabled) { | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL2.TEXTURE_COMPARE_MODE, GL2.COMPARE_REF_TO_TEXTURE); | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL2.TEXTURE_COMPARE_FUNC, GL.LEQUAL); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL2.TEXTURE_COMPARE_MODE, GL.NONE); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setCubeMapCompareMode(texunit: kha.graphics4.TextureUnit, enabled: Bool) { | ||
|  | 		if (enabled) { | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL2.TEXTURE_COMPARE_MODE, GL2.COMPARE_REF_TO_TEXTURE); | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL2.TEXTURE_COMPARE_FUNC, GL.LEQUAL); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL2.TEXTURE_COMPARE_MODE, GL.NONE); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setCubeMap(stage: kha.graphics4.TextureUnit, cubeMap: kha.graphics4.CubeMap): Void { | ||
|  | 		if (cubeMap == null) { | ||
|  | 			SystemImpl.gl.activeTexture(GL.TEXTURE0 + (cast stage : TextureUnit).value); | ||
|  | 			SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, null); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			cubeMap.set((cast stage : TextureUnit).value); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setCubeMapDepth(stage: kha.graphics4.TextureUnit, cubeMap: kha.graphics4.CubeMap): Void { | ||
|  | 		cubeMap.setDepth((cast stage : TextureUnit).value); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function maxBoundTextures(): Int { | ||
|  | 		return SystemImpl.gl.getParameter(GL.MAX_TEXTURE_IMAGE_UNITS); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setCullMode(mode: CullMode): Void { | ||
|  | 		switch (mode) { | ||
|  | 			case None: | ||
|  | 				SystemImpl.gl.disable(GL.CULL_FACE); | ||
|  | 			case Clockwise: | ||
|  | 				SystemImpl.gl.enable(GL.CULL_FACE); | ||
|  | 				SystemImpl.gl.cullFace(GL.BACK); | ||
|  | 			case CounterClockwise: | ||
|  | 				SystemImpl.gl.enable(GL.CULL_FACE); | ||
|  | 				SystemImpl.gl.cullFace(GL.FRONT); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setPipeline(pipe: PipelineState): Void { | ||
|  | 		setCullMode(pipe.cullMode); | ||
|  | 		setDepthMode(pipe.depthWrite, pipe.depthMode); | ||
|  | 		if (pipe.stencilFrontMode == Always && pipe.stencilBackMode == Always && pipe.stencilFrontBothPass == Keep && pipe.stencilBackBothPass == Keep | ||
|  | 			&& pipe.stencilFrontDepthFail == Keep && pipe.stencilBackDepthFail == Keep && pipe.stencilFrontFail == Keep && pipe.stencilBackFail == Keep) { | ||
|  | 			SystemImpl.gl.disable(GL.STENCIL_TEST); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			SystemImpl.gl.enable(GL.STENCIL_TEST); | ||
|  | 			setStencilParameters(true, pipe.stencilFrontMode, pipe.stencilFrontBothPass, pipe.stencilFrontDepthFail, pipe.stencilFrontFail, | ||
|  | 				pipe.stencilReferenceValue, pipe.stencilReadMask, pipe.stencilWriteMask); | ||
|  | 			setStencilParameters(false, pipe.stencilBackMode, pipe.stencilBackBothPass, pipe.stencilBackDepthFail, pipe.stencilBackFail, | ||
|  | 				pipe.stencilReferenceValue, pipe.stencilReadMask, pipe.stencilWriteMask); | ||
|  | 		} | ||
|  | 		setBlendingMode(pipe.blendSource, pipe.blendDestination, pipe.blendOperation, pipe.alphaBlendSource, pipe.alphaBlendDestination, | ||
|  | 			pipe.alphaBlendOperation); | ||
|  | 		currentPipeline = pipe; | ||
|  | 		pipe.set(); | ||
|  | 		colorMaskRed = pipe.colorWriteMaskRed; | ||
|  | 		colorMaskGreen = pipe.colorWriteMaskGreen; | ||
|  | 		colorMaskBlue = pipe.colorWriteMaskBlue; | ||
|  | 		colorMaskAlpha = pipe.colorWriteMaskAlpha; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setStencilReferenceValue(value: Int): Void { | ||
|  | 		SystemImpl.gl.stencilFuncSeparate(GL.FRONT, convertCompareMode(currentPipeline.stencilFrontMode), value, currentPipeline.stencilReadMask); | ||
|  | 		SystemImpl.gl.stencilFuncSeparate(GL.BACK, convertCompareMode(currentPipeline.stencilBackMode), value, currentPipeline.stencilReadMask); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setBool(location: kha.graphics4.ConstantLocation, value: Bool): Void { | ||
|  | 		SystemImpl.gl.uniform1i((cast location : ConstantLocation).value, value ? 1 : 0); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setInt(location: kha.graphics4.ConstantLocation, value: Int): Void { | ||
|  | 		SystemImpl.gl.uniform1i((cast location : ConstantLocation).value, value); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setInt2(location: kha.graphics4.ConstantLocation, value1: Int, value2: Int): Void { | ||
|  | 		SystemImpl.gl.uniform2i((cast location : ConstantLocation).value, value1, value2); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setInt3(location: kha.graphics4.ConstantLocation, value1: Int, value2: Int, value3: Int): Void { | ||
|  | 		SystemImpl.gl.uniform3i((cast location : ConstantLocation).value, value1, value2, value3); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setInt4(location: kha.graphics4.ConstantLocation, value1: Int, value2: Int, value3: Int, value4: Int): Void { | ||
|  | 		SystemImpl.gl.uniform4i((cast location : ConstantLocation).value, value1, value2, value3, value4); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setInts(location: kha.graphics4.ConstantLocation, values: Int32Array): Void { | ||
|  | 		var webglLocation = (cast location : ConstantLocation); | ||
|  | 		var rawValues = new js.lib.Int32Array(values.buffer, values.byteOffset, values.length); | ||
|  | 		switch (webglLocation.type) { | ||
|  | 			case GL.INT_VEC2: | ||
|  | 				SystemImpl.gl.uniform2iv(webglLocation.value, rawValues); | ||
|  | 			case GL.INT_VEC3: | ||
|  | 				SystemImpl.gl.uniform3iv(webglLocation.value, rawValues); | ||
|  | 			case GL.INT_VEC4: | ||
|  | 				SystemImpl.gl.uniform4iv(webglLocation.value, rawValues); | ||
|  | 			default: | ||
|  | 				SystemImpl.gl.uniform1iv(webglLocation.value, rawValues); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setFloat(location: kha.graphics4.ConstantLocation, value: FastFloat): Void { | ||
|  | 		SystemImpl.gl.uniform1f((cast location : ConstantLocation).value, value); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setFloat2(location: kha.graphics4.ConstantLocation, value1: FastFloat, value2: FastFloat): Void { | ||
|  | 		SystemImpl.gl.uniform2f((cast location : ConstantLocation).value, value1, value2); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setFloat3(location: kha.graphics4.ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat): Void { | ||
|  | 		SystemImpl.gl.uniform3f((cast location : ConstantLocation).value, value1, value2, value3); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setFloat4(location: kha.graphics4.ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat, value4: FastFloat): Void { | ||
|  | 		SystemImpl.gl.uniform4f((cast location : ConstantLocation).value, value1, value2, value3, value4); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setFloats(location: kha.graphics4.ConstantLocation, values: Float32Array): Void { | ||
|  | 		var webglLocation = (cast location : ConstantLocation); | ||
|  | 		var rawValues = new js.lib.Float32Array(values.buffer, values.byteOffset, values.length); | ||
|  | 		switch (webglLocation.type) { | ||
|  | 			case GL.FLOAT_VEC2: | ||
|  | 				SystemImpl.gl.uniform2fv(webglLocation.value, rawValues); | ||
|  | 			case GL.FLOAT_VEC3: | ||
|  | 				SystemImpl.gl.uniform3fv(webglLocation.value, rawValues); | ||
|  | 			case GL.FLOAT_VEC4: | ||
|  | 				SystemImpl.gl.uniform4fv(webglLocation.value, rawValues); | ||
|  | 			case GL.FLOAT_MAT4: | ||
|  | 				SystemImpl.gl.uniformMatrix4fv(webglLocation.value, false, rawValues); | ||
|  | 			default: | ||
|  | 				SystemImpl.gl.uniform1fv(webglLocation.value, rawValues); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVector2(location: kha.graphics4.ConstantLocation, value: FastVector2): Void { | ||
|  | 		SystemImpl.gl.uniform2f((cast location : ConstantLocation).value, value.x, value.y); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVector3(location: kha.graphics4.ConstantLocation, value: FastVector3): Void { | ||
|  | 		SystemImpl.gl.uniform3f((cast location : ConstantLocation).value, value.x, value.y, value.z); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setVector4(location: kha.graphics4.ConstantLocation, value: FastVector4): Void { | ||
|  | 		SystemImpl.gl.uniform4f((cast location : ConstantLocation).value, value.x, value.y, value.z, value.w); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static var matrixCache = new js.lib.Float32Array(16); | ||
|  | 	public inline function setMatrix(location: kha.graphics4.ConstantLocation, matrix: FastMatrix4): Void { | ||
|  | 		matrixCache[0] = matrix._00; | ||
|  | 		matrixCache[1] = matrix._01; | ||
|  | 		matrixCache[2] = matrix._02; | ||
|  | 		matrixCache[3] = matrix._03; | ||
|  | 		matrixCache[4] = matrix._10; | ||
|  | 		matrixCache[5] = matrix._11; | ||
|  | 		matrixCache[6] = matrix._12; | ||
|  | 		matrixCache[7] = matrix._13; | ||
|  | 		matrixCache[8] = matrix._20; | ||
|  | 		matrixCache[9] = matrix._21; | ||
|  | 		matrixCache[10] = matrix._22; | ||
|  | 		matrixCache[11] = matrix._23; | ||
|  | 		matrixCache[12] = matrix._30; | ||
|  | 		matrixCache[13] = matrix._31; | ||
|  | 		matrixCache[14] = matrix._32; | ||
|  | 		matrixCache[15] = matrix._33; | ||
|  | 		SystemImpl.gl.uniformMatrix4fv((cast location : ConstantLocation).value, false, matrixCache); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static var matrix3Cache = new js.lib.Float32Array(9); | ||
|  | 	public inline function setMatrix3(location: kha.graphics4.ConstantLocation, matrix: FastMatrix3): Void { | ||
|  | 		matrix3Cache[0] = matrix._00; | ||
|  | 		matrix3Cache[1] = matrix._01; | ||
|  | 		matrix3Cache[2] = matrix._02; | ||
|  | 		matrix3Cache[3] = matrix._10; | ||
|  | 		matrix3Cache[4] = matrix._11; | ||
|  | 		matrix3Cache[5] = matrix._12; | ||
|  | 		matrix3Cache[6] = matrix._20; | ||
|  | 		matrix3Cache[7] = matrix._21; | ||
|  | 		matrix3Cache[8] = matrix._22; | ||
|  | 		SystemImpl.gl.uniformMatrix3fv((cast location : ConstantLocation).value, false, matrix3Cache); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function drawIndexedVertices(start: Int = 0, count: Int = -1): Void { | ||
|  | 		var type = SystemImpl.elementIndexUint == null ? GL.UNSIGNED_SHORT : GL.UNSIGNED_INT; | ||
|  | 		var size = type == GL.UNSIGNED_SHORT ? 2 : 4; | ||
|  | 		SystemImpl.gl.drawElements(GL.TRIANGLES, count == -1 ? indicesCount : count, type, start * size); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function convertStencilAction(action: StencilAction) { | ||
|  | 		switch (action) { | ||
|  | 			case StencilAction.Decrement: | ||
|  | 				return GL.DECR; | ||
|  | 			case StencilAction.DecrementWrap: | ||
|  | 				return GL.DECR_WRAP; | ||
|  | 			case StencilAction.Increment: | ||
|  | 				return GL.INCR; | ||
|  | 			case StencilAction.IncrementWrap: | ||
|  | 				return GL.INCR_WRAP; | ||
|  | 			case StencilAction.Invert: | ||
|  | 				return GL.INVERT; | ||
|  | 			case StencilAction.Keep: | ||
|  | 				return GL.KEEP; | ||
|  | 			case StencilAction.Replace: | ||
|  | 				return GL.REPLACE; | ||
|  | 			case StencilAction.Zero: | ||
|  | 				return GL.ZERO; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function convertCompareMode(compareMode: CompareMode) { | ||
|  | 		switch (compareMode) { | ||
|  | 			case Always: | ||
|  | 				return GL.ALWAYS; | ||
|  | 			case Equal: | ||
|  | 				return GL.EQUAL; | ||
|  | 			case Greater: | ||
|  | 				return GL.GREATER; | ||
|  | 			case GreaterEqual: | ||
|  | 				return GL.GEQUAL; | ||
|  | 			case Less: | ||
|  | 				return GL.LESS; | ||
|  | 			case LessEqual: | ||
|  | 				return GL.LEQUAL; | ||
|  | 			case Never: | ||
|  | 				return GL.NEVER; | ||
|  | 			case NotEqual: | ||
|  | 				return GL.NOTEQUAL; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function setStencilParameters(front: Bool, compareMode: CompareMode, bothPass: StencilAction, depthFail: StencilAction, stencilFail: StencilAction, | ||
|  | 			referenceValue: StencilValue, readMask: Int = 0xff, writeMask: Int = 0xff): Void { | ||
|  | 		var stencilFunc = convertCompareMode(compareMode); | ||
|  | 		SystemImpl.gl.stencilMaskSeparate(front ? GL.FRONT : GL.BACK, writeMask); | ||
|  | 		SystemImpl.gl.stencilOpSeparate(front ? GL.FRONT : GL.BACK, convertStencilAction(stencilFail), convertStencilAction(depthFail), | ||
|  | 			convertStencilAction(bothPass)); | ||
|  | 		switch (referenceValue) { | ||
|  | 			case Static(value): | ||
|  | 				SystemImpl.gl.stencilFuncSeparate(front ? GL.FRONT : GL.BACK, stencilFunc, value, readMask); | ||
|  | 			case Dynamic: | ||
|  | 				SystemImpl.gl.stencilFuncSeparate(front ? GL.FRONT : GL.BACK, stencilFunc, 0, readMask); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function drawIndexedVerticesInstanced(instanceCount: Int, start: Int = 0, count: Int = -1) { | ||
|  | 		if (instancedRenderingAvailable()) { | ||
|  | 			var type = SystemImpl.elementIndexUint == null ? GL.UNSIGNED_SHORT : GL.UNSIGNED_INT; | ||
|  | 			var typeSize = SystemImpl.elementIndexUint == null ? 2 : 4; | ||
|  | 			if (SystemImpl.gl2) { | ||
|  | 				untyped SystemImpl.gl.drawElementsInstanced(GL.TRIANGLES, count == -1 ? indicesCount : count, type, start * typeSize, instanceCount); | ||
|  | 			} | ||
|  | 			else { | ||
|  | 				instancedExtension.drawElementsInstancedANGLE(GL.TRIANGLES, count == -1 ? indicesCount : count, type, start * typeSize, instanceCount); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function instancedRenderingAvailable(): Bool { | ||
|  | 		return instancedExtension; | ||
|  | 	} | ||
|  | } |