{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -Wno-incomplete-patterns #-} {-# OPTIONS_GHC -Wno-unused-foralls #-} module Graphics.GPipe.Internal.Texture where import Control.Exception (throwIO) import Control.Monad (foldM, forM_, void, when) import Control.Monad.Exception (MonadAsyncException, bracket) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Trans.Class (lift) import Data.IORef (IORef, newIORef, readIORef) import Data.IntMap.Polymorphic.Lazy (insert) import Data.Text.Lazy (Text) import Foreign.Marshal.Alloc (alloca, allocaBytes, free, mallocBytes) import Foreign.Marshal.Utils (with) import Foreign.Ptr (minusPtr, nullPtr, plusPtr, wordPtrToPtr) import Foreign.Storable (Storable (peek)) import Graphics.GL.Core45 import Graphics.GL.Ext.EXT.TextureFilterAnisotropic import Graphics.GL.Types (GLenum, GLuint) import Graphics.GPipe.Internal.Buffer (Buffer (bufElementSize, bufName, bufferLength), BufferColor, BufferFormat (..), BufferStartPos, bufferWriteInternal, makeBuffer) import Graphics.GPipe.Internal.Compiler (Binding, RenderIOState (samplerNameToRenderIO)) import Graphics.GPipe.Internal.Context (ContextHandler, ContextT, FBOKey (FBOKey), GPipeException (GPipeException), Render (Render), addContextFinalizer, addFBOTextureFinalizer, liftNonWinContextAsyncIO, liftNonWinContextIO, registerRenderWriteTexture) import Graphics.GPipe.Internal.Expr (ExprM, F, FFloat, S (..), SType (..), scalarS, tshow, useSampler, vec2S, vec3S, vec4S) import Graphics.GPipe.Internal.Format (ColorRenderable, ColorSampleable (..), DepthRenderable, Format, TextureFormat (..), getGlInternalFormat) import Graphics.GPipe.Internal.IDs (SamplerId (..)) import Graphics.GPipe.Internal.Shader (Shader (..), ShaderM, getNewName, modifyRenderIO) import Linear.V2 (V2 (..)) import Linear.V3 (V3 (..)) import Linear.V4 (V4 (..)) data Texture1D os a = Texture1D TexName Size1 MaxLevels data Texture1DArray os a = Texture1DArray TexName Size2 MaxLevels data Texture2D os a = Texture2D TexName Size2 MaxLevels | RenderBuffer2D TexName Size2 data Texture2DArray os a = Texture2DArray TexName Size3 MaxLevels data Texture3D os a = Texture3D TexName Size3 MaxLevels data TextureCube os a = TextureCube TexName Size1 MaxLevels type MaxLevels = Int type Size1 = Int type Size2 = V2 Int type Size3 = V3 Int getNewSamplerId :: ShaderM s SamplerId getNewSamplerId = SamplerId <$> getNewName newTexture1D :: forall ctx w os f c m. (ContextHandler ctx, ColorSampleable c, MonadIO m) => Format c -> Size1 -> MaxLevels -> ContextT ctx os m (Texture1D os (Format c)) newTexture1DArray :: forall ctx w os f c m. (ContextHandler ctx, ColorSampleable c, MonadIO m) => Format c -> Size2 -> MaxLevels -> ContextT ctx os m (Texture1DArray os (Format c)) newTexture2D :: forall ctx w os f c m. (ContextHandler ctx, TextureFormat c, MonadIO m) => Format c -> Size2 -> MaxLevels -> ContextT ctx os m (Texture2D os (Format c)) newTexture2DArray :: forall ctx w os f c m. (ContextHandler ctx, ColorSampleable c, MonadIO m) => Format c -> Size3 -> MaxLevels -> ContextT ctx os m (Texture2DArray os (Format c)) newTexture3D :: forall ctx w os f c m. (ContextHandler ctx, ColorRenderable c, MonadIO m) => Format c -> Size3 -> MaxLevels -> ContextT ctx os m (Texture3D os (Format c)) newTextureCube :: forall ctx w os f c m. (ContextHandler ctx, ColorSampleable c, MonadIO m) => Format c -> Size1 -> MaxLevels -> ContextT ctx os m (TextureCube os (Format c)) newTexture1D f s mx | s < 0 = error "newTexture1D, negative size" | mx <= 0 = error "newTexture1D, non-positive MaxLevels" | otherwise = do mxSize <- getGlValue GL_MAX_TEXTURE_SIZE if s > mxSize then liftIO $ throwIO $ GPipeException "newTexture1D, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels s) tex = Texture1D t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_1D forM_ (zip (texture1DSizes tex) [0..]) $ \(lw, l) -> glTexImage1D GL_TEXTURE_1D l glintf (fromIntegral lw) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_1D (ls-1) return tex newTexture1DArray f s@(V2 w sl) mx | w < 0 || sl < 0 = error "newTexture1DArray, negative size" | mx <= 0 = error "newTexture1DArray, non-positive MaxLevels" | otherwise = do mxSize <- getGlValue GL_MAX_TEXTURE_SIZE if w > mxSize || sl > mxSize then liftIO $ throwIO $ GPipeException "newTexture1DArray, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels w) tex = Texture1DArray t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_1D_ARRAY forM_ (zip (texture1DArraySizes tex) [0..]) $ \(V2 lw _, l) -> glTexImage2D GL_TEXTURE_1D_ARRAY l glintf (fromIntegral lw) (fromIntegral sl) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_1D_ARRAY (ls-1) return tex newTexture2D f s@(V2 w h) mx | w < 0 || h < 0 = error "newTexture2D, negative size" | mx <= 0 = error "newTexture2D, non-positive MaxLevels" | getGlFormat (undefined :: c) == GL_STENCIL_INDEX = do mxSize <- getGlValue GL_MAX_RENDERBUFFER_SIZE if w > mxSize || h > mxSize then liftIO $ throwIO $ GPipeException "newTexture2D, size larger than maximum supported by graphics driver" else do t <- makeRenderBuff liftNonWinContextAsyncIO $ glRenderbufferStorage GL_RENDERBUFFER (getGlInternalFormat f) (fromIntegral w) (fromIntegral h) return $ RenderBuffer2D t s | otherwise = do mxSize <- getGlValue GL_MAX_TEXTURE_SIZE if w > mxSize || h > mxSize then liftIO $ throwIO $ GPipeException "newTexture2D, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels (max w h)) tex = Texture2D t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_2D forM_ (zip (texture2DSizes tex) [0..]) $ \(V2 lw lh, l) -> glTexImage2D GL_TEXTURE_2D l glintf (fromIntegral lw) (fromIntegral lh) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_2D (ls-1) return tex newTexture2DArray f s@(V3 w h sl) mx | w < 0 || h < 0 || sl < 0 = error "newTexture2DArray, negative size" | mx <= 0 = error "newTexture2DArray, non-positive MaxLevels" | otherwise = do mxSize <- getGlValue GL_MAX_TEXTURE_SIZE if w > mxSize || h > mxSize || sl > mxSize then liftIO $ throwIO $ GPipeException "newTexture2DArray, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels (max w h)) tex = Texture2DArray t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_2D_ARRAY forM_ (zip (texture2DArraySizes tex) [0..]) $ \(V3 lw lh _, l) -> glTexImage3D GL_TEXTURE_2D_ARRAY l glintf (fromIntegral lw) (fromIntegral lh) (fromIntegral sl) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_2D_ARRAY (ls-1) return tex newTexture3D f s@(V3 w h d) mx | w < 0 || h < 0 || d < 0 = error "newTexture3D, negative size" | mx <= 0 = error "newTexture3D, non-positive MaxLevels" | otherwise = do mxSize <- getGlValue GL_MAX_TEXTURE_SIZE if w > mxSize || h > mxSize || d > mxSize then liftIO $ throwIO $ GPipeException "newTexture3D, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels (max w (max h d))) tex = Texture3D t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_3D forM_ (zip (texture3DSizes tex) [0..]) $ \(V3 lw lh ld, l) -> glTexImage3D GL_TEXTURE_3D l glintf (fromIntegral lw) (fromIntegral lh) (fromIntegral ld) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_3D (ls-1) return tex newTextureCube f s mx | s < 0 = error "newTextureCube, negative size" | mx <= 0 = error "newTextureCube, non-positive MaxLevels" | otherwise = do mxSize <- getGlValue GL_MAX_CUBE_MAP_TEXTURE_SIZE if s > mxSize then liftIO $ throwIO $ GPipeException "newTextureCube, size larger than maximum supported by graphics driver" else do t <- makeTex let glintf = fromIntegral $ getGlInternalFormat f glf = getGlFormat (undefined :: c) ls = min mx (calcMaxLevels s) tex = TextureCube t s ls liftNonWinContextAsyncIO $ do useTexSync t GL_TEXTURE_CUBE_MAP forM_ [(size, getGlCubeSide side) | size <- zip (textureCubeSizes tex) [0..], side <- [minBound..maxBound]] $ \((lx, l), side) -> glTexImage2D side l glintf (fromIntegral lx) (fromIntegral lx) 0 glf GL_BYTE nullPtr setDefaultTexParams GL_TEXTURE_CUBE_MAP (ls-1) glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_S GL_CLAMP_TO_EDGE glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_T GL_CLAMP_TO_EDGE glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_R GL_CLAMP_TO_EDGE return tex getGlValue :: (ContextHandler ctx, MonadIO m) => GLenum -> ContextT ctx os m Int getGlValue enum = liftNonWinContextIO $ alloca (\ptr -> fmap fromIntegral (glGetIntegerv enum ptr >> peek ptr)) setDefaultTexParams :: GLenum -> Int -> IO () setDefaultTexParams t ml = do glTexParameteri t GL_TEXTURE_BASE_LEVEL 0 glTexParameteri t GL_TEXTURE_MAX_LEVEL (fromIntegral ml) glTexParameteri t GL_TEXTURE_MIN_FILTER GL_NEAREST_MIPMAP_NEAREST glTexParameteri t GL_TEXTURE_MAG_FILTER GL_NEAREST texture1DLevels :: Texture1D os f -> Int texture1DArrayLevels :: Texture1DArray os f -> Int texture2DLevels :: Texture2D os f -> Int texture2DArrayLevels :: Texture2DArray os f -> Int texture3DLevels :: Texture3D os f -> Int textureCubeLevels :: TextureCube os f -> Int texture1DLevels (Texture1D _ _ ls) = ls texture1DArrayLevels (Texture1DArray _ _ ls) = ls texture2DLevels (Texture2D _ _ ls) = ls texture2DLevels (RenderBuffer2D _ _) = 1 texture2DArrayLevels (Texture2DArray _ _ ls) = ls texture3DLevels (Texture3D _ _ ls) = ls textureCubeLevels (TextureCube _ _ ls) = ls texture1DSizes :: Texture1D os f -> [Size1] texture1DArraySizes :: Texture1DArray os f -> [Size2] texture2DSizes :: Texture2D os f -> [Size2] texture2DArraySizes :: Texture2DArray os f -> [Size3] texture3DSizes :: Texture3D os f -> [Size3] textureCubeSizes :: TextureCube os f -> [Size1] texture1DSizes (Texture1D _ w ls) = map (calcLevelSize w) [0..(ls-1)] texture1DArraySizes (Texture1DArray _ (V2 w s) ls) = map (\l -> V2 (calcLevelSize w l) s) [0..(ls-1)] texture2DSizes (Texture2D _ (V2 w h) ls) = map (\l -> V2 (calcLevelSize w l) (calcLevelSize h l)) [0..(ls-1)] texture2DSizes (RenderBuffer2D _ s) = [s] texture2DArraySizes (Texture2DArray _ (V3 w h s) ls) = map (\l -> V3 (calcLevelSize w l) (calcLevelSize h l) s) [0..(ls-1)] texture3DSizes (Texture3D _ (V3 w h d) ls) = map (\l -> V3 (calcLevelSize w l) (calcLevelSize h l) (calcLevelSize d l)) [0..(ls-1)] textureCubeSizes (TextureCube _ x ls) = map (calcLevelSize x) [0..(ls-1)] calcLevelSize :: Int -> Int -> Int calcLevelSize size0 level = max 1 (size0 `div` (2 ^ level)) calcMaxLevels :: Int -> Int calcMaxLevels s = 1 + truncate (logBase 2.0 (fromIntegral s :: Double)) type TexName = IORef GLuint makeTex :: (ContextHandler ctx, MonadIO m) => ContextT ctx os m TexName makeTex = do name <- liftNonWinContextIO $ alloca (\ptr -> glGenTextures 1 ptr >> peek ptr) tex <- liftIO $ newIORef name addContextFinalizer tex $ with name (glDeleteTextures 1) addFBOTextureFinalizer False tex return tex makeRenderBuff :: (ContextHandler ctx, MonadIO m) => ContextT ctx os m TexName makeRenderBuff = do name <- liftNonWinContextIO $ alloca (\ptr -> glGenRenderbuffers 1 ptr >> peek ptr) tex <- liftIO $ newIORef name addContextFinalizer tex $ with name (glDeleteRenderbuffers 1) addFBOTextureFinalizer True tex return tex useTex :: Integral a => TexName -> GLenum -> a -> IO Int useTex texNameRef t bind = do glActiveTexture (GL_TEXTURE0 + fromIntegral bind) n <- readIORef texNameRef glBindTexture t n return (fromIntegral n) useTexSync :: TexName -> GLenum -> IO () useTexSync tn t = do maxUnits <- alloca (\ptr -> glGetIntegerv GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ptr >> peek ptr) -- Use last for all sync actions, keeping 0.. for async drawcalls void $ useTex tn t (maxUnits-1) type Level = Int data CubeSide = CubePosX | CubeNegX | CubePosY | CubeNegY | CubePosZ | CubeNegZ deriving (Eq, Enum, Bounded) type StartPos1 = Int type StartPos2 = V2 Int type StartPos3 = V3 Int writeTexture1D :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture1D os (Format c) -> Level -> StartPos1 -> Size1 -> [h] -> ContextT ctx os m () writeTexture1DArray :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture1DArray os (Format c) -> Level -> StartPos2 -> Size2 -> [h] -> ContextT ctx os m () writeTexture2D :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture2D os (Format c) -> Level -> StartPos2 -> Size2 -> [h] -> ContextT ctx os m () writeTexture2DArray :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture2DArray os (Format c) -> Level -> StartPos3 -> Size3 -> [h] -> ContextT ctx os m () writeTexture3D :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture3D os (Format c) -> Level -> StartPos3 -> Size3 -> [h] -> ContextT ctx os m () writeTextureCube :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => TextureCube os (Format c) -> Level -> CubeSide -> StartPos2 -> Size2 -> [h] -> ContextT ctx os m () writeTexture1DFromBuffer :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture1D os (Format c) -> Level -> StartPos1 -> Size1 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () writeTexture1DArrayFromBuffer:: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture1DArray os (Format c) -> Level -> StartPos2 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () writeTexture2DFromBuffer :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture2D os (Format c) -> Level -> StartPos2 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () writeTexture2DArrayFromBuffer:: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture2DArray os (Format c) -> Level -> StartPos3 -> Size3 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () writeTexture3DFromBuffer :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture3D os (Format c) -> Level -> StartPos3 -> Size3 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () writeTextureCubeFromBuffer :: forall ctx b c h w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => TextureCube os (Format c) -> Level -> CubeSide -> StartPos2 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTexture1D :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture1D os (Format c) -> Level -> StartPos1 -> Size1 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTexture1DArray :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture1DArray os (Format c) -> Level -> StartPos2 -> Size1 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTexture2D :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture2D os (Format c) -> Level -> StartPos2 -> Size2 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTexture2DArray :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture2DArray os (Format c) -> Level -> StartPos3 -> Size2 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTexture3D :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => Texture3D os (Format c) -> Level -> StartPos3 -> Size2 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTextureCube :: forall ctx a b c h w os f m. (ContextHandler ctx, MonadAsyncException m, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) h ~ b, h ~ HostFormat b) => TextureCube os (Format c) -> Level -> CubeSide -> StartPos2 -> Size2 -> (a -> h -> ContextT ctx os m a) -> a -> ContextT ctx os m a readTexture1DToBuffer :: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture1D os (Format c) -> Level -> StartPos1 -> Size1 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTexture1DArrayToBuffer:: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture1DArray os (Format c) -> Level -> StartPos2 -> Size1 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTexture2DToBuffer :: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture2D os (Format c) -> Level -> StartPos2 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTexture2DArrayToBuffer:: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture2DArray os (Format c) -> Level -> StartPos3 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTexture3DToBuffer :: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => Texture3D os (Format c) -> Level -> StartPos3 -> Size2 -> Buffer os b -> BufferStartPos -> ContextT ctx os m () readTextureCubeToBuffer :: forall ctx b c w os f m. (ContextHandler ctx, MonadIO m, BufferFormat b, ColorSampleable c, BufferColor (Color c (ColorElement c)) (HostFormat b) ~ b) => TextureCube os (Format c) -> Level -> CubeSide -> StartPos2 -> Size2 -> Buffer os b-> BufferStartPos -> ContextT ctx os m () getGlColorFormat :: (TextureFormat f, BufferFormat b) => f -> b -> GLenum getGlColorFormat f b = let x = getGlFormat f in if x == GL_DEPTH_STENCIL || x == GL_DEPTH_COMPONENT then GL_DEPTH_COMPONENT else getGlPaddedFormat b writeTexture1D t@(Texture1D texn _ ml) l x w d | l < 0 || l >= ml = error "writeTexture1D, level out of bounds" | x < 0 || x >= mx = error "writeTexture1D, x out of bounds" | w < 0 || x+w > mx = error "writeTexture1D, w out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take w d) if end `minusPtr` ptr /= size then error "writeTexture1D, data list too short" else do useTexSync texn GL_TEXTURE_1D glTexSubImage1D GL_TEXTURE_1D (fromIntegral l) (fromIntegral x) (fromIntegral w) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where mx = texture1DSizes t !! l writeTexture1DArray t@(Texture1DArray texn _ ml) l (V2 x y) (V2 w h) d | l < 0 || l >= ml = error "writeTexture1DArray, level out of bounds" | x < 0 || x >= mx = error "writeTexture1DArray, x out of bounds" | w < 0 || x+w > mx = error "writeTexture1DArray, w out of bounds" | y < 0 || y >= my = error "writeTexture1DArray, y out of bounds" | h < 0 || y+h > my = error "writeTexture2D, h out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*h*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take (w*h) d) if end `minusPtr` ptr /= size then error "writeTexture1DArray, data list too short" else do useTexSync texn GL_TEXTURE_1D_ARRAY glTexSubImage2D GL_TEXTURE_1D_ARRAY (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where V2 mx my = texture1DArraySizes t !! l writeTexture2D t@(Texture2D texn _ ml) l (V2 x y) (V2 w h) d | l < 0 || l >= ml = error "writeTexture2D, level out of bounds" | x < 0 || x >= mx = error "writeTexture2D, x out of bounds" | w < 0 || x+w > mx = error "writeTexture2D, w out of bounds" | y < 0 || y >= my = error "writeTexture2D, y out of bounds" | h < 0 || y+h > my = error "writeTexture2D, h out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*h*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take (w*h) d) if end `minusPtr` ptr /= size then error "writeTexture2D, data list too short" else do useTexSync texn GL_TEXTURE_2D glTexSubImage2D GL_TEXTURE_2D (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where V2 mx my = texture2DSizes t !! l writeTexture2DArray t@(Texture2DArray texn _ ml) l (V3 x y z) (V3 w h d) dat | l < 0 || l >= ml = error "writeTexture2DArray, level out of bounds" | x < 0 || x >= mx = error "writeTexture2DArray, x out of bounds" | w < 0 || x+w > mx = error "writeTexture2DArray, w out of bounds" | y < 0 || y >= my = error "writeTexture2DArray, y out of bounds" | h < 0 || y+h > my = error "writeTexture2DArray, h out of bounds" | z < 0 || z >= mz = error "writeTexture2DArray, z out of bounds" | d < 0 || z+d > mz = error "writeTexture2DArray, d out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*h*d*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take (w*h*d) dat) if end `minusPtr` ptr /= size then error "writeTexture2DArray, data list too short" else do useTexSync texn GL_TEXTURE_2D_ARRAY glTexSubImage3D GL_TEXTURE_2D_ARRAY (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral z) (fromIntegral w) (fromIntegral h) (fromIntegral d) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where V3 mx my mz = texture2DArraySizes t !! l writeTexture3D t@(Texture3D texn _ ml) l (V3 x y z) (V3 w h d) dat | l < 0 || l >= ml = error "writeTexture3D, level out of bounds" | x < 0 || x >= mx = error "writeTexture3D, x out of bounds" | w < 0 || x+w > mx = error "writeTexture3D, w out of bounds" | y < 0 || y >= my = error "writeTexture3D, y out of bounds" | h < 0 || y+h > my = error "writeTexture3D, h out of bounds" | z < 0 || z >= mz = error "writeTexture3D, z out of bounds" | d < 0 || z+d > mz = error "writeTexture3D, d out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*h*d*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take (w*h*d) dat) if end `minusPtr` ptr /= size then error "writeTexture3D, data list too short" else do useTexSync texn GL_TEXTURE_3D glTexSubImage3D GL_TEXTURE_3D (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral z) (fromIntegral w) (fromIntegral h) (fromIntegral d) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where V3 mx my mz = texture3DSizes t !! l writeTextureCube t@(TextureCube texn _ ml) l s (V2 x y) (V2 w h) d | l < 0 || l >= ml = error "writeTextureCube, level out of bounds" | x < 0 || x >= mxy = error "writeTextureCube, x out of bounds" | w < 0 || x+w > mxy = error "writeTextureCube, w out of bounds" | y < 0 || y >= mxy = error "writeTextureCube, y out of bounds" | h < 0 || y+h > mxy = error "writeTextureCube, h out of bounds" | otherwise = liftNonWinContextAsyncIO $ do let b = makeBuffer undefined undefined 0 :: Buffer os b size = w*h*bufElementSize b allocaBytes size $ \ ptr -> do end <- bufferWriteInternal b ptr (take (w*h) d) if end `minusPtr` ptr /= size then error "writeTextureCube, data list too short" else do useTexSync texn GL_TEXTURE_CUBE_MAP glTexSubImage2D (getGlCubeSide s) (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr where mxy = textureCubeSizes t !! l writeTexture1DFromBuffer t@(Texture1D texn _ ml) l x w b i | l < 0 || l >= ml = error "writeTexture1DFromBuffer, level out of bounds" | x < 0 || x >= mx = error "writeTexture1DFromBuffer, x out of bounds" | w < 0 || x+w > mx = error "writeTexture1DFromBuffer, w out of bounds" | i < 0 || i > bufferLength b = error "writeTexture1DFromBuffer, i out of bounds" | bufferLength b - i < w = error "writeTexture1DFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_1D bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage1D GL_TEXTURE_1D (fromIntegral l) (fromIntegral x) (fromIntegral w) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where mx = texture1DSizes t !! l writeTexture1DArrayFromBuffer t@(Texture1DArray texn _ ml) l (V2 x y) (V2 w h) b i | l < 0 || l >= ml = error "writeTexture1DArrayFromBuffer, level out of bounds" | x < 0 || x >= mx = error "writeTexture1DArrayFromBuffer, x out of bounds" | w < 0 || x+w > mx = error "writeTexture1DArrayFromBuffer, w out of bounds" | y < 0 || y >= my = error "writeTexture1DArrayFromBuffer, y out of bounds" | h < 0 || y+h > my = error "writeTexture1DArrayFromBuffer, h out of bounds" | i < 0 || i > bufferLength b = error "writeTexture1DArrayFromBuffer, i out of bounds" | bufferLength b - i < w*h = error "writeTexture1DArrayFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_1D_ARRAY bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage2D GL_TEXTURE_1D_ARRAY (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where V2 mx my = texture1DArraySizes t !! l writeTexture2DFromBuffer t@(Texture2D texn _ ml) l (V2 x y) (V2 w h) b i | l < 0 || l >= ml = error "writeTexture2DFromBuffer, level out of bounds" | x < 0 || x >= mx = error "writeTexture2DFromBuffer, x out of bounds" | w < 0 || x+w > mx = error "writeTexture2DFromBuffer, w out of bounds" | y < 0 || y >= my = error "writeTexture2DFromBuffer, y out of bounds" | h < 0 || y+h > my = error "writeTexture2DFromBuffer, h out of bounds" | i < 0 || i > bufferLength b = error "writeTexture2DFromBuffer, i out of bounds" | bufferLength b - i < w*h = error "writeTexture2DFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_2D bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage2D GL_TEXTURE_2D (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where V2 mx my = texture2DSizes t !! l writeTexture2DArrayFromBuffer t@(Texture2DArray texn _ ml) l (V3 x y z) (V3 w h d) b i | l < 0 || l >= ml = error "writeTexture2DArrayFromBuffer, level out of bounds" | x < 0 || x >= mx = error "writeTexture2DArrayFromBuffer, x out of bounds" | w < 0 || x+w > mx = error "writeTexture2DArrayFromBuffer, w out of bounds" | y < 0 || y >= my = error "writeTexture2DArrayFromBuffer, y out of bounds" | h < 0 || y+h > my = error "writeTexture2DArrayFromBuffer, h out of bounds" | z < 0 || z >= mz = error "writeTexture2DArrayFromBuffer, z out of bounds" | d < 0 || z+d > mz = error "writeTexture2DArrayFromBuffer, d out of bounds" | i < 0 || i > bufferLength b = error "writeTexture2DArrayFromBuffer, i out of bounds" | bufferLength b - i < w*h = error "writeTexture2DArrayFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_2D_ARRAY bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage3D GL_TEXTURE_2D_ARRAY (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral z) (fromIntegral w) (fromIntegral h) (fromIntegral d) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where V3 mx my mz = texture2DArraySizes t !! l writeTexture3DFromBuffer t@(Texture3D texn _ ml) l (V3 x y z) (V3 w h d) b i | l < 0 || l >= ml = error "writeTexture3DFromBuffer, level out of bounds" | x < 0 || x >= mx = error "writeTexture3DFromBuffer, x out of bounds" | w < 0 || x+w > mx = error "writeTexture3DFromBuffer, w out of bounds" | y < 0 || y >= my = error "writeTexture3DFromBuffer, y out of bounds" | h < 0 || y+h > my = error "writeTexture3DFromBuffer, h out of bounds" | z < 0 || z >= mz = error "writeTexture3DFromBuffer, z out of bounds" | d < 0 || z+d > mz = error "writeTexture3DFromBuffer, d out of bounds" | i < 0 || i > bufferLength b = error "writeTexture3DFromBuffer, i out of bounds" | bufferLength b - i < w*h = error "writeTexture3DFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_3D bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage3D GL_TEXTURE_3D (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral z) (fromIntegral w) (fromIntegral h) (fromIntegral d) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where V3 mx my mz = texture3DSizes t !! l writeTextureCubeFromBuffer t@(TextureCube texn _ ml) l s (V2 x y) (V2 w h) b i | l < 0 || l >= ml = error "writeTextureCubeFromBuffer, level out of bounds" | x < 0 || x >= mxy = error "writeTextureCubeFromBuffer, x out of bounds" | w < 0 || x+w > mxy = error "writeTextureCubeFromBuffer, w out of bounds" | y < 0 || y >= mxy = error "writeTextureCubeFromBuffer, y out of bounds" | h < 0 || y+h > mxy = error "writeTextureCubeFromBuffer, h out of bounds" | i < 0 || i > bufferLength b = error "writeTextureCubeFromBuffer, i out of bounds" | bufferLength b - i < w*h = error "writeTextureCubeFromBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do useTexSync texn GL_TEXTURE_CUBE_MAP bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_UNPACK_BUFFER bname glTexSubImage2D (getGlCubeSide s) (fromIntegral l) (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_UNPACK_BUFFER 0 where mxy = textureCubeSizes t !! l readTexture1D t@(Texture1D texn _ ml) l x w f s | l < 0 || l >= ml = error "readTexture1DArray, level out of bounds" | x < 0 || x >= mx = error "readTexture1DArray, x out of bounds" | w < 0 || x+w > mx = error "readTexture1DArray, w out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*bufElementSize b setGlPixelStoreRange x 0 0 w 1 useTexSync texn GL_TEXTURE_1D_ARRAY glGetTexImage GL_TEXTURE_1D_ARRAY (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*bufElementSize b -1]) where mx = texture1DSizes t !! l readTexture1DArray t@(Texture1DArray texn _ ml) l (V2 x y) w f s | l < 0 || l >= ml = error "readTexture1DArray, level out of bounds" | x < 0 || x >= mx = error "readTexture1DArray, x out of bounds" | w < 0 || x+w > mx = error "readTexture1DArray, w out of bounds" | y < 0 || y >= my = error "readTexture1DArray, y out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*bufElementSize b setGlPixelStoreRange x y 0 w 1 useTexSync texn GL_TEXTURE_1D_ARRAY glGetTexImage GL_TEXTURE_1D_ARRAY (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*bufElementSize b -1]) where V2 mx my = texture1DArraySizes t !! l readTexture2D t@(Texture2D texn _ ml) l (V2 x y) (V2 w h) f s | l < 0 || l >= ml = error "readTexture2D, level out of bounds" | x < 0 || x >= mx = error "readTexture2D, x out of bounds" | w < 0 || x+w > mx = error "readTexture2D, w out of bounds" | y < 0 || y >= my = error "readTexture2D, y out of bounds" | h < 0 || y+h > my = error "readTexture2D, h out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*h*bufElementSize b setGlPixelStoreRange x y 0 w h useTexSync texn GL_TEXTURE_2D glGetTexImage GL_TEXTURE_2D (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*h*bufElementSize b -1]) where V2 mx my = texture2DSizes t !! l readTexture2DArray t@(Texture2DArray texn _ ml) l (V3 x y z) (V2 w h) f s | l < 0 || l >= ml = error "readTexture2DArray, level out of bounds" | x < 0 || x >= mx = error "readTexture2DArray, x out of bounds" | w < 0 || x+w > mx = error "readTexture2DArray, w out of bounds" | y < 0 || y >= my = error "readTexture2DArray, y out of bounds" | h < 0 || y+h > my = error "readTexture2DArray, h out of bounds" | z < 0 || z >= mz = error "readTexture2DArray, y out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*h*bufElementSize b setGlPixelStoreRange x y z w h useTexSync texn GL_TEXTURE_2D_ARRAY glGetTexImage GL_TEXTURE_2D_ARRAY (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*h*bufElementSize b -1]) where V3 mx my mz = texture2DArraySizes t !! l readTexture3D t@(Texture3D texn _ ml) l (V3 x y z) (V2 w h) f s | l < 0 || l >= ml = error "readTexture3D, level out of bounds" | x < 0 || x >= mx = error "readTexture3D, x out of bounds" | w < 0 || x+w > mx = error "readTexture3D, w out of bounds" | y < 0 || y >= my = error "readTexture3D, y out of bounds" | h < 0 || y+h > my = error "readTexture3D, h out of bounds" | z < 0 || z >= mz = error "readTexture3D, y out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*h*bufElementSize b setGlPixelStoreRange x y z w h useTexSync texn GL_TEXTURE_3D glGetTexImage GL_TEXTURE_3D (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*h*bufElementSize b -1]) where V3 mx my mz = texture3DSizes t !! l readTextureCube t@(TextureCube texn _ ml) l si (V2 x y) (V2 w h) f s | l < 0 || l >= ml = error "readTextureCube, level out of bounds" | x < 0 || x >= mxy = error "readTextureCube, x out of bounds" | w < 0 || x+w > mxy = error "readTextureCube, w out of bounds" | y < 0 || y >= mxy = error "readTextureCube, y out of bounds" | h < 0 || y+h > mxy = error "readTextureCube, h out of bounds" | otherwise = let b = makeBuffer undefined undefined 0 :: Buffer os b f' ptr a off = f a =<< liftIO (peekPixel (undefined :: b) (ptr `plusPtr` off)) in bracket (liftNonWinContextIO $ do ptr <- mallocBytes $ w*h*bufElementSize b setGlPixelStoreRange x y 0 w h useTexSync texn GL_TEXTURE_CUBE_MAP glGetTexImage (getGlCubeSide si) (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) ptr return ptr) (liftIO . free) (\ptr -> foldM (f' ptr) s [0,bufElementSize b..w*h*bufElementSize b -1]) where mxy = textureCubeSizes t !! l readTexture1DToBuffer t@(Texture1D texn _ ml) l x w b i | l < 0 || l >= ml = error "readTexture1DToBuffer, level out of bounds" | x < 0 || x >= mx = error "readTexture1DToBuffer, x out of bounds" | w < 0 || x+w > mx = error "readTexture1DToBuffer, w out of bounds" | i < 0 || i > bufferLength b = error "readTexture1DToBuffer, i out of bounds" | bufferLength b - i < w = error "readTexture1DToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname setGlPixelStoreRange x 0 0 w 1 useTexSync texn GL_TEXTURE_1D glGetTexImage GL_TEXTURE_1D (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where mx = texture1DSizes t !! l readTexture1DArrayToBuffer t@(Texture1DArray texn _ ml) l (V2 x y) w b i | l < 0 || l >= ml = error "readTexture1DArrayToBuffer, level out of bounds" | x < 0 || x >= mx = error "readTexture1DArrayToBuffer, x out of bounds" | w < 0 || x+w > mx = error "readTexture1DArrayToBuffer, w out of bounds" | y < 0 || y >= my = error "readTexture1DArrayToBuffer, y out of bounds" | i < 0 || i > bufferLength b = error "readTexture1DArrayToBuffer, i out of bounds" | bufferLength b - i < w = error "readTexture1DArrayToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname setGlPixelStoreRange x y 0 w 1 useTexSync texn GL_TEXTURE_1D_ARRAY glGetTexImage GL_TEXTURE_1D_ARRAY (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where V2 mx my = texture1DArraySizes t !! l readTexture2DToBuffer t@(Texture2D texn _ ml) l (V2 x y) (V2 w h) b i | l < 0 || l >= ml = error "readTexture2DToBuffer, level out of bounds" | x < 0 || x >= mx = error "readTexture2DToBuffer, x out of bounds" | w < 0 || x+w > mx = error "readTexture2DToBuffer, w out of bounds" | y < 0 || y >= my = error "readTexture2DToBuffer, y out of bounds" | h < 0 || y+h > my = error "readTexture2DToBuffer, h out of bounds" | i < 0 || i > bufferLength b = error "readTexture2DToBuffer, i out of bounds" | bufferLength b - i < w*h = error "readTexture2DToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname setGlPixelStoreRange x y 0 w h useTexSync texn GL_TEXTURE_2D glGetTexImage GL_TEXTURE_2D (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where V2 mx my = texture2DSizes t !! l readTexture2DArrayToBuffer t@(Texture2DArray texn _ ml) l (V3 x y z) (V2 w h) b i | l < 0 || l >= ml = error "readTexture2DArrayToBuffer, level out of bounds" | x < 0 || x >= mx = error "readTexture2DArrayToBuffer, x out of bounds" | w < 0 || x+w > mx = error "readTexture2DArrayToBuffer, w out of bounds" | y < 0 || y >= my = error "readTexture2DArrayToBuffer, y out of bounds" | h < 0 || y+h > my = error "readTexture2DArrayToBuffer, h out of bounds" | z < 0 || z >= mz = error "readTexture2DArrayToBuffer, z out of bounds" | i < 0 || i > bufferLength b = error "readTexture2DArrayToBuffer, i out of bounds" | bufferLength b - i < w*h = error "readTexture2DArrayToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname setGlPixelStoreRange x y z w h useTexSync texn GL_TEXTURE_2D_ARRAY glGetTexImage GL_TEXTURE_2D_ARRAY (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where V3 mx my mz = texture2DArraySizes t !! l readTexture3DToBuffer t@(Texture3D texn _ ml) l (V3 x y z) (V2 w h) b i | l < 0 || l >= ml = error "readTexture3DToBuffer, level out of bounds" | x < 0 || x >= mx = error "readTexture3DToBuffer, x out of bounds" | w < 0 || x+w > mx = error "readTexture3DToBuffer, w out of bounds" | y < 0 || y >= my = error "readTexture3DToBuffer, y out of bounds" | h < 0 || y+h > my = error "readTexture3DToBuffer, h out of bounds" | z < 0 || z >= mz = error "readTexture3DToBuffer, z out of bounds" | i < 0 || i > bufferLength b = error "readTexture3DToBuffer, i out of bounds" | bufferLength b - i < w*h = error "readTexture3DToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname setGlPixelStoreRange x y z w h useTexSync texn GL_TEXTURE_3D glGetTexImage GL_TEXTURE_3D (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where V3 mx my mz = texture3DSizes t !! l readTextureCubeToBuffer t@(TextureCube texn _ ml) l s (V2 x y) (V2 w h) b i | l < 0 || l >= ml = error "readTextureCubeToBuffer, level out of bounds" | x < 0 || x >= mxy = error "readTextureCubeToBuffer, x out of bounds" | w < 0 || x+w > mxy = error "readTextureCubeToBuffer, w out of bounds" | y < 0 || y >= mxy = error "readTextureCubeToBuffer, y out of bounds" | h < 0 || y+h > mxy = error "readTextureCubeToBuffer, h out of bounds" | i < 0 || i > bufferLength b = error "readTextureCubeToBuffer, i out of bounds" | bufferLength b - i < w*h = error "readTextureCubeToBuffer, buffer data too small" | otherwise = liftNonWinContextAsyncIO $ do setGlPixelStoreRange x y 0 w h bname <- readIORef $ bufName b glBindBuffer GL_PIXEL_PACK_BUFFER bname useTexSync texn GL_TEXTURE_CUBE_MAP glGetTexImage (getGlCubeSide s) (fromIntegral l) (getGlColorFormat (undefined :: c) (undefined :: b)) (getGlType (undefined :: b)) (wordPtrToPtr $ fromIntegral $ i*bufElementSize b) glBindBuffer GL_PIXEL_PACK_BUFFER 0 where mxy = textureCubeSizes t !! l setGlPixelStoreRange :: Int -> Int -> Int -> Int -> Int -> IO () setGlPixelStoreRange x y z w h = do glPixelStorei GL_PACK_SKIP_PIXELS $ fromIntegral x glPixelStorei GL_PACK_SKIP_ROWS $ fromIntegral y glPixelStorei GL_PACK_SKIP_IMAGES $ fromIntegral z glPixelStorei GL_PACK_ROW_LENGTH $ fromIntegral w glPixelStorei GL_PACK_IMAGE_HEIGHT $ fromIntegral h generateTexture1DMipmap :: (ContextHandler ctx, MonadIO m) => Texture1D os f -> ContextT ctx os m () generateTexture1DArrayMipmap :: (ContextHandler ctx, MonadIO m) => Texture1DArray os f -> ContextT ctx os m () generateTexture2DMipmap :: (ContextHandler ctx, MonadIO m) => Texture2D os f -> ContextT ctx os m () generateTexture2DArrayMipmap :: (ContextHandler ctx, MonadIO m) => Texture2DArray os f -> ContextT ctx os m () generateTexture3DMipmap :: (ContextHandler ctx, MonadIO m) => Texture3D os f -> ContextT ctx os m () generateTextureCubeMipmap :: (ContextHandler ctx, MonadIO m) => TextureCube os f -> ContextT ctx os m () genMips :: (ContextHandler ctx, MonadIO m) => TexName -> GLenum -> ContextT ctx os m () genMips texn target = liftNonWinContextAsyncIO $ do useTexSync texn target glGenerateMipmap target generateTexture1DMipmap (Texture1D texn _ _) = genMips texn GL_TEXTURE_1D generateTexture1DArrayMipmap (Texture1DArray texn _ _) = genMips texn GL_TEXTURE_1D_ARRAY generateTexture2DMipmap (Texture2D texn _ _) = genMips texn GL_TEXTURE_2D generateTexture2DMipmap _ = return () -- Only one level for renderbuffers generateTexture2DArrayMipmap (Texture2DArray texn _ _) = genMips texn GL_TEXTURE_2D_ARRAY generateTexture3DMipmap (Texture3D texn _ _) = genMips texn GL_TEXTURE_3D generateTextureCubeMipmap (TextureCube texn _ _) = genMips texn GL_TEXTURE_CUBE_MAP ---------------------------------------------------------------------- -- Samplers data Filter = Nearest | Linear deriving (Eq, Enum) data EdgeMode = Repeat | Mirror | ClampToEdge | ClampToBorder deriving (Eq, Enum) type BorderColor c = Color c (ColorElement c) type Anisotropy = Maybe Float type MinFilter = Filter type MagFilter = Filter type LodFilter = Filter -- | A GADT for sample filters, where 'SamplerFilter' cannot be used for integer textures. data SamplerFilter c where SamplerFilter :: (ColorElement c ~ Float) => MagFilter -> MinFilter -> LodFilter -> Anisotropy -> SamplerFilter c SamplerNearest :: SamplerFilter c type EdgeMode2 = V2 EdgeMode type EdgeMode3 = V3 EdgeMode data ComparisonFunction = Never | Less | Equal | Lequal | Greater | Notequal | Gequal | Always deriving ( Eq, Ord, Show ) getGlCompFunc :: (Num a, Eq a) => ComparisonFunction -> a getGlCompFunc Never = GL_NEVER getGlCompFunc Less = GL_LESS getGlCompFunc Equal = GL_EQUAL getGlCompFunc Lequal = GL_LEQUAL getGlCompFunc Greater = GL_GREATER getGlCompFunc Notequal = GL_NOTEQUAL getGlCompFunc Gequal = GL_GEQUAL getGlCompFunc Always = GL_ALWAYS newSampler1D :: forall os s c. ColorSampleable c => (s -> (Texture1D os (Format c), SamplerFilter c, (EdgeMode, BorderColor c))) -> Shader os s (Sampler1D (Format c)) newSampler1DArray :: forall os s c. ColorSampleable c => (s -> (Texture1DArray os (Format c), SamplerFilter c, (EdgeMode, BorderColor c))) -> Shader os s (Sampler1DArray (Format c)) newSampler2D :: forall os s c. ColorSampleable c => (s -> (Texture2D os (Format c), SamplerFilter c, (EdgeMode2, BorderColor c))) -> Shader os s (Sampler2D (Format c)) newSampler2DArray :: forall os s c. ColorSampleable c => (s -> (Texture2DArray os (Format c), SamplerFilter c, (EdgeMode2, BorderColor c))) -> Shader os s (Sampler2DArray (Format c)) newSampler3D :: forall os s c. ColorRenderable c => (s -> (Texture3D os (Format c), SamplerFilter c, (EdgeMode3, BorderColor c))) -> Shader os s (Sampler3D (Format c)) newSamplerCube :: forall os s c. ColorSampleable c => (s -> (TextureCube os (Format c), SamplerFilter c)) -> Shader os s (SamplerCube (Format c)) newSampler1DShadow :: forall os s d. DepthRenderable d => (s -> (Texture1D os (Format d), SamplerFilter d, (EdgeMode, BorderColor d), ComparisonFunction)) -> Shader os s (Sampler1D Shadow) newSampler1DArrayShadow :: forall os s d. DepthRenderable d => (s -> (Texture1DArray os (Format d), SamplerFilter d, (EdgeMode, BorderColor d), ComparisonFunction)) -> Shader os s (Sampler1DArray Shadow) newSampler2DShadow :: forall os s d. DepthRenderable d => (s -> (Texture2D os d, SamplerFilter (Format d), (EdgeMode2, BorderColor d), ComparisonFunction)) -> Shader os s (Sampler2D Shadow) newSampler2DArrayShadow :: forall os s d. DepthRenderable d => (s -> (Texture2DArray os (Format d), SamplerFilter d, (EdgeMode2, BorderColor d), ComparisonFunction)) -> Shader os s (Sampler2DArray Shadow) newSamplerCubeShadow :: forall os s d. DepthRenderable d => (s -> (TextureCube os (Format d), SamplerFilter d, ComparisonFunction)) -> Shader os s (SamplerCube Shadow) newSampler1D sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture1D tn _ _, filt, (ex, ec)) = sf s in do n <- useTex tn GL_TEXTURE_1D bind setNoShadowMode GL_TEXTURE_1D setSamplerFilter GL_TEXTURE_1D filt setEdgeMode GL_TEXTURE_1D (Just ex, Nothing, Nothing) (setBorderColor (undefined :: c) GL_TEXTURE_1D ec) return n return $ Sampler1D sampId False (samplerPrefix (undefined :: c)) newSampler1DArray sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture1DArray tn _ _, filt, (ex, ec)) = sf s in do n <- useTex tn GL_TEXTURE_1D_ARRAY bind setNoShadowMode GL_TEXTURE_1D_ARRAY setSamplerFilter GL_TEXTURE_1D_ARRAY filt setEdgeMode GL_TEXTURE_1D_ARRAY (Just ex, Nothing, Nothing) (setBorderColor (undefined :: c) GL_TEXTURE_1D_ARRAY ec) return n return $ Sampler1DArray sampId False (samplerPrefix (undefined :: c)) newSampler2D sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture2D tn _ _, filt, (V2 ex ey, ec)) = sf s in do n <- useTex tn GL_TEXTURE_2D bind setNoShadowMode GL_TEXTURE_2D setSamplerFilter GL_TEXTURE_2D filt setEdgeMode GL_TEXTURE_2D (Just ex, Just ey, Nothing) (setBorderColor (undefined :: c) GL_TEXTURE_2D ec) return n return $ Sampler2D sampId False (samplerPrefix (undefined :: c)) newSampler2DArray sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture2DArray tn _ _, filt, (V2 ex ey, ec)) = sf s in do n <- useTex tn GL_TEXTURE_2D_ARRAY bind setNoShadowMode GL_TEXTURE_2D_ARRAY setSamplerFilter GL_TEXTURE_2D_ARRAY filt setEdgeMode GL_TEXTURE_2D_ARRAY (Just ex, Just ey, Nothing) (setBorderColor (undefined :: c) GL_TEXTURE_2D_ARRAY ec) return n return $ Sampler2DArray sampId False (samplerPrefix (undefined :: c)) newSampler3D sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture3D tn _ _, filt, (V3 ex ey ez, ec)) = sf s in do n <- useTex tn GL_TEXTURE_3D bind setNoShadowMode GL_TEXTURE_3D setSamplerFilter GL_TEXTURE_3D filt setEdgeMode GL_TEXTURE_3D (Just ex, Just ey, Just ez) (setBorderColor (undefined :: c) GL_TEXTURE_3D ec) return n return $ Sampler3D sampId False (samplerPrefix (undefined :: c)) newSamplerCube sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (TextureCube tn _ _, filt) = sf s in do n <- useTex tn GL_TEXTURE_CUBE_MAP bind setNoShadowMode GL_TEXTURE_CUBE_MAP setSamplerFilter GL_TEXTURE_CUBE_MAP filt return n return $ SamplerCube sampId False (samplerPrefix (undefined :: c)) newSampler1DShadow sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture1D tn _ _, filt, (ex, ec), cf) = sf s in do n <- useTex tn GL_TEXTURE_1D bind setShadowFunc GL_TEXTURE_1D cf setSamplerFilter GL_TEXTURE_1D filt setEdgeMode GL_TEXTURE_1D (Just ex, Nothing, Nothing) (setBorderColor (undefined :: d) GL_TEXTURE_1D ec) return n return $ Sampler1D sampId True "" newSampler1DArrayShadow sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture1DArray tn _ _, filt, (ex, ec), cf) = sf s in do n <- useTex tn GL_TEXTURE_1D_ARRAY bind setShadowFunc GL_TEXTURE_1D_ARRAY cf setSamplerFilter GL_TEXTURE_1D_ARRAY filt setEdgeMode GL_TEXTURE_1D_ARRAY (Just ex, Nothing, Nothing) (setBorderColor (undefined :: d) GL_TEXTURE_1D_ARRAY ec) return n return $ Sampler1DArray sampId True "" newSampler2DShadow sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture2D tn _ _, filt, (V2 ex ey, ec), cf) = sf s in do n <- useTex tn GL_TEXTURE_2D bind setShadowFunc GL_TEXTURE_2D cf setSamplerFilter GL_TEXTURE_2D filt setEdgeMode GL_TEXTURE_2D (Just ex, Just ey, Nothing) (setBorderColor (undefined :: d) GL_TEXTURE_2D ec) return n return $ Sampler2D sampId True "" newSampler2DArrayShadow sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (Texture2DArray tn _ _, filt, (V2 ex ey, ec), cf) = sf s in do n <- useTex tn GL_TEXTURE_2D_ARRAY bind setShadowFunc GL_TEXTURE_2D_ARRAY cf setSamplerFilter GL_TEXTURE_2D_ARRAY filt setEdgeMode GL_TEXTURE_2D_ARRAY (Just ex, Just ey, Nothing) (setBorderColor (undefined :: d) GL_TEXTURE_2D_ARRAY ec) return n return $ Sampler2DArray sampId True "" newSamplerCubeShadow sf = Shader $ do sampId <- getNewSamplerId doForSampler sampId $ \s bind -> let (TextureCube tn _ _, filt, cf) = sf s in do n <- useTex tn GL_TEXTURE_CUBE_MAP bind setShadowFunc GL_TEXTURE_CUBE_MAP cf setSamplerFilter GL_TEXTURE_CUBE_MAP filt return n return $ SamplerCube sampId True "" setNoShadowMode :: GLenum -> IO () setNoShadowMode t = glTexParameteri t GL_TEXTURE_COMPARE_MODE GL_NONE setShadowFunc :: GLenum -> ComparisonFunction -> IO () setShadowFunc t cf = do glTexParameteri t GL_TEXTURE_COMPARE_MODE GL_COMPARE_REF_TO_TEXTURE glTexParameteri t GL_TEXTURE_COMPARE_FUNC (getGlCompFunc cf) setEdgeMode :: GLenum -> (Maybe EdgeMode, Maybe EdgeMode, Maybe EdgeMode) -> IO () -> IO () setEdgeMode t (se,te,re) bcio = do glwrap GL_TEXTURE_WRAP_S se glwrap GL_TEXTURE_WRAP_T te glwrap GL_TEXTURE_WRAP_R re when (se == Just ClampToBorder || te == Just ClampToBorder || re == Just ClampToBorder) bcio where glwrap _ Nothing = return () glwrap x (Just Repeat) = glTexParameteri t x GL_REPEAT glwrap x (Just Mirror) = glTexParameteri t x GL_MIRRORED_REPEAT glwrap x (Just ClampToEdge) = glTexParameteri t x GL_CLAMP_TO_EDGE glwrap x (Just ClampToBorder) = glTexParameteri t x GL_CLAMP_TO_BORDER setSamplerFilter :: GLenum -> SamplerFilter a -> IO () setSamplerFilter t (SamplerFilter magf minf lodf a) = setSamplerFilter' t magf minf lodf a setSamplerFilter t SamplerNearest = setSamplerFilter' t Nearest Nearest Nearest Nothing setSamplerFilter' :: GLenum -> MagFilter -> MinFilter -> LodFilter -> Anisotropy -> IO () setSamplerFilter' t magf minf lodf a = do glTexParameteri t GL_TEXTURE_MIN_FILTER glmin glTexParameteri t GL_TEXTURE_MAG_FILTER glmag case a of Nothing -> return () Just a' -> glTexParameterf t GL_TEXTURE_MAX_ANISOTROPY_EXT (realToFrac a') where glmin = case (minf, lodf) of (Nearest, Nearest) -> GL_NEAREST_MIPMAP_NEAREST (Linear, Nearest) -> GL_LINEAR_MIPMAP_NEAREST (Nearest, Linear) -> GL_NEAREST_MIPMAP_LINEAR (Linear, Linear) -> GL_LINEAR_MIPMAP_LINEAR glmag = case magf of Nearest -> GL_NEAREST Linear -> GL_LINEAR doForSampler :: SamplerId -> (s -> Binding -> IO Int) -> ShaderM s () doForSampler n io = modifyRenderIO (\s -> s { samplerNameToRenderIO = insert n io (samplerNameToRenderIO s) } ) -- | Used instead of 'Format' for shadow samplers. These samplers have specialized sampler values, see 'sample1DShadow' and friends. data Shadow data Sampler1D f = Sampler1D SamplerId Bool Text data Sampler1DArray f = Sampler1DArray SamplerId Bool Text data Sampler2D f = Sampler2D SamplerId Bool Text data Sampler2DArray f = Sampler2DArray SamplerId Bool Text data Sampler3D f = Sampler3D SamplerId Bool Text data SamplerCube f = SamplerCube SamplerId Bool Text -- | A GADT to specify where the level of detail and/or partial derivates should be taken from. Some values of this GADT are restricted to -- only 'FragmentStream's. data SampleLod vx x where SampleAuto :: SampleLod v F SampleBias :: FFloat -> SampleLod vx F SampleLod :: S x Float -> SampleLod vx x SampleGrad :: vx -> vx -> SampleLod vx x -- | For some reason, OpenGl doesnt allow explicit lod to be specified for some sampler types, hence this extra GADT. data SampleLod' vx x where SampleAuto' :: SampleLod' v F SampleBias' :: FFloat -> SampleLod' vx F SampleGrad' :: vx -> vx -> SampleLod' vx x type SampleLod1 x = SampleLod (S x Float) x type SampleLod2 x = SampleLod (V2 (S x Float)) x type SampleLod3 x = SampleLod (V3 (S x Float)) x type SampleLod2' x = SampleLod' (V2 (S x Float)) x type SampleLod3' x = SampleLod' (V3 (S x Float)) x fromLod' :: SampleLod' v x -> SampleLod v x fromLod' SampleAuto' = SampleAuto fromLod' (SampleBias' x) = SampleBias x fromLod' (SampleGrad' x y) = SampleGrad x y type SampleProj x = Maybe (S x Float) type SampleOffset1 x = Maybe Int type SampleOffset2 x = Maybe (V2 Int) type SampleOffset3 x = Maybe (V3 Int) -- | The type of a color sample made by a texture t type ColorSample x f = Color f (S x (ColorElement f)) type ReferenceValue x = S x Float sample1D :: forall c x. ColorSampleable c => Sampler1D (Format c) -> SampleLod1 x -> SampleProj x -> SampleOffset1 x -> S x Float -> ColorSample x c sample1DArray :: forall c x. ColorSampleable c => Sampler1DArray (Format c) -> SampleLod1 x -> SampleOffset1 x -> V2 (S x Float) -> ColorSample x c sample2D :: forall c x. ColorSampleable c => Sampler2D (Format c) -> SampleLod2 x -> SampleProj x -> SampleOffset2 x -> V2 (S x Float) -> ColorSample x c sample2DArray :: forall c x. ColorSampleable c => Sampler2DArray (Format c) -> SampleLod2 x -> SampleOffset2 x -> V3 (S x Float) -> ColorSample x c sample3D :: forall c x. ColorSampleable c => Sampler3D (Format c) -> SampleLod3 x -> SampleProj x -> SampleOffset3 x -> V3 (S x Float) -> ColorSample x c sampleCube :: forall c x. ColorSampleable c => SamplerCube (Format c) -> SampleLod3 x -> V3 (S x Float) -> ColorSample x c sample1DShadow :: forall x. Sampler1D Shadow -> SampleLod1 x -> SampleProj x -> SampleOffset1 x -> ReferenceValue x -> S x Float -> S x Float sample1DArrayShadow :: forall x. Sampler1DArray Shadow-> SampleLod1 x -> SampleOffset1 x -> ReferenceValue x -> V2 (S x Float) -> S x Float sample2DShadow :: forall x. Sampler2D Shadow -> SampleLod2 x -> SampleProj x -> SampleOffset2 x -> ReferenceValue x -> V2 (S x Float) -> S x Float sample2DArrayShadow :: forall x. Sampler2DArray Shadow-> SampleLod2' x -> SampleOffset2 x -> ReferenceValue x -> V3 (S x Float)-> S x Float sampleCubeShadow :: forall x. SamplerCube Shadow -> SampleLod3' x -> ReferenceValue x -> V3 (S x Float) -> S x Float sample1D (Sampler1D sampId _ prefix) lod proj off coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "1D" sampId lod proj off coord v1toF v1toF civ1toF pv1toF sample1DArray (Sampler1DArray sampId _ prefix) lod off coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "1DArray" sampId lod Nothing off coord v2toF v1toF civ1toF undefined sample2D (Sampler2D sampId _ prefix) lod proj off coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "2D" sampId lod proj off coord v2toF v2toF civ2toF pv2toF sample2DArray (Sampler2DArray sampId _ prefix) lod off coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "2DArray" sampId lod Nothing off coord v3toF v2toF civ2toF undefined sample3D (Sampler3D sampId _ prefix) lod proj off coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "3D" sampId lod proj off coord v3toF v3toF civ3toF pv3toF sampleCube (SamplerCube sampId _ prefix) lod coord = toColor (undefined :: c) $ sample (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "Cube" sampId lod Nothing Nothing coord v3toF v3toF undefined undefined sample1DShadow (Sampler1D sampId _ _) lod proj off ref coord = sampleShadow "1D" sampId lod proj off (t1t3 coord ref) v3toF v1toF civ1toF pv3toF sample1DArrayShadow (Sampler1DArray sampId _ _) lod off ref coord = sampleShadow "1DArray" sampId lod Nothing off (t2t3 coord ref) v3toF v1toF civ1toF undefined sample2DShadow (Sampler2D sampId _ _) lod proj off ref coord = sampleShadow "2D" sampId lod proj off (t2t3 coord ref) v3toF v2toF civ2toF pv3toF sample2DArrayShadow (Sampler2DArray sampId _ _) lod off ref coord = sampleShadow "2DArray" sampId (fromLod' lod) Nothing off (t3t4 coord ref) v4toF v2toF civ2toF undefined sampleCubeShadow (SamplerCube sampId _ _) lod ref coord = sampleShadow "Cube" sampId (fromLod' lod) Nothing Nothing (t3t4 coord ref) v4toF v3toF undefined undefined t1t3 :: S x Float -> S x Float -> V3 (S x Float) t2t3 :: V2 t -> t -> V3 t t3t4 :: V3 t -> t -> V4 t t1t3 x = V3 x 0 t2t3 (V2 x y) = V3 x y t3t4 (V3 x y z) = V4 x y z texelFetch1D :: forall c x. ColorSampleable c => Sampler1D (Format c) -> SampleOffset1 x -> S x Level -> S x Int -> ColorSample x c texelFetch1DArray :: forall c x. ColorSampleable c => Sampler1DArray (Format c) -> SampleOffset1 x -> S x Level -> V2(S x Int) -> ColorSample x c texelFetch2D :: forall c x. ColorSampleable c => Sampler2D (Format c) -> SampleOffset2 x -> S x Level -> V2 (S x Int) -> ColorSample x c texelFetch2DArray :: forall c x. ColorSampleable c => Sampler2DArray (Format c) -> SampleOffset2 x -> S x Level -> V3 (S x Int) -> ColorSample x c texelFetch3D :: forall c x. ColorSampleable c => Sampler3D (Format c) -> SampleOffset3 x -> S x Level -> V3 (S x Int) -> ColorSample x c texelFetch1D (Sampler1D sampId _ prefix) off lod coord = toColor (undefined :: c) $ fetch (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "1D" sampId lod off coord iv1toF civ1toF texelFetch1DArray (Sampler1DArray sampId _ prefix) off lod coord = toColor (undefined :: c) $ fetch (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "1DArray" sampId lod off coord iv2toF civ1toF texelFetch2D (Sampler2D sampId _ prefix) off lod coord = toColor (undefined :: c) $ fetch (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "2D" sampId lod off coord iv2toF civ2toF texelFetch2DArray (Sampler2DArray sampId _ prefix) off lod coord = toColor (undefined :: c) $ fetch (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "2DArray" sampId lod off coord iv3toF civ2toF texelFetch3D (Sampler3D sampId _ prefix) off lod coord = toColor (undefined :: c) $ fetch (undefined :: ColorElement c) prefix (typeStr4 (undefined :: c)) "3D" sampId lod off coord iv3toF civ3toF sampler1DSize :: Sampler1D f -> S x Level -> S x Int sampler1DArraySize :: Sampler1DArray f -> S x Level -> V2 (S x Int) sampler2DSize :: Sampler2D f -> S x Level -> V2 (S x Int) sampler2DArraySize :: Sampler2DArray f -> S x Level -> V3 (S x Int) sampler3DSize :: Sampler3D f -> S x Level -> V3 (S x Int) samplerCubeSize :: SamplerCube f -> S x Level -> S x Int sampler1DSize (Sampler1D sampId shadow prefix) = scalarS STypeInt . getTextureSize prefix sampId (addShadowPrefix shadow "1D") sampler1DArraySize (Sampler1DArray sampId shadow prefix) = vec2S (STypeIVec 2) . getTextureSize prefix sampId (addShadowPrefix shadow "1DArray") sampler2DSize (Sampler2D sampId shadow prefix) = vec2S (STypeIVec 2) . getTextureSize prefix sampId (addShadowPrefix shadow "2D") sampler2DArraySize (Sampler2DArray sampId shadow prefix) = vec3S (STypeIVec 3) . getTextureSize prefix sampId (addShadowPrefix shadow "2DArray") sampler3DSize (Sampler3D sampId shadow prefix) = vec3S (STypeIVec 3) . getTextureSize prefix sampId (addShadowPrefix shadow "3D") samplerCubeSize (SamplerCube sampId shadow prefix) = (\(V2 x _) -> x) . vec2S (STypeIVec 2) . getTextureSize prefix sampId (addShadowPrefix shadow "Cube") addShadowPrefix :: Bool -> Text -> Text addShadowPrefix shadow = if shadow then (<> "Shadow") else id getTextureSize :: Text -> SamplerId -> Text -> S c Int -> ExprM Text getTextureSize prefix sampId sName l = do s <- useSampler prefix sName sampId l' <- unS l return $ "textureSize(" <> s <> "," <> l' <> ")" sample :: e -> Text -> Text -> Text -> SamplerId -> SampleLod lcoord x -> SampleProj x -> Maybe off -> coord -> (coord -> ExprM Text) -> (lcoord -> ExprM Text) -> (off -> Text) -> (coord -> S x Float -> ExprM Text) -> V4 (S x e) sample _ prefix sDynType sName sampId lod proj off coord vToS lvToS ivToS pvToS = vec4S (STypeDyn sDynType) $ do s <- useSampler prefix sName sampId sampleFunc s proj lod off coord vToS lvToS ivToS pvToS sampleShadow :: Text -> SamplerId -> SampleLod lcoord x -> SampleProj x -> Maybe off -> coord -> (coord -> ExprM Text) -> (lcoord -> ExprM Text) -> (off -> Text) -> (coord -> S x Float -> ExprM Text) -> S x Float sampleShadow sName sampId lod proj off coord vToS lvToS civToS pvToS = scalarS STypeFloat $ do s <- useSampler "" (sName <> "Shadow") sampId sampleFunc s proj lod off coord vToS lvToS civToS pvToS fetch :: e -> Text -> Text -> Text -> SamplerId -> S x Int -> Maybe off -> coord -> (coord -> ExprM Text) -> (off -> Text) -> V4 (S x e) fetch _ prefix sDynType sName sampId lod off coord ivToS civToS = vec4S (STypeDyn sDynType) $ do s <- useSampler prefix sName sampId fetchFunc s off coord lod ivToS civToS v1toF :: S c Float -> ExprM Text v2toF :: V2 (S c Float) -> ExprM Text v3toF :: V3 (S c Float) -> ExprM Text v4toF :: V4 (S c Float) -> ExprM Text v1toF = unS v2toF (V2 x y) = do x' <- unS x y' <- unS y return $ "vec2(" <> x' <> "," <> y' <> ")" v3toF (V3 x y z) = do x' <- unS x y' <- unS y z' <- unS z return $ "vec3(" <> x' <> "," <> y' <> "," <> z' <> ")" v4toF (V4 x y z w) = do x' <- unS x y' <- unS y z' <- unS z w' <- unS w return $ "vec4(" <> x' <> "," <> y' <> "," <> z' <> "," <> w' <> ")" iv1toF :: S c Int -> ExprM Text iv2toF :: V2 (S c Int) -> ExprM Text iv3toF :: V3 (S c Int) -> ExprM Text iv1toF = unS iv2toF (V2 x y) = do x' <- unS x y' <- unS y return $ "ivec2(" <> x' <> "," <> y' <> ")" iv3toF (V3 x y z) = do x' <- unS x y' <- unS y z' <- unS z return $ "ivec3(" <> x' <> "," <> y' <> "," <> z' <> ")" civ1toF :: Int -> Text civ2toF :: V2 Int -> Text civ3toF :: V3 Int -> Text civ1toF = tshow civ2toF (V2 x y) = "ivec2(" <> tshow x <> "," <> tshow y <> ")" civ3toF (V3 x y z) = "ivec3(" <> tshow x <> "," <> tshow y <> "," <> tshow z <> ")" pv1toF :: S c Float -> S c Float -> ExprM Text pv2toF :: V2 (S c Float) -> S c Float -> ExprM Text pv3toF :: V3 (S c Float) -> S c Float -> ExprM Text pv1toF x y = do x' <- unS x y' <- unS y return $ "vec2(" <> x' <> "," <> y' <> ")" pv2toF (V2 x y) z = do x' <- unS x y' <- unS y z' <- unS z return $ "vec3(" <> x' <> "," <> y' <> "," <> z' <> ")" pv3toF (V3 x y z) w = do x' <- unS x y' <- unS y z' <- unS z w' <- unS w return $ "vec4(" <> x' <> "," <> y' <> "," <> z' <> "," <> w' <> ")" sampleFunc :: Text -> Maybe a -> SampleLod vx x -> Maybe t -> coord -> (coord -> ExprM Text) -> (vx -> ExprM Text) -> (t -> Text) -> (coord -> a -> ExprM Text) -> ExprM Text sampleFunc s proj lod off coord vToS lvToS civToS pvToS = do pc <- projCoordParam proj l <- lodParam lod b <- biasParam lod return $ "texture" <> projName proj <> lodName lod <> offName off <> "(" <> s <> "," <> pc <> l <> o <> b <> ")" where o = offParam off civToS projName Nothing = "" projName _ = "Proj" projCoordParam Nothing = vToS coord projCoordParam (Just p) = pvToS coord p lodParam (SampleLod x) = fmap ("," <> ) (unS x) lodParam (SampleGrad x y) = (<>) <$> fmap ("," <> ) (lvToS x) <*> fmap ("," <> ) (lvToS y) lodParam _ = return "" biasParam :: SampleLod v x -> ExprM Text biasParam (SampleBias (S x)) = do x' <- x return $ "," <> x' biasParam _ = return "" lodName (SampleLod _) = "Lod" lodName (SampleGrad _ _) = "Grad" lodName _ = "" fetchFunc :: Text -> Maybe t -> coord -> S x a -> (coord -> ExprM Text) -> (t -> Text) -> ExprM Text fetchFunc s off coord lod vToS civToS = do c <- vToS coord l <- unS lod return $ "texelFetch" <> offName off <> "(" <> s <> "," <> c <> "," <> l <> o <> ")" where o = offParam off civToS offParam :: Maybe t -> (t -> Text) -> Text offParam Nothing _ = "" offParam (Just x) civToS = "," <> civToS x offName :: Maybe t -> Text offName Nothing = "" offName _ = "Offset" ---------------------------------------------------------------------------------- -- | A texture image is a reference to a 2D array of pixels in a texture. Some textures contain one 'Image' per level of detail while some contain several. data Image f = Image TexName Int Int (V2 Int) (GLuint -> IO ()) -- the two Ints is last two in FBOKey instance Eq (Image f) where (==) = imageEquals -- | Compare two images that doesn't necessarily has same type imageEquals :: Image a -> Image b -> Bool imageEquals (Image tn' k1' k2' _ _) (Image tn k1 k2 _ _) = tn' == tn && k1' == k1 && k2' == k2 getImageBinding :: Image t -> GLuint -> IO () getImageBinding (Image _ _ _ _ io) = io getImageFBOKey :: Image t -> IO FBOKey getImageFBOKey (Image tn k1 k2 _ _) = do tn' <- readIORef tn return $ FBOKey tn' k1 k2 -- | Retrieve the 2D size an image imageSize :: Image f -> V2 Int imageSize (Image _ _ _ s _) = s getTexture1DImage :: Texture1D os f -> Level -> Render os (Image f) getTexture1DArrayImage :: Texture1DArray os f -> Level -> Int -> Render os (Image f) getTexture2DImage :: Texture2D os f -> Level -> Render os (Image f) getTexture2DArrayImage :: Texture2DArray os f -> Level -> Int -> Render os (Image f) getTexture3DImage :: Texture3D os f -> Level -> Int -> Render os (Image f) getTextureCubeImage :: TextureCube os f -> Level -> CubeSide -> Render os (Image f) getLayeredTextureImage :: Texture3D os f -> MaxLevels -> Render os (Image f) registerRenderWriteTextureName :: TexName -> Render os () registerRenderWriteTextureName tn = Render (lift $ lift $ lift $ readIORef tn) >>= registerRenderWriteTexture . fromIntegral getTexture1DImage t@(Texture1D tn _ ls) l' = let l = min ls l' in do registerRenderWriteTextureName tn return $ Image tn 0 l (V2 (texture1DSizes t !! l) 1) $ \attP -> do n <- readIORef tn glFramebufferTexture1D GL_DRAW_FRAMEBUFFER attP GL_TEXTURE_1D n (fromIntegral l) getTexture1DArrayImage t@(Texture1DArray tn _ ls) l' y' = let l = min ls l' V2 x y = texture1DArraySizes t !! l in do registerRenderWriteTextureName tn return $ Image tn y' l (V2 x 1) $ \attP -> do n <- readIORef tn glFramebufferTextureLayer GL_DRAW_FRAMEBUFFER attP n (fromIntegral l) (fromIntegral $ min y' (y-1)) getTexture2DImage t@(Texture2D tn _ ls) l' = let l = min ls l' in do registerRenderWriteTextureName tn return $ Image tn 0 l (texture2DSizes t !! l) $ \attP -> do n <- readIORef tn glFramebufferTexture2D GL_DRAW_FRAMEBUFFER attP GL_TEXTURE_2D n (fromIntegral l) getTexture2DImage t@(RenderBuffer2D tn _) _ = return $ Image tn (-1) 0 (head $ texture2DSizes t) $ \attP -> do n <- readIORef tn glFramebufferRenderbuffer GL_DRAW_FRAMEBUFFER attP GL_RENDERBUFFER n getTexture2DArrayImage t@(Texture2DArray tn _ ls) l' z' = let l = min ls l' V3 x y z = texture2DArraySizes t !! l in do registerRenderWriteTextureName tn return $ Image tn z' l (V2 x y) $ \attP -> do n <- readIORef tn glFramebufferTextureLayer GL_DRAW_FRAMEBUFFER attP n (fromIntegral l) (fromIntegral $ min z' (z-1)) getTexture3DImage t@(Texture3D tn _ ls) l' z' = let l = min ls l' V3 x y z = texture3DSizes t !! l in do registerRenderWriteTextureName tn return $ Image tn z' l (V2 x y) $ \attP -> do n <- readIORef tn glFramebufferTextureLayer GL_DRAW_FRAMEBUFFER attP n (fromIntegral l) (fromIntegral $ min z' (z-1)) getTextureCubeImage t@(TextureCube tn _ ls) l' s = let l = min ls l' x = textureCubeSizes t !! l s' = getGlCubeSide s in do registerRenderWriteTextureName tn return $ Image tn (fromIntegral s') l (V2 x x) $ \attP -> do n <- readIORef tn glFramebufferTexture2D GL_DRAW_FRAMEBUFFER attP s' n (fromIntegral l) -- Experimental. Meant to be used with a geometry shader and emitVertex(PositionAnd)Layer. getLayeredTextureImage t@(Texture3D tn _ ls) l' = let l = min ls l' V3 x y _ = texture3DSizes t !! l in do registerRenderWriteTextureName tn return $ Image tn 0 l (V2 x y) $ \attP -> do n <- readIORef tn glFramebufferTexture GL_DRAW_FRAMEBUFFER attP n (fromIntegral l) getGlCubeSide :: CubeSide -> GLenum getGlCubeSide CubePosX = GL_TEXTURE_CUBE_MAP_POSITIVE_X getGlCubeSide CubeNegX = GL_TEXTURE_CUBE_MAP_NEGATIVE_X getGlCubeSide CubePosY = GL_TEXTURE_CUBE_MAP_POSITIVE_Y getGlCubeSide CubeNegY = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y getGlCubeSide CubePosZ = GL_TEXTURE_CUBE_MAP_POSITIVE_Z getGlCubeSide CubeNegZ = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z