h-raylib-5.1.1.0: src/Raylib/Internal/Web/Native.hs
{-# OPTIONS -Wall -Wno-unrecognised-pragmas #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# HLINT ignore "Redundant lambda" #-}
-- | Internal functions for running in a browser
--
-- /NOTE: This module is only used when building for the web/
module Raylib.Internal.Web.Native
( callRaylibFunction,
jslog,
jsfree,
p'jsfree,
CallRaylibType (..),
)
where
import Foreign (FunPtr, Ptr, Storable (peek, sizeOf), castPtr, free, mallocArray, pokeArray)
import Foreign.C (CChar, CString, CUChar (..), CUInt (..), castCharToCChar, withCStringLen)
import Raylib.Internal.Web.Processable
( Processable (processableType),
ProcessedParam (..),
processParam,
)
-- | For \"varargs\" function calls, based on https://wiki.haskell.org/Varargs
class CallRaylibType t where
callRaylibFunction' :: String -> IO [ProcessedParam] -> t
instance (Storable a, Processable a) => CallRaylibType (IO a) where
callRaylibFunction' func params' = do
params <- params'
callRaylibFunctionRaw func params
instance (Storable a, Processable a, CallRaylibType r) => CallRaylibType (a -> r) where
callRaylibFunction' func params' = \x ->
callRaylibFunction'
func
( do
params <- params'
param <- processParam x
return $ params ++ [param]
)
callRaylibFunctionRaw :: forall a. (Storable a, Processable a) => String -> [ProcessedParam] -> IO a
callRaylibFunctionRaw func params = do
let l = length func
p = length params
namePtr <- mallocArray l
pokeArray namePtr (map castCharToCChar func :: [CChar])
let nameLen = fromIntegral l :: CUInt
ptrs = map (\(ProcessedParam ptr _ _) -> ptr) params
sizes = map (\(ProcessedParam _ size _) -> fromIntegral size) params :: [CUInt]
signs = map (\(ProcessedParam _ _ pType) -> fromIntegral pType) params :: [CUChar]
numParams = fromIntegral p :: CUInt
ptrsPtr <- mallocArray p
pokeArray ptrsPtr ptrs
sizesPtr <- mallocArray p
pokeArray sizesPtr sizes
typesPtr <- mallocArray p
pokeArray typesPtr signs
resPtr <- c'callRaylibFunction namePtr nameLen ptrsPtr sizesPtr typesPtr numParams (fromIntegral $ sizeOf (undefined :: a)) (fromIntegral $ fromEnum $ processableType (undefined :: a))
res <- peek (castPtr resPtr)
jsfree resPtr
free namePtr
free ptrsPtr
mapM_ free ptrs
free sizesPtr
free typesPtr
return res
jslog :: String -> IO ()
jslog str = withCStringLen str (\(s, len) -> c'jslog s (fromIntegral len))
-- | This is an interfacing function that allows Haskell to call raylib
-- functions that have been compiled with emscripten. This has to be done in
-- a roundabout way because we cannot directly call these functions through
-- Haskell; we have to call a JS proxy function that calls the actual raylib
-- functions.
callRaylibFunction :: (CallRaylibType t) => String -> t
callRaylibFunction func = callRaylibFunction' func (return [])
#ifdef WEB_FFI
foreign import ccall "main.h jslog" c'jslog :: CString -> CUInt -> IO ()
foreign import ccall "main.h jsfree" jsfree :: Ptr () -> IO ()
foreign import ccall "main.h &jsfree" p'jsfree :: FunPtr (Ptr a -> IO ())
foreign import ccall "main.h callRaylibFunction" c'callRaylibFunction :: CString -> CUInt -> Ptr (Ptr ()) -> Ptr CUInt -> Ptr CUChar -> CUInt -> CUInt -> CUChar -> IO (Ptr ())
#else
c'jslog :: CString -> CUInt -> IO ()
c'jslog = error "(c'jslog) Not running in the web!"
jsfree :: Ptr () -> IO ()
jsfree = error "(jsfree) Not running in the web!"
p'jsfree :: FunPtr (Ptr a -> IO ())
p'jsfree = error "(p'jsfree) Not running in the web!"
c'callRaylibFunction :: CString -> CUInt -> Ptr (Ptr ()) -> Ptr CUInt -> Ptr CUChar -> CUInt -> CUInt -> CUChar -> IO (Ptr ())
c'callRaylibFunction = error "(c'callRaylibFunction): Not running in the web!"
#endif