package kha.graphics4; import js.html.webgl.GL; import haxe.io.Bytes; import kha.js.graphics4.Graphics; class CubeMap implements Canvas implements Resource { var myWidth: Int; var myHeight: Int; var format: TextureFormat; var renderTarget: Bool; var depthStencilFormat: DepthStencilFormat; var graphics4: kha.graphics4.Graphics; public var frameBuffer: Dynamic = null; public var texture: Dynamic = null; public var depthTexture: Dynamic = null; public var isDepthAttachment: Bool = false; // WebGL2 constants static inline var GL_RGBA16F = 0x881A; static inline var GL_RGBA32F = 0x8814; static inline var GL_R16F = 0x822D; static inline var GL_R32F = 0x822E; static inline var GL_DEPTH_COMPONENT24 = 0x81A6; static inline var GL_DEPTH24_STENCIL8 = 0x88F0; static inline var GL_DEPTH32F_STENCIL8 = 0x8CAD; function new(size: Int, format: TextureFormat, renderTarget: Bool, depthStencilFormat: DepthStencilFormat) { myWidth = size; myHeight = size; this.format = format; this.renderTarget = renderTarget; this.depthStencilFormat = depthStencilFormat; if (renderTarget) createTexture(); } public static function createRenderTarget(size: Int, format: TextureFormat = null, depthStencil: DepthStencilFormat = null): CubeMap { if (format == null) format = TextureFormat.RGBA32; if (depthStencil == null) depthStencil = NoDepthAndStencil; return new CubeMap(size, format, true, depthStencil); } function createTexture() { if (SystemImpl.gl == null) return; texture = SystemImpl.gl.createTexture(); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, texture); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MAG_FILTER, GL.LINEAR); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MIN_FILTER, GL.LINEAR); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); if (renderTarget) { frameBuffer = SystemImpl.gl.createFramebuffer(); SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, frameBuffer); switch (format) { case DEPTH16: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, SystemImpl.gl2 ? GL.DEPTH_COMPONENT16 : GL.DEPTH_COMPONENT, myWidth, myHeight, 0, GL.DEPTH_COMPONENT, GL.UNSIGNED_SHORT, null); case RGBA128: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, SystemImpl.gl2 ? GL_RGBA32F : GL.RGBA, myWidth, myHeight, 0, GL.RGBA, GL.FLOAT, null); case RGBA64: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, SystemImpl.gl2 ? GL_RGBA16F : GL.RGBA, myWidth, myHeight, 0, GL.RGBA, SystemImpl.halfFloat.HALF_FLOAT_OES, null); case RGBA32: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL.RGBA, myWidth, myHeight, 0, GL.RGBA, GL.UNSIGNED_BYTE, null); case A32: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, SystemImpl.gl2 ? GL_R32F : GL.ALPHA, myWidth, myHeight, 0, GL.ALPHA, GL.FLOAT, null); case A16: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, SystemImpl.gl2 ? GL_R16F : GL.ALPHA, myWidth, myHeight, 0, GL.ALPHA, SystemImpl.halfFloat.HALF_FLOAT_OES, null); default: for (i in 0...6) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL.RGBA, myWidth, myHeight, 0, GL.RGBA, GL.UNSIGNED_BYTE, null); } if (format == DEPTH16) { SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MAG_FILTER, GL.NEAREST); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MIN_FILTER, GL.NEAREST); isDepthAttachment = true; // Some WebGL implementations throw incomplete framebuffer error, create color attachment if (!SystemImpl.gl2) { var colortex = SystemImpl.gl.createTexture(); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, colortex); for (i in 0...6) { SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL.RGBA, myWidth, myHeight, 0, GL.RGBA, GL.UNSIGNED_BYTE, null); SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_CUBE_MAP_POSITIVE_X + i, colortex, 0); } SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, texture); } } initDepthStencilBuffer(depthStencilFormat); SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, null); } SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, null); } function initDepthStencilBuffer(depthStencilFormat: DepthStencilFormat) { switch (depthStencilFormat) { case NoDepthAndStencil: case DepthOnly, Depth16: { depthTexture = SystemImpl.gl.createTexture(); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, depthTexture); if (depthStencilFormat == DepthOnly) SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP, 0, SystemImpl.gl2 ? GL_DEPTH_COMPONENT24 : GL.DEPTH_COMPONENT, myWidth, myHeight, 0, GL.DEPTH_COMPONENT, GL.UNSIGNED_INT, null); else SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP, 0, SystemImpl.gl2 ? GL.DEPTH_COMPONENT16 : GL.DEPTH_COMPONENT, myWidth, myHeight, 0, GL.DEPTH_COMPONENT, GL.UNSIGNED_SHORT, null); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MAG_FILTER, GL.NEAREST); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MIN_FILTER, GL.NEAREST); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, frameBuffer); SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_CUBE_MAP, depthTexture, 0); } case DepthAutoStencilAuto, Depth24Stencil8, Depth32Stencil8: depthTexture = SystemImpl.gl.createTexture(); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, depthTexture); SystemImpl.gl.texImage2D(GL.TEXTURE_CUBE_MAP, 0, SystemImpl.gl2 ? GL_DEPTH24_STENCIL8 : GL.DEPTH_STENCIL, myWidth, myHeight, 0, GL.DEPTH_STENCIL, SystemImpl.depthTexture.UNSIGNED_INT_24_8_WEBGL, null); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MAG_FILTER, GL.NEAREST); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_MIN_FILTER, GL.NEAREST); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE); SystemImpl.gl.texParameteri(GL.TEXTURE_CUBE_MAP, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE); SystemImpl.gl.bindFramebuffer(GL.FRAMEBUFFER, frameBuffer); SystemImpl.gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_CUBE_MAP, depthTexture, 0); } } public function set(stage: Int): Void { SystemImpl.gl.activeTexture(GL.TEXTURE0 + stage); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, texture); } public function setDepth(stage: Int): Void { SystemImpl.gl.activeTexture(GL.TEXTURE0 + stage); SystemImpl.gl.bindTexture(GL.TEXTURE_CUBE_MAP, depthTexture); } public function unload(): Void {} public function lock(level: Int = 0): Bytes { return null; } public function unlock(): Void {} public var width(get, never): Int; function get_width(): Int { return myWidth; } public var height(get, never): Int; function get_height(): Int { return myHeight; } public var g1(get, never): kha.graphics1.Graphics; function get_g1(): kha.graphics1.Graphics { return null; } public var g2(get, never): kha.graphics2.Graphics; function get_g2(): kha.graphics2.Graphics { return null; } public var g4(get, never): kha.graphics4.Graphics; function get_g4(): kha.graphics4.Graphics { if (graphics4 == null) { graphics4 = new Graphics(this); } return graphics4; } }