package kha.graphics1; import kha.arrays.Float32Array; import kha.arrays.Int32Array; import kha.Blob; import kha.Color; import kha.FastFloat; import kha.Image; import kha.graphics4.ConstantLocation; import kha.graphics4.IndexBuffer; import kha.graphics4.MipMapFilter; import kha.graphics4.PipelineState; import kha.graphics4.TextureFilter; import kha.graphics4.TextureAddressing; import kha.graphics4.TextureUnit; import kha.graphics4.VertexBuffer; import kha.graphics4.VertexData; import kha.math.FastMatrix3; import kha.math.FastMatrix4; import kha.math.FastVector2; import kha.math.FastVector3; import kha.math.FastVector4; import kha.Video; class Graphics4 implements kha.graphics4.Graphics { var canvas: Canvas; var g1: kha.graphics1.Graphics; var indexBuffer: IndexBuffer; var vertexBuffer: VertexBuffer; var pipeline: PipelineState; public function new(canvas: Canvas) { this.canvas = canvas; } public function begin(additionalRenderTargets: Array = null): Void { this.g1 = canvas.g1; g1.begin(); } public function beginFace(face: Int): Void {} public function beginEye(eye: Int): Void {} public function end(): Void { g1.end(); } public function vsynced(): Bool { return true; } public function refreshRate(): Int { return 60; } public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void {} public function viewport(x: Int, y: Int, width: Int, height: Int): Void {} public function scissor(x: Int, y: Int, width: Int, height: Int): Void {} public function disableScissor(): Void {} public function setVertexBuffer(vertexBuffer: VertexBuffer): Void { this.vertexBuffer = vertexBuffer; } public function setVertexBuffers(vertexBuffers: Array): Void {} public function setIndexBuffer(indexBuffer: IndexBuffer): Void { this.indexBuffer = indexBuffer; } public function setTexture(unit: TextureUnit, texture: Image): Void {} public function setTextureDepth(unit: TextureUnit, texture: Image): Void {} public function setTextureArray(unit: TextureUnit, texture: Image): Void {} public function setVideoTexture(unit: TextureUnit, texture: Video): Void {} public function setImageTexture(unit: TextureUnit, texture: Image): Void {} public function setTextureParameters(texunit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing, minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void {} public function setTexture3DParameters(texunit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing, wAddressing: TextureAddressing, minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void {} public function setTextureCompareMode(texunit: TextureUnit, enabled: Bool): Void {} public function setCubeMapCompareMode(texunit: TextureUnit, enabled: Bool): Void {} public function setCubeMap(stage: kha.graphics4.TextureUnit, cubeMap: kha.graphics4.CubeMap): Void {} public function setCubeMapDepth(stage: kha.graphics4.TextureUnit, cubeMap: kha.graphics4.CubeMap): Void {} public function renderTargetsInvertedY(): Bool { return false; } public function instancedRenderingAvailable(): Bool { return false; } public function setPipeline(pipeline: PipelineState): Void { this.pipeline = pipeline; } public function setStencilReferenceValue(value: Int): Void {} public function setBool(location: ConstantLocation, value: Bool): Void {} public function setInt(location: ConstantLocation, value: Int): Void {} public function setInt2(location: ConstantLocation, value1: Int, value2: Int): Void {} public function setInt3(location: ConstantLocation, value1: Int, value2: Int, value3: Int): Void {} public function setInt4(location: ConstantLocation, value1: Int, value2: Int, value3: Int, value4: Int): Void {} public function setInts(location: ConstantLocation, ints: Int32Array): Void {} public function setFloat(location: ConstantLocation, value: FastFloat): Void {} public function setFloat2(location: ConstantLocation, value1: FastFloat, value2: FastFloat): Void {} public function setFloat3(location: ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat): Void {} public function setFloat4(location: ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat, value4: FastFloat): Void {} public function setFloats(location: ConstantLocation, floats: Float32Array): Void {} public function setFloat4s(location: ConstantLocation, float4s: Float32Array): Void {} public function setVector2(location: ConstantLocation, value: FastVector2): Void {} public function setVector3(location: ConstantLocation, value: FastVector3): Void {} public function setVector4(location: ConstantLocation, value: FastVector4): Void {} public function setMatrix(location: ConstantLocation, value: FastMatrix4): Void {} public function setMatrix3(location: ConstantLocation, value: FastMatrix3): Void {} static inline function min(a: FastFloat, b: FastFloat, c: FastFloat): FastFloat { var min1 = a < b ? a : b; return min1 < c ? min1 : c; } static inline function max(a: FastFloat, b: FastFloat, c: FastFloat): FastFloat { var max1 = a > b ? a : b; return max1 > c ? max1 : c; } inline function xtopixel(x: FastFloat): Int { return Std.int((x + 1) / 2 * canvas.width); } inline function ytopixel(y: FastFloat): Int { return Std.int((y + 1) / 2 * canvas.height); } public function drawIndexedVertices(start: Int = 0, count: Int = -1): Void { #if js // var vertexShaderSource = "output.gl_Position = new vec4(input.pos.x,input.pos.y,0.5,1.0);"; // var vertexShader = untyped __js__("new Function([\"input\", \"output\", \"vec4\"], vertexShaderSource)"); // var vertexShader = untyped __js__("window[this.pipeline.vertexShader.name]"); var vertexShader = untyped __js__("shader_vert"); // var fragmentShaderSource = "output.gl_FragColor = new vec4(1.0, 0.0, 0.0, 1.0);"; // var fragmentShader = untyped __js__("new Function([\"input\", \"output\", \"vec4\"], fragmentShaderSource)"); // var fragmentShader = untyped __js__("window[this.pipeline.fragmentShader.name]"); var fragmentShader = untyped __js__("shader_frag"); var index = 0; while (index < indexBuffer._data.length) { var indices = [ indexBuffer._data[index + 0], indexBuffer._data[index + 1], indexBuffer._data[index + 2] ]; var layout = pipeline.inputLayout[0]; var vertexStride = Std.int(layout.byteSize() / 4); var offsets = [indices[0] * vertexStride, indices[1] * vertexStride, indices[2] * vertexStride]; var vsinputs = new Array(); for (index in 0...3) { var vsinput: Dynamic = {}; var vindex = 0; for (element in layout.elements) { switch (element.data) { case VertexData.Float1: var data1 = vertexBuffer._data.get(offsets[index] + vindex + 0); untyped vsinput[element.name] = data1; vindex += 1; case VertexData.Float2: var data2 = [ vertexBuffer._data.get(offsets[index] + vindex + 0), vertexBuffer._data.get(offsets[index] + vindex + 1) ]; untyped vsinput[element.name] = data2; vindex += 2; case VertexData.Float3: var data3 = [ vertexBuffer._data.get(offsets[index] + vindex + 0), vertexBuffer._data.get(offsets[index] + vindex + 1), vertexBuffer._data.get(offsets[index] + vindex + 2) ]; untyped vsinput[element.name] = data3; vindex += 3; case VertexData.Float4: var data4 = [ vertexBuffer._data.get(offsets[index] + vindex + 0), vertexBuffer._data.get(offsets[index] + vindex + 1), vertexBuffer._data.get(offsets[index] + vindex + 2), vertexBuffer._data.get(offsets[index] + vindex + 3) ]; untyped vsinput[element.name] = data4; vindex += 4; case VertexData.Float4x4: case Short2Norm: case Short4Norm: } } vsinputs.push(vsinput); } var vsoutputs: Array = [{}, {}, {}, {}]; for (i in 0...3) vertexShader(vsinputs[i], vsoutputs[i], vec2, vec3, vec4, mat4); var positions: Array> = [vsoutputs[0].gl_Position, vsoutputs[1].gl_Position, vsoutputs[2].gl_Position]; var minx = min(positions[0][0], positions[1][0], positions[2][0]); var maxx = max(positions[0][0], positions[1][0], positions[2][0]); var miny = min(positions[0][1], positions[1][1], positions[2][1]); var maxy = max(positions[0][1], positions[1][1], positions[2][1]); var minxp = xtopixel(minx); var maxxp = xtopixel(maxx); var minyp = ytopixel(miny); var maxyp = ytopixel(maxy); for (y in minyp...maxyp) for (x in minxp...maxxp) { var bc_screen: FastVector3 = barycentric(xtopixel(positions[0][0]), ytopixel(positions[0][1]), xtopixel(positions[1][0]), ytopixel(positions[1][1]), xtopixel(positions[2][0]), ytopixel(positions[2][1]), x, y); if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0) continue; var fsoutput: Dynamic = {}; fragmentShader({}, fsoutput, vec2, vec3, vec4, mat4); var color: Array = fsoutput.gl_FragColor; g1.setPixel(x, y, Color.fromFloats(color[2], color[1], color[0], color[3])); } index += 3; } #end } static function vec2(x: FastFloat, y: FastFloat): Array { return [x, y]; } static function vec3(x: FastFloat, y: FastFloat, z: FastFloat): Array { return [x, y, z]; } static function vec4(x: FastFloat, y: FastFloat, z: FastFloat, w: FastFloat): Array { return [x, y, z, w]; } static function mat4(x: FastFloat, y: FastFloat): Array { return [x, y]; } static inline function barycentric(_1x: Int, _1y: Int, _2x: Int, _2y: Int, _3x: Int, _3y: Int, x: Int, y: Int): FastVector3 { var a = new FastVector3(_3x - _1x, _2x - _1x, _1x - x); var b = new FastVector3(_3y - _1y, _2y - _1y, _1y - y); var u: FastVector3 = a.cross(b); if (Math.abs(u.z) < 1) return new FastVector3(-1, 1, 1); // degenerate return new FastVector3(1.0 - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z); } public function drawIndexedVerticesInstanced(instanceCount: Int, start: Int = 0, count: Int = -1): Void {} public function flush(): Void {} public function maxBoundTextures(): Int { return 16; } }