diff --git a/.eslintrc.json b/.eslintrc.json index 1a035f1..ba501b9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -40,10 +40,12 @@ "F4": false, "F5": false, "F6": false, + "F9": false, "A2": false, "A5": false, "Float32Array": false, "Int32Array": false, - "Uint16Array": false + "Uint16Array": false, + "Uint8Array": false } } diff --git a/elm.json b/elm.json index cb1aa32..4152db2 100644 --- a/elm.json +++ b/elm.json @@ -14,6 +14,7 @@ ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { + "elm/bytes": "1.0.8 <= v < 2.0.0", "elm/core": "1.0.0 <= v < 2.0.0", "elm/html": "1.0.0 <= v < 2.0.0" }, diff --git a/src/Elm/Kernel/Texture.js b/src/Elm/Kernel/Texture.js index b6745d6..ef79674 100644 --- a/src/Elm/Kernel/Texture.js +++ b/src/Elm/Kernel/Texture.js @@ -65,3 +65,31 @@ var _Texture_load = F6(function (magnify, mininify, horizontalWrap, verticalWrap var _Texture_size = function (texture) { return __Utils_Tuple2(texture.__width, texture.__height); }; + + +//Texture Loading from Bytes + +// eslint-disable-next-line no-unused-vars +var _Texture_loadBytes = F9(function (magnify, mininify, horizontalWrap, verticalWrap, flipY, width, height, pixelFormat, bytes) { + function createTexture(gl) { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); + gl.texImage2D(gl.TEXTURE_2D, 0, pixelFormat, width, height, 0, pixelFormat, gl.UNSIGNED_BYTE, new Uint8Array(bytes.buffer)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magnify); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, mininify); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, horizontalWrap); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, verticalWrap); + if (mininify !== 9728 && mininify !== 9729) { + gl.generateMipmap(gl.TEXTURE_2D); + } + gl.bindTexture(gl.TEXTURE_2D, null); + return texture; + } + return { + $: __0_TEXTURE, + __$createTexture: createTexture, + __width: width, + __height: height + }; +}); diff --git a/src/WebGL/Texture.elm b/src/WebGL/Texture.elm index faedb12..2723521 100644 --- a/src/WebGL/Texture.elm +++ b/src/WebGL/Texture.elm @@ -21,6 +21,10 @@ module WebGL.Texture , nonPowerOfTwoOptions , repeat , size + , Format + , loadBytesWith + , unsafeLoad + , rgb , rgba, luminanceAlpha, luminance, alpha ) {-| @@ -51,10 +55,11 @@ module WebGL.Texture # Things You Shouldn’t Do -@docs nonPowerOfTwoOptions +@docs nonPowerOfTwoOptions, loadBytesWith, unsafeLoad, Format, rgb , rgba, luminanceAlpha, luminance, alpha -} - +import Bitwise +import Bytes exposing (Bytes) import Elm.Kernel.Texture import Task exposing (Task) @@ -304,3 +309,110 @@ or other times you may want to use only a potion of a texture image. size : Texture -> ( Int, Int ) size = Elm.Kernel.Texture.size + + + +{-| Building [`Texture`](#Texture) from bytes + + - [`Options`](#Options) - same as for [`loadWith`](#loadWith) + + - `(width, height)` - dimensions of new created texture + + - [`Format`](#Format) - pixel format in bytes + + - Bytes - encoded pixels, where `Bytes.width` > `width` \* `height` \* `Bytes per pixe`or you get `SizeError` + +Do not generate texture in `view`, [read more about this here](https://package.elm-lang.org/packages/elm-explorations/webgl/latest#making-the-most-of-the-gpu). + +-} +loadBytesWith : + Options + -> ( Int, Int ) + -> Format + -> Bytes + -> Result Error Texture +loadBytesWith ({ magnify, minify, horizontalWrap, verticalWrap, flipY } as opt) ( w, h ) ((Format _ bytesPerPixel) as format) b = + let + isMipmap = + minify /= nearest && minify /= linear + + widthPowerOfTwo = + Bitwise.and (w - 1) w == 0 + + heightPowerOfTwo = + Bitwise.and (h - 1) h == 0 + + isSizeValid = + (widthPowerOfTwo && heightPowerOfTwo) || (not isMipmap && horizontalWrap == clampToEdge && verticalWrap == clampToEdge) + in + if w > 0 && h > 0 && isSizeValid && Bytes.width b >= w * h * bytesPerPixel then + Ok (unsafeLoad opt ( w, h ) format b) + + else + Err (SizeError w h) + + +{-| It is intended specifically for library writers who want to create custom texture loaders. +-} +unsafeLoad : + Options + -> ( Int, Int ) + -> Format + -> Bytes + -> Texture +unsafeLoad { magnify, minify, horizontalWrap, verticalWrap, flipY } ( w, h ) (Format format _) b = + let + expand (Resize mag) (Resize min) (Wrap hor) (Wrap vert) = + Elm.Kernel.Texture.loadBytes mag min hor vert flipY w h format b + in + expand magnify minify horizontalWrap verticalWrap + +{-| How to read bytes intpo pixel + + | Format | Channels | Bytes per pixel | + ------------------------------------------------ + | rgba | 4 | 4 | + | rgb | 3 | 3 | + | luminanceAlpha | 2 | 2 | + | luminance | 1 | 1 | + | alpha | 1 | 1 | + ------------------------------------------------ + +-} +type Format + = Format Int Int + + +{-| Single pixel is 4 bytes long and have 4 channels +-} +rgba : Format +rgba = + Format 6408 4 + + +{-| Single pixel is 3 bytes long and have 3 channels +-} +rgb : Format +rgb = + Format 6407 3 + + +{-| Single pixel is 2 bytes long and have 2 channels +-} +luminanceAlpha : Format +luminanceAlpha = + Format 6410 2 + + +{-| Single pixel is 1 bytes long and have 1 channels +-} +luminance : Format +luminance = + Format 6409 1 + + +{-| Single pixel is 1 bytes long and have 1 channels +-} +alpha : Format +alpha = + Format 6406 1