From ea4f2c47a2daf74a6a9e669569617f1395281e79 Mon Sep 17 00:00:00 2001 From: Romans Potasovs Date: Wed, 15 May 2019 11:25:41 +0300 Subject: [PATCH] Add WebGL.Texture.loadBytesWith --- elm.json | 1 + src/Elm/Kernel/Texture.js | 72 ++++++++++++++++++++++++++++++++++++++- src/WebGL/Texture.elm | 52 +++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 2 deletions(-) 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..71063b2 100644 --- a/src/Elm/Kernel/Texture.js +++ b/src/Elm/Kernel/Texture.js @@ -2,7 +2,8 @@ import Elm.Kernel.Utils exposing (Tuple2) import Elm.Kernel.Scheduler exposing (binding, succeed, fail) -import WebGL.Texture as Texture exposing (LoadError, SizeError) +import WebGL.Texture as Texture exposing (LoadError, SizeError, RGBA, RGB, LUMINANCE_ALPHA, LUMINANCE, ALPHA) +import Result exposing (Err, Ok) */ @@ -65,3 +66,72 @@ 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 + + +function getFormat(gl, format) { + return (format == __Texture_RGBA && gl.RGBA) + || (format == __Texture_RGB && gl.RGB) + || (format == __Texture_LUMINANCE_ALPHA && gl.LUMINANCE_ALPHA) + || (format == __Texture_LUMINANCE && gl.LUMINANCE) + || (format == __Texture_ALPHA && gl.ALPHA) +} + +function getByteCount(format) { + return (format == __Texture_RGBA && 4) + || (format == __Texture_RGB && 3) + || (format == __Texture_LUMINANCE_ALPHA && 2) + || (format == __Texture_LUMINANCE && 1) + || (format == __Texture_ALPHA && 1) +} + +// eslint-disable-next-line no-unused-vars +var _Texture_loadBytes = F9(function (magnify, mininify, horizontalWrap, verticalWrap, flipY, width, height, format, bytes) { + var isMipmap = mininify !== 9728 && mininify !== 9729; + function createTexture(gl) { + var pixelFormat = getFormat(gl, format); + 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 (isMipmap) { + gl.generateMipmap(gl.TEXTURE_2D); + } + gl.bindTexture(gl.TEXTURE_2D, null); + return texture; + } + if (bytes.byteLength < width * height * getByteCount(format)) { + return __Result_Err(A2( + __Texture_SizeError, + width, + height + )); + } + var widthPowerOfTwo = (width & (width - 1)) === 0; + var heightPowerOfTwo = (height & (height - 1)) === 0; + var isSizeValid = (widthPowerOfTwo && heightPowerOfTwo) || ( + !isMipmap + && horizontalWrap === 33071 // clamp to edge + && verticalWrap === 33071 + ); + if (isSizeValid) { + return __Result_Ok({ + $: __0_TEXTURE, + __$createTexture: createTexture, + __width: width, + __height: height + }); + } else { + return __Result_Err(A2( + __Texture_SizeError, + width, + height + )); + } +}); diff --git a/src/WebGL/Texture.elm b/src/WebGL/Texture.elm index faedb12..3df1d46 100644 --- a/src/WebGL/Texture.elm +++ b/src/WebGL/Texture.elm @@ -21,6 +21,8 @@ module WebGL.Texture , nonPowerOfTwoOptions , repeat , size + , Format(..) + , loadBytesWith ) {-| @@ -51,10 +53,11 @@ module WebGL.Texture # Things You Shouldn’t Do -@docs nonPowerOfTwoOptions +@docs nonPowerOfTwoOptions, loadBytesWith, Format -} +import Bytes exposing (Bytes) import Elm.Kernel.Texture import Task exposing (Task) @@ -304,3 +307,50 @@ 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 } ( w, h ) 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 | + | LUMINANCE_ALPHA | 2 | 2 | + | LUMINANCE | 1 | 1 | + | ALPHA | 1 | 1 | + ------------------------------------------------ + +-} +type Format + = RGBA + | RGB + | LUMINANCE_ALPHA + | LUMINANCE + | ALPHA