265 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			265 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package kha.js; | ||
|  | 
 | ||
|  | import kha.Color; | ||
|  | import kha.graphics2.Graphics; | ||
|  | import kha.graphics2.ImageScaleQuality; | ||
|  | import kha.math.FastMatrix3; | ||
|  | import js.html.CanvasRenderingContext2D; | ||
|  | 
 | ||
|  | class CanvasGraphics extends Graphics { | ||
|  | 	var canvas: CanvasRenderingContext2D; | ||
|  | 	var webfont: kha.js.Font; | ||
|  | 	var myColor: Color; | ||
|  | 	var scaleQuality: ImageScaleQuality; | ||
|  | 	var clipping: Bool = false; | ||
|  | 
 | ||
|  | 	static var instance: CanvasGraphics; | ||
|  | 
 | ||
|  | 	public function new(canvas: CanvasRenderingContext2D) { | ||
|  | 		super(); | ||
|  | 		this.canvas = canvas; | ||
|  | 		instance = this; | ||
|  | 		myColor = Color.fromBytes(0, 0, 0); | ||
|  | 		// webfont = new Font("Arial", new FontStyle(false, false, false), 12); | ||
|  | 		// canvas.globalCompositeOperation = "normal"; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public static function stringWidth(font: kha.Font, text: String): Float { | ||
|  | 		if (instance == null) | ||
|  | 			return 5 * text.length; | ||
|  | 		else { | ||
|  | 			instance.font = font; | ||
|  | 			return instance.canvas.measureText(text).width; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function begin(clear: Bool = true, clearColor: Color = null): Void { | ||
|  | 		if (clear) | ||
|  | 			this.clear(clearColor); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function clear(color: Color = null): Void { | ||
|  | 		if (color == null) | ||
|  | 			color = 0x00000000; | ||
|  | 		canvas.strokeStyle = "rgba(" + color.Rb + "," + color.Gb + "," + color.Bb + "," + color.A + ")"; | ||
|  | 		canvas.fillStyle = "rgba(" + color.Rb + "," + color.Gb + "," + color.Bb + "," + color.A + ")"; | ||
|  | 		if (color.A == 0) // if color is transparent, clear the screen. Note: in Canvas, transparent colors will overlay, not overwrite. | ||
|  | 			canvas.clearRect(0, 0, canvas.canvas.width, canvas.canvas.height); | ||
|  | 		else | ||
|  | 			canvas.fillRect(0, 0, canvas.canvas.width, canvas.canvas.height); | ||
|  | 		this.color = myColor; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function end(): Void {} | ||
|  | 
 | ||
|  | 	/*override public function translate(x: Float, y: Float) { | ||
|  | 		tx = x; | ||
|  | 		ty = y; | ||
|  | 	}*/ | ||
|  | 	override public function drawImage(img: kha.Image, x: Float, y: Float) { | ||
|  | 		canvas.globalAlpha = opacity; | ||
|  | 		canvas.drawImage(cast(img, CanvasImage).image, x, y); | ||
|  | 		canvas.globalAlpha = 1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function drawScaledSubImage(image: kha.Image, sx: Float, sy: Float, sw: Float, sh: Float, dx: Float, dy: Float, dw: Float, dh: Float) { | ||
|  | 		canvas.globalAlpha = opacity; | ||
|  | 		try { | ||
|  | 			if (dw < 0 || dh < 0) { | ||
|  | 				canvas.save(); | ||
|  | 				canvas.translate(dx, dy); | ||
|  | 				var x = 0.0; | ||
|  | 				var y = 0.0; | ||
|  | 				if (dw < 0) { | ||
|  | 					canvas.scale(-1, 1); | ||
|  | 					x = -dw; | ||
|  | 				} | ||
|  | 				if (dh < 0) { | ||
|  | 					canvas.scale(1, -1); | ||
|  | 					y = -dh; | ||
|  | 				} | ||
|  | 				canvas.drawImage(cast(image, CanvasImage).image, sx, sy, sw, sh, x, y, dw, dh); | ||
|  | 				canvas.restore(); | ||
|  | 			} | ||
|  | 			else { | ||
|  | 				canvas.drawImage(cast(image, CanvasImage).image, sx, sy, sw, sh, dx, dy, dw, dh); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		catch (ex:Dynamic) {} | ||
|  | 		canvas.globalAlpha = 1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function set_color(color: Color): Color { | ||
|  | 		myColor = color; | ||
|  | 		canvas.strokeStyle = "rgba(" + color.Rb + "," + color.Gb + "," + color.Bb + "," + color.A + ")"; | ||
|  | 		canvas.fillStyle = "rgba(" + color.Rb + "," + color.Gb + "," + color.Bb + "," + color.A + ")"; | ||
|  | 		return color; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function get_color(): Color { | ||
|  | 		return myColor; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function get_imageScaleQuality(): ImageScaleQuality { | ||
|  | 		return scaleQuality; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function set_imageScaleQuality(value: ImageScaleQuality): ImageScaleQuality { | ||
|  | 		if (value == ImageScaleQuality.Low) { | ||
|  | 			untyped canvas.mozImageSmoothingEnabled = false; | ||
|  | 			untyped canvas.webkitImageSmoothingEnabled = false; | ||
|  | 			untyped canvas.msImageSmoothingEnabled = false; | ||
|  | 			canvas.imageSmoothingEnabled = false; | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			untyped canvas.mozImageSmoothingEnabled = true; | ||
|  | 			untyped canvas.webkitImageSmoothingEnabled = true; | ||
|  | 			untyped canvas.msImageSmoothingEnabled = true; | ||
|  | 			canvas.imageSmoothingEnabled = true; | ||
|  | 		} | ||
|  | 		return scaleQuality = value; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function drawRect(x: Float, y: Float, width: Float, height: Float, strength: Float = 1.0) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		var oldStrength = canvas.lineWidth; | ||
|  | 		canvas.lineWidth = Math.round(strength); | ||
|  | 		canvas.rect(x, y, width, height); | ||
|  | 		canvas.stroke(); | ||
|  | 		canvas.lineWidth = oldStrength; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function fillRect(x: Float, y: Float, width: Float, height: Float) { | ||
|  | 		canvas.globalAlpha = opacity * myColor.A; | ||
|  | 		canvas.fillRect(x, y, width, height); | ||
|  | 		canvas.globalAlpha = opacity; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function drawArc(cx: Float, cy: Float, radius: Float, sAngle: Float, eAngle: Float, strength: Float = 1.0, ccw: Bool = false) { | ||
|  | 		_drawArc(cx, cy, radius, sAngle, eAngle, strength, ccw); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function drawCircle(cx: Float, cy: Float, radius: Float, strength: Float = 1.0) { | ||
|  | 		_drawArc(cx, cy, radius, 0, 2 * Math.PI, strength, false); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	inline function _drawArc(cx: Float, cy: Float, radius: Float, sAngle: Float, eAngle: Float, strength: Float, ccw: Bool) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		var oldStrength = canvas.lineWidth; | ||
|  | 		canvas.lineWidth = Math.round(strength); | ||
|  | 		canvas.arc(cx, cy, radius, sAngle, eAngle, ccw); | ||
|  | 		canvas.stroke(); | ||
|  | 		canvas.lineWidth = oldStrength; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function fillArc(cx: Float, cy: Float, radius: Float, sAngle: Float, eAngle: Float, ccw: Bool = false) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		canvas.arc(cx, cy, radius, sAngle, eAngle, ccw); | ||
|  | 		canvas.fill(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public function fillCircle(cx: Float, cy: Float, radius: Float) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		canvas.arc(cx, cy, radius, 0, 2 * Math.PI, false); | ||
|  | 		canvas.fill(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var bakedQuadCache = new kha.Kravur.AlignedQuad(); | ||
|  | 
 | ||
|  | 	override public function drawString(text: String, x: Float, y: Float) { | ||
|  | 		// canvas.fillText(text, tx + x, ty + y + webfont.getHeight()); | ||
|  | 		// canvas.drawImage(cast(webfont.getTexture(), Image).image, 0, 0, 50, 50, tx + x, ty + y, 50, 50); | ||
|  | 
 | ||
|  | 		var image = webfont.getImage(fontSize, myColor); | ||
|  | 		if (image.width > 0) { | ||
|  | 			// the image created in getImage() is not imediately useable | ||
|  | 			var xpos = x; | ||
|  | 			var ypos = y; | ||
|  | 			for (i in 0...text.length) { | ||
|  | 				var q = webfont.kravur._get(fontSize).getBakedQuad(bakedQuadCache, kha.graphics2.Graphics.fontGlyphs.indexOf(text.charCodeAt(i)), xpos, ypos); | ||
|  | 
 | ||
|  | 				if (q != null) { | ||
|  | 					if (q.s1 - q.s0 > 0 && q.t1 - q.t0 > 0 && q.x1 - q.x0 > 0 && q.y1 - q.y0 > 0) | ||
|  | 						canvas.drawImage(image, q.s0 * image.width, q.t0 * image.height, (q.s1 - q.s0) * image.width, (q.t1 - q.t0) * image.height, q.x0, | ||
|  | 							q.y0, q.x1 - q.x0, q.y1 - q.y0); | ||
|  | 					xpos += q.xadvance; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function drawCharacters(text: Array<Int>, start: Int, length: Int, x: Float, y: Float): Void { | ||
|  | 		var image = webfont.getImage(fontSize, myColor); | ||
|  | 		if (image.width > 0) { | ||
|  | 			// the image created in getImage() is not imediately useable | ||
|  | 			var xpos = x; | ||
|  | 			var ypos = y; | ||
|  | 			for (i in start...start + length) { | ||
|  | 				var q = webfont.kravur._get(fontSize).getBakedQuad(bakedQuadCache, kha.graphics2.Graphics.fontGlyphs.indexOf(text[i]), xpos, ypos); | ||
|  | 
 | ||
|  | 				if (q != null) { | ||
|  | 					if (q.s1 - q.s0 > 0 && q.t1 - q.t0 > 0 && q.x1 - q.x0 > 0 && q.y1 - q.y0 > 0) | ||
|  | 						canvas.drawImage(image, q.s0 * image.width, q.t0 * image.height, (q.s1 - q.s0) * image.width, (q.t1 - q.t0) * image.height, q.x0, | ||
|  | 							q.y0, q.x1 - q.x0, q.y1 - q.y0); | ||
|  | 					xpos += q.xadvance; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function set_font(font: kha.Font): kha.Font { | ||
|  | 		webfont = cast(font, kha.js.Font); | ||
|  | 		// canvas.font = webfont.size + "px " + webfont.name; | ||
|  | 		return cast webfont; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override function get_font(): kha.Font { | ||
|  | 		return cast webfont; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function drawLine(x1: Float, y1: Float, x2: Float, y2: Float, strength: Float = 1.0) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		var oldWith = canvas.lineWidth; | ||
|  | 		canvas.lineWidth = Math.round(strength); | ||
|  | 		canvas.moveTo(x1, y1); | ||
|  | 		canvas.lineTo(x2, y2); | ||
|  | 		canvas.moveTo(0, 0); | ||
|  | 		canvas.stroke(); | ||
|  | 		canvas.lineWidth = oldWith; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function fillTriangle(x1: Float, y1: Float, x2: Float, y2: Float, x3: Float, y3: Float) { | ||
|  | 		canvas.beginPath(); | ||
|  | 		canvas.moveTo(x1, y1); | ||
|  | 		canvas.lineTo(x2, y2); | ||
|  | 		canvas.lineTo(x3, y3); | ||
|  | 		canvas.closePath(); | ||
|  | 		canvas.fill(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function scissor(x: Int, y: Int, width: Int, height: Int): Void { | ||
|  | 		if (!clipping) { | ||
|  | 			canvas.save(); | ||
|  | 			clipping = true; | ||
|  | 		} | ||
|  | 		canvas.beginPath(); | ||
|  | 		canvas.rect(x, y, width, height); | ||
|  | 		canvas.clip(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function disableScissor(): Void { | ||
|  | 		if (clipping) { | ||
|  | 			canvas.restore(); | ||
|  | 			clipping = false; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function drawVideo(video: kha.Video, x: Float, y: Float, width: Float, height: Float): Void { | ||
|  | 		canvas.drawImage(cast(video, Video).element, x, y, width, height); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	override public function setTransformation(transformation: FastMatrix3): Void { | ||
|  | 		canvas.setTransform(transformation._00, transformation._01, transformation._10, transformation._11, transformation._20, transformation._21); | ||
|  | 	} | ||
|  | } |