235 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| package kha;
 | |
| 
 | |
| import haxe.io.Bytes;
 | |
| import js.Browser;
 | |
| import js.lib.Uint8Array;
 | |
| import js.html.VideoElement;
 | |
| import js.html.webgl.GL;
 | |
| import kha.graphics4.TextureFormat;
 | |
| import kha.js.CanvasGraphics;
 | |
| 
 | |
| class CanvasImage extends Image {
 | |
| 	public var image: Dynamic;
 | |
| 	public var video: VideoElement;
 | |
| 
 | |
| 	static var context: Dynamic;
 | |
| 
 | |
| 	var data: Dynamic;
 | |
| 
 | |
| 	var myWidth: Int;
 | |
| 	var myHeight: Int;
 | |
| 	var myFormat: TextureFormat;
 | |
| 	var renderTarget: Bool;
 | |
| 
 | |
| 	public var frameBuffer: Dynamic;
 | |
| 
 | |
| 	var graphics1: kha.graphics1.Graphics;
 | |
| 	var g2canvas: CanvasGraphics = null;
 | |
| 
 | |
| 	public static function init() {
 | |
| 		var canvas: Dynamic = Browser.document.createElement("canvas");
 | |
| 		if (canvas != null) {
 | |
| 			context = canvas.getContext("2d");
 | |
| 			canvas.width = 2048;
 | |
| 			canvas.height = 2048;
 | |
| 			context.globalCompositeOperation = "copy";
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function new(width: Int, height: Int, format: TextureFormat, renderTarget: Bool) {
 | |
| 		myWidth = width;
 | |
| 		myHeight = height;
 | |
| 		myFormat = format;
 | |
| 		this.renderTarget = renderTarget;
 | |
| 		image = null;
 | |
| 		video = null;
 | |
| 		if (renderTarget)
 | |
| 			createTexture();
 | |
| 	}
 | |
| 
 | |
| 	override function get_g1(): kha.graphics1.Graphics {
 | |
| 		if (graphics1 == null) {
 | |
| 			graphics1 = new kha.graphics2.Graphics1(this);
 | |
| 		}
 | |
| 		return graphics1;
 | |
| 	}
 | |
| 
 | |
| 	override function get_g2(): kha.graphics2.Graphics {
 | |
| 		if (g2canvas == null) {
 | |
| 			var canvas: Dynamic = Browser.document.createElement("canvas");
 | |
| 			image = canvas;
 | |
| 			var context = canvas.getContext("2d");
 | |
| 			canvas.width = width;
 | |
| 			canvas.height = height;
 | |
| 			g2canvas = new CanvasGraphics(context);
 | |
| 		}
 | |
| 		return g2canvas;
 | |
| 	}
 | |
| 
 | |
| 	override function get_g4(): kha.graphics4.Graphics {
 | |
| 		return null;
 | |
| 	}
 | |
| 
 | |
| 	override function get_width(): Int {
 | |
| 		return myWidth;
 | |
| 	}
 | |
| 
 | |
| 	override function get_height(): Int {
 | |
| 		return myHeight;
 | |
| 	}
 | |
| 
 | |
| 	override function get_format(): TextureFormat {
 | |
| 		return myFormat;
 | |
| 	}
 | |
| 
 | |
| 	override function get_realWidth(): Int {
 | |
| 		return myWidth;
 | |
| 	}
 | |
| 
 | |
| 	override function get_realHeight(): Int {
 | |
| 		return myHeight;
 | |
| 	}
 | |
| 
 | |
| 	override function get_stride(): Int {
 | |
| 		return myFormat == TextureFormat.RGBA32 ? 4 * width : width;
 | |
| 	}
 | |
| 
 | |
| 	override public function isOpaque(x: Int, y: Int): Bool {
 | |
| 		if (data == null) {
 | |
| 			if (context == null)
 | |
| 				return true;
 | |
| 			else
 | |
| 				createImageData();
 | |
| 		}
 | |
| 		return (data.data[y * Std.int(image.width) * 4 + x * 4 + 3] != 0);
 | |
| 	}
 | |
| 
 | |
| 	override public function at(x: Int, y: Int): Color {
 | |
| 		if (data == null) {
 | |
| 			if (context == null)
 | |
| 				return Color.Black;
 | |
| 			else
 | |
| 				createImageData();
 | |
| 		}
 | |
| 
 | |
| 		var r = data.data[y * Std.int(image.width) * 4 + x * 4];
 | |
| 		var g = data.data[y * Std.int(image.width) * 4 + x * 4 + 1];
 | |
| 		var b = data.data[y * Std.int(image.width) * 4 + x * 4 + 2];
 | |
| 		var a = data.data[y * Std.int(image.width) * 4 + x * 4 + 3];
 | |
| 
 | |
| 		return Color.fromValue((a << 24) | (r << 16) | (g << 8) | b);
 | |
| 	}
 | |
| 
 | |
| 	function createImageData() {
 | |
| 		context.strokeStyle = "rgba(0,0,0,0)";
 | |
| 		context.fillStyle = "rgba(0,0,0,0)";
 | |
| 		context.fillRect(0, 0, image.width, image.height);
 | |
| 		context.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height);
 | |
| 		data = context.getImageData(0, 0, image.width, image.height);
 | |
| 	}
 | |
| 
 | |
| 	var texture: Dynamic;
 | |
| 
 | |
| 	static function upperPowerOfTwo(v: Int): Int {
 | |
| 		v--;
 | |
| 		v |= v >>> 1;
 | |
| 		v |= v >>> 2;
 | |
| 		v |= v >>> 4;
 | |
| 		v |= v >>> 8;
 | |
| 		v |= v >>> 16;
 | |
| 		v++;
 | |
| 		return v;
 | |
| 	}
 | |
| 
 | |
| 	public function createTexture() {
 | |
| 		if (SystemImpl.gl == null)
 | |
| 			return;
 | |
| 		texture = SystemImpl.gl.createTexture();
 | |
| 		// texture.image = image;
 | |
| 		SystemImpl.gl.bindTexture(GL.TEXTURE_2D, texture);
 | |
| 		// Sys.gl.pixelStorei(Sys.gl.UNPACK_FLIP_Y_WEBGL, true);
 | |
| 
 | |
| 		SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
 | |
| 		SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR);
 | |
| 		SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
 | |
| 		SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
 | |
| 		if (renderTarget) {
 | |
| 			frameBuffer = SystemImpl.gl.createFramebuffer();
 | |
| 			SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, frameBuffer);
 | |
| 			SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, realWidth, realHeight, 0, GL.RGBA, GL.UNSIGNED_BYTE, null);
 | |
| 			SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, texture, 0);
 | |
| 			SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null);
 | |
| 		}
 | |
| 		else if (video != null)
 | |
| 			SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, video);
 | |
| 		else
 | |
| 			SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, image);
 | |
| 		// Sys.gl.generateMipmap(Sys.gl.TEXTURE_2D);
 | |
| 		SystemImpl.gl.bindTexture(GL.TEXTURE_2D, null);
 | |
| 	}
 | |
| 
 | |
| 	public function set(stage: Int): Void {
 | |
| 		SystemImpl.gl.activeTexture(GL.TEXTURE0 + stage);
 | |
| 		SystemImpl.gl.bindTexture(GL.TEXTURE_2D, texture);
 | |
| 		if (video != null)
 | |
| 			SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, video);
 | |
| 	}
 | |
| 
 | |
| 	public var bytes: Bytes;
 | |
| 
 | |
| 	override public function lock(level: Int = 0): Bytes {
 | |
| 		bytes = Bytes.alloc(myFormat == TextureFormat.RGBA32 ? 4 * width * height : width * height);
 | |
| 		return bytes;
 | |
| 	}
 | |
| 
 | |
| 	override public function unlock(): Void {
 | |
| 		data = null;
 | |
| 
 | |
| 		if (SystemImpl.gl != null) {
 | |
| 			texture = SystemImpl.gl.createTexture();
 | |
| 			// texture.image = image;
 | |
| 			SystemImpl.gl.bindTexture(GL.TEXTURE_2D, texture);
 | |
| 			// Sys.gl.pixelStorei(Sys.gl.UNPACK_FLIP_Y_WEBGL, true);
 | |
| 
 | |
| 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
 | |
| 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR);
 | |
| 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
 | |
| 			SystemImpl.gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
 | |
| 			SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.LUMINANCE, width, height, 0, GL.LUMINANCE, GL.UNSIGNED_BYTE, new Uint8Array(bytes.getData()));
 | |
| 
 | |
| 			if (SystemImpl.ie && SystemImpl.gl.getError() == 1282) { // no LUMINANCE support in IE11
 | |
| 				var rgbaBytes = Bytes.alloc(width * height * 4);
 | |
| 				for (y in 0...height)
 | |
| 					for (x in 0...width) {
 | |
| 						var value = bytes.get(y * width + x);
 | |
| 						rgbaBytes.set(y * width * 4 + x * 4 + 0, value);
 | |
| 						rgbaBytes.set(y * width * 4 + x * 4 + 1, value);
 | |
| 						rgbaBytes.set(y * width * 4 + x * 4 + 2, value);
 | |
| 						rgbaBytes.set(y * width * 4 + x * 4 + 3, 255);
 | |
| 					}
 | |
| 				SystemImpl.gl.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, width, height, 0, GL.RGBA, GL.UNSIGNED_BYTE, new Uint8Array(rgbaBytes.getData()));
 | |
| 			}
 | |
| 
 | |
| 			// Sys.gl.generateMipmap(Sys.gl.TEXTURE_2D);
 | |
| 			SystemImpl.gl.bindTexture(GL.TEXTURE_2D, null);
 | |
| 			bytes = null;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	override public function getPixels(): Bytes {
 | |
| 		@:privateAccess var context: js.html.CanvasRenderingContext2D = g2canvas.canvas;
 | |
| 		var imageData: js.html.ImageData = context.getImageData(0, 0, width, height);
 | |
| 		var bytes = Bytes.alloc(imageData.data.length);
 | |
| 		for (i in 0...imageData.data.length) {
 | |
| 			bytes.set(i, imageData.data[i]);
 | |
| 		}
 | |
| 		return bytes;
 | |
| 	}
 | |
| 
 | |
| 	override public function unload(): Void {
 | |
| 		image = null;
 | |
| 		video = null;
 | |
| 		data = null;
 | |
| 	}
 | |
| }
 |