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;
|
||
|
}
|
||
|
}
|