diff --git a/examples/plot3d-demo/LICENSE b/examples/plot3d-demo/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/examples/plot3d-demo/app/Main.hs b/examples/plot3d-demo/app/Main.hs new file mode 100644 index 0000000..2596939 --- /dev/null +++ b/examples/plot3d-demo/app/Main.hs @@ -0,0 +1,250 @@ +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_GHC -ddump-splices #-} + +module Main where + +import Control.Monad.Extra (whenM, whileM) +import Data.Bits ((.|.)) +import Data.Foldable (for_, traverse_) +import Data.IORef (IORef, modifyIORef', newIORef, readIORef, writeIORef) +import Data.String (IsString (..)) +import FFICXX.Runtime.Cast (FPtr (..)) +import FFICXX.Runtime.TH (IsCPrimitive (..), TemplateParamInfo (..)) +import Foreign.C.String (CString, newCString, withCString) +import Foreign.C.Types (CBool (..), CDouble (..), CFloat, CInt (..), CUInt (..)) +import Foreign.Marshal.Alloc (alloca) +import Foreign.Marshal.Array (allocaArray) +import Foreign.Marshal.Utils (fromBool, toBool) +import Foreign.Ptr (Ptr, castPtr, nullPtr) +import Foreign.Storable (Storable (..)) +import ImGui +import ImGui.Enum +import ImGui.ImGuiIO.Implementation + ( imGuiIO_ConfigFlags_get, + imGuiIO_ConfigFlags_set, + imGuiIO_DeltaTime_get, + imGuiIO_Framerate_get, + ) +import ImGui.ImVec2.Implementation (imVec2_x_get, imVec2_y_get) +import ImGui.ImVec4.Implementation (imVec4_w_get, imVec4_x_get, imVec4_y_get, imVec4_z_get) +import ImPlot qualified +import ImPlot3D qualified +import ImPlot3D.Enum +import ImPlot3D.TH qualified +import ImPlot3D.Template +import STD.Deletable (delete) +import System.IO.Unsafe (unsafePerformIO) +import System.Random (randomRIO) +import Text.Printf (printf) + +instance IsString CString where + fromString s = unsafePerformIO $ newCString s + +-- this is a hack. but it's the best up to now. +ImPlot3D.TH.genPlotLine3DInstanceFor + CPrim + ( [t|Ptr CFloat|], + TPInfo + { tpinfoCxxType = "float", + tpinfoCxxHeaders = [], + tpinfoCxxNamespaces = [], + tpinfoSuffix = "float" + } + ) + +ImPlot3D.TH.genPlotSurfaceInstanceFor + CPrim + ( [t|Ptr CFloat|], + TPInfo + { tpinfoCxxType = "float", + tpinfoCxxHeaders = [], + tpinfoCxxNamespaces = [], + tpinfoSuffix = "float" + } + ) + +showFramerate :: ImGuiIO -> IO () +showFramerate io = do + begin ("Framerate monitor" :: CString) nullPtr 0 + framerate :: Float <- realToFrac <$> imGuiIO_Framerate_get io + withCString (printf "Application average %.3f ms/frame (%.1f FPS)" (1000.0 / framerate) framerate) $ \c_str -> + textUnformatted c_str + end + +demoLinePlot3D :: (Ptr CFloat, Ptr CFloat, Ptr CFloat) -> IO () +demoLinePlot3D (px1, py1, pz1) = do + t <- getTime + for_ [0 .. 1000] $ \i -> do + let x = fromIntegral i * 0.001 + pokeElemOff px1 i x + pokeElemOff py1 i (0.5 + 0.5 * cos (50.0 * (x + realToFrac t / 10.0))) + pokeElemOff pz1 i (0.5 + 0.5 * sin (50.0 * (x + realToFrac t / 10.0))) + + size <- newImVec2 (-1) 0 + whenM (toBool <$> ImPlot3D.beginPlot3D ("Line Plot" :: CString) size (fromIntegral (fromEnum ImPlot3DFlags_None))) $ do + ImPlot3D.setupAxes3D + ("x" :: CString) + ("y" :: CString) + ("z" :: CString) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + ImPlot3D.plotLine3D ("f(x)" :: CString) px1 py1 pz1 1001 (fromIntegral (fromEnum ImPlot3DLineFlags_None)) 0 4 {- sizeof(float) -} + ImPlot3D.endPlot3D + delete size + +demoSurfacePlot :: IORef CFloat -> (Ptr CFloat, Ptr CFloat, Ptr CFloat) -> IO () +demoSurfacePlot ref (px, py, pz) = do + t <- readIORef ref + io <- getIO + dt <- imGuiIO_DeltaTime_get io + let t' = t + dt + writeIORef ref t' + let n :: Int + n = 20 + min_val = -1.0 + max_val = 1.0 + step = (max_val - min_val) / (fromIntegral n - 1.0) + for_ [0 .. (n-1)] $ \i -> do + for_ [0 .. (n-1)] $ \j -> do + let idx = i * fromIntegral n + j + x, y, z :: CFloat + x = min_val + (fromIntegral j) * step + y = min_val + (fromIntegral i) * step + z = sin (2*t' + sqrt (x*x + y*y)) + pokeElemOff px idx x + pokeElemOff py idx y + pokeElemOff pz idx z + + size <- newImVec2 (-1) 0 + whenM (toBool <$> ImPlot3D.beginPlot3D ("Surface Plot" :: CString) size (fromIntegral (fromEnum ImPlot3DFlags_None))) $ do + ImPlot3D.setupAxes3D + ("x" :: CString) + ("y" :: CString) + ("z" :: CString) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + (fromIntegral (fromEnum ImPlot3DAxisFlags_None)) + + ImPlot3D.plotSurface ("Wave Surface" :: CString) px py pz (fromIntegral n) (fromIntegral n) 0.0 0.0 (fromIntegral (fromEnum ImPlot3DSurfaceFlags_NoMarkers)) 0 4 {- sizeof(float) -} + ImPlot3D.endPlot3D + + pure () + +imPlot3DDemo :: Resource -> IO () +imPlot3DDemo res = do + begin ("ImPlot3D Demo" :: CString) nullPtr 0 + whenM (toBool <$> beginTabBar ("ImPlot3DDemoTabs" :: CString)) $ do + whenM (toBool <$> beginTabItem_ ("Line plot" :: CString)) $ do + demoLinePlot3D (res_array1 res) + endTabItem + whenM (toBool <$> beginTabItem_ ("Surface plot" :: CString)) $ do + demoSurfacePlot (res_time res) (res_array2 res) + endTabItem + endTabBar + end + + +data Resource = Resource + { res_array1 :: (Ptr CFloat, Ptr CFloat, Ptr CFloat), + res_array2 :: (Ptr CFloat, Ptr CFloat, Ptr CFloat), + res_disp :: (Ptr CInt, Ptr CInt), + res_time :: IORef CFloat + } + +alloca3DArray :: (Int, Int, Int) -> ((Ptr CFloat, Ptr CFloat, Ptr CFloat) -> IO a) -> IO a +alloca3DArray (nx, ny, nz) f = + allocaArray nx $ \(px :: Ptr CFloat) -> + allocaArray ny $ \(py :: Ptr CFloat) -> + allocaArray nz $ \(pz :: Ptr CFloat) -> + f (px, py, pz) + +withRes :: (Resource -> IO a) -> IO a +withRes f = + alloca3DArray (1001, 1001, 1001) $ \(px1, py1, pz1) -> + alloca3DArray (400, 400, 400) $ \(px2, py2, pz2) -> + alloca $ \(p_dispW :: Ptr CInt) -> + alloca $ \(p_dispH :: Ptr CInt) -> do + t0 <- realToFrac <$> getTime + ref <- newIORef t0 + let res = Resource (px1, py1, pz1) (px2, py2, pz2) (p_dispW, p_dispH) ref + f res + +main :: IO () +main = do + let glsl_version :: CString + glsl_version = "#version 150" + glfwInit + glfwWindowHint (0x22002 {- GLFW_CONTEXT_VERSION_MAJOR -}) 3 + glfwWindowHint (0x22003 {- GLFW_CONTEXT_VERSION_MINOR -}) 2 + -- 3.2+ only + glfwWindowHint (0x22008 {- GLFW_OPENGL_PROFILE -}) (0x32001 {- GLFW_OPENGL_CORE_PROFILE -}) + -- Required on Mac + glfwWindowHint (0x22006 {- GLFW_OPENGL_FORWARD_COMPAT -}) (1 {- GL_TRUE -}) + window :: GLFWwindow <- + glfwCreateWindow + 1280 + 720 + ("ImPlot3D Haskell Demo" :: CString) + (cast_fptr_to_obj nullPtr :: GLFWmonitor) + (cast_fptr_to_obj nullPtr :: GLFWwindow) + glfwMakeContextCurrent window + -- Enable vsync + glfwSwapInterval 1 + ctxt <- createContext + ImPlot.createImPlotContext + ImPlot3D.createContext + io <- getIO + + -- Setup Dear ImGui style + -- styleColorsDark + styleColorsLight + + -- Setup Platform/Renderer backends + imGui_ImplGlfw_InitForOpenGL window (fromBool True) + imGui_ImplOpenGL3_Init glsl_version + + flags <- imGuiIO_ConfigFlags_get io + -- Enable Keyboard Controls and Gamepad Controls + let flags' = + flags + .|. fromIntegral (fromEnum ImGuiConfigFlags_NavEnableKeyboard) + .|. fromIntegral (fromEnum ImGuiConfigFlags_NavEnableGamepad) + imGuiIO_ConfigFlags_set io flags' + + clear_color <- newImVec4 0.45 0.55 0.60 1.00 + + withRes $ \res -> do + -- main loop + whileM $ do + glfwPollEvents + -- Start the Dear ImGui frame + imGui_ImplOpenGL3_NewFrame + imGui_ImplGlfw_NewFrame + newFrame + + showFramerate io + + -- start demo + imPlot3DDemo res + + render + + let (p_dispW, p_dispH) = res_disp res + glfwGetFramebufferSize window p_dispW p_dispH + dispW <- peek p_dispW + dispH <- peek p_dispH + glViewport 0 0 dispW dispH + x <- imVec4_x_get clear_color + y <- imVec4_y_get clear_color + z <- imVec4_z_get clear_color + w <- imVec4_w_get clear_color + glClearColor (x * w) (y * w) (z * w) w + glClear 0x4000 {- GL_COLOR_BUFFER_BIT -} + + imGui_ImplOpenGL3_RenderDrawData =<< getDrawData + glfwSwapBuffers window + + not . toBool <$> glfwWindowShouldClose window diff --git a/examples/plot3d-demo/plot3d-demo.cabal b/examples/plot3d-demo/plot3d-demo.cabal new file mode 100644 index 0000000..9eecdb1 --- /dev/null +++ b/examples/plot3d-demo/plot3d-demo.cabal @@ -0,0 +1,33 @@ +cabal-version: 3.4 +name: plot3d-demo +version: 0.1.0.0 +-- synopsis: +-- description: +license: MIT +license-file: LICENSE +author: Ian-Woo Kim +maintainer: ianwookim@gmail.com +-- copyright: +category: Graphics +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable plot3d-demo + import: warnings + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base ^>=4.18.0.0, + extra, + fficxx-runtime, + imgui, + implot, + implot3d, + random, + stdcxx + hs-source-dirs: app + default-language: GHC2021 diff --git a/flake.nix b/flake.nix index e28c4c4..c9deeb0 100644 --- a/flake.nix +++ b/flake.nix @@ -30,6 +30,9 @@ implot = self.callPackage ./nix/implot/default.nix { frameworks = self.darwin.apple_sdk.frameworks; }; + implot3d = self.callPackage ./nix/implot3d/default.nix { + frameworks = self.darwin.apple_sdk.frameworks; + }; }; in flake-utils.lib.eachDefaultSystem (system: let @@ -58,7 +61,7 @@ ] ++ ( if isEnv - then [p.imgui p.implot] + then [p.imgui p.implot p.implot3d] else [] )); pyenv = @@ -76,6 +79,7 @@ pkgs.cabal-install pkgs.imgui pkgs.implot + pkgs.implot3d pkgs.glfw pkgs.alejandra pkgs.pkgconfig diff --git a/imgui-gen/Gen.hs b/imgui-gen/Gen.hs index 7739cf9..77b1624 100644 --- a/imgui-gen/Gen.hs +++ b/imgui-gen/Gen.hs @@ -126,6 +126,7 @@ cabal = cabal_extrafiles = [], cabal_pkg_config_depends = ["libimgui", "glfw3"], cabal_buildType = Simple + -- NOTE: on macos, we also need ot add "frameworks: OpenGL" } gLFWmonitor :: Class diff --git a/implot-gen/Gen.hs b/implot-gen/Gen.hs index 62cebc1..8c1bd6b 100644 --- a/implot-gen/Gen.hs +++ b/implot-gen/Gen.hs @@ -335,6 +335,10 @@ extraLib = [] extraDep = [] +-- +-- +-- + data CLIMode = Gen (Maybe FilePath) | DepGraph (Maybe FilePath) diff --git a/implot3d-gen/Gen.hs b/implot3d-gen/Gen.hs new file mode 100644 index 0000000..9386787 --- /dev/null +++ b/implot3d-gen/Gen.hs @@ -0,0 +1,404 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import qualified Data.Graph as G +import qualified Data.HashMap.Strict as HM +import Data.Maybe (fromMaybe) +import Data.Tree (drawForest) +import FFICXX.Generate.Builder (simpleBuilder) +import FFICXX.Generate.Code.Primitive + ( bool, + bool_, + charpp, + cppclass, + cppclass_, + cppclasscopy_, + cppclassref, + cppclassref_, + cstring, + cstring_, + double, + double_, + float, + float_, + int, + int_, + star, + uint, + uint_, + void_, + voidp, + ) +import FFICXX.Generate.Config + ( FFICXXConfig (..), + SimpleBuilderConfig (..), + ) +import FFICXX.Generate.Dependency.Graph + ( constructDepGraph, + findDepCycles, + gatherHsBootSubmodules, + locateInDepCycles, + ) +import FFICXX.Generate.Type.Cabal (BuildType (..), Cabal (..), CabalName (..)) +import FFICXX.Generate.Type.Class + ( Arg (..), + CTypes (..), + Class (..), + EnumType (..), + Function (..), + ProtectedMethod (..), + TLOrdinary (..), + TLTemplate (..), + TopLevel (..), + Types (..), + Variable (..), + ) +import FFICXX.Generate.Type.Config + ( ModuleUnit (..), + ModuleUnitImports (..), + ModuleUnitMap (..), + modImports, + ) +import FFICXX.Generate.Type.Module (TemplateClassImportHeader (..)) +import FFICXX.Generate.Util.DepGraph (drawDepGraph) +import FFICXX.Runtime.Types (FFISafety (..)) +import qualified Options.Applicative as OA +import System.Directory (getCurrentDirectory) +import System.Environment (getArgs) +import System.FilePath (()) +import System.IO (IOMode (..), hPutStrLn, stdout, withFile) + +------------------------ +-- import from stdcxx -- +------------------------ + +stdcxx_cabal :: Cabal +stdcxx_cabal = + Cabal + { cabal_pkgname = CabalName "stdcxx", + cabal_version = "0.8.0.0", + cabal_cheaderprefix = "STD", + cabal_moduleprefix = "STD", + cabal_additional_c_incs = [], + cabal_additional_c_srcs = [], + cabal_additional_pkgdeps = [], + cabal_license = Nothing, + cabal_licensefile = Nothing, + cabal_extraincludedirs = [], + cabal_extralibdirs = [], + cabal_extrafiles = [], + cabal_pkg_config_depends = [], + cabal_buildType = Simple + } + +deletable :: Class +deletable = + AbstractClass + { class_cabal = stdcxx_cabal, + class_name = "Deletable", + class_parents = [], + class_protected = Protected [], + class_alias = Nothing, + class_funcs = [Destructor Nothing], + class_vars = [], + class_tmpl_funcs = [] + } + +-- +-- from imgui +-- + +imgui_cabal = + Cabal + { cabal_pkgname = CabalName "imgui", + cabal_version = "1.0.0.0", + cabal_cheaderprefix = "ImGui", + cabal_moduleprefix = "ImGui", + cabal_additional_c_incs = [], + cabal_additional_c_srcs = [], + cabal_additional_pkgdeps = [CabalName "stdcxx"], + cabal_license = Just "BSD-3-Clause", + cabal_licensefile = Just "LICENSE", + cabal_extraincludedirs = [], + cabal_extralibdirs = [], + cabal_extrafiles = [], + cabal_pkg_config_depends = ["libimgui", "glfw3"], + cabal_buildType = Simple + } + +imVec2 :: Class +imVec2 = + Class + imgui_cabal + "ImVec2" + [deletable] + mempty + Nothing + [] + [] + [] + False + +-- +-- from implot +-- + +implot_cabal = + Cabal + { cabal_pkgname = CabalName "implot", + cabal_version = "1.0.0.0", + cabal_cheaderprefix = "ImPlot", + cabal_moduleprefix = "ImPlot", + cabal_additional_c_incs = [], + cabal_additional_c_srcs = [], + cabal_additional_pkgdeps = [CabalName "stdcxx", CabalName "imgui"], + cabal_license = Just "BSD-3-Clause", + cabal_licensefile = Just "LICENSE", + cabal_extraincludedirs = [], + cabal_extralibdirs = [], + cabal_extrafiles = [], + cabal_pkg_config_depends = ["libimplot"], + cabal_buildType = Simple + } + +------------------ +-- start implot3d -- +------------------ + +cabal = + Cabal + { cabal_pkgname = CabalName "implot3d", + cabal_version = "1.0.0.0", + cabal_cheaderprefix = "ImPlot3D", + cabal_moduleprefix = "ImPlot3D", + cabal_additional_c_incs = [], + cabal_additional_c_srcs = [], + cabal_additional_pkgdeps = [CabalName "stdcxx", CabalName "imgui", CabalName "implot"], + cabal_license = Just "BSD-3-Clause", + cabal_licensefile = Just "LICENSE", + cabal_extraincludedirs = [], + cabal_extralibdirs = [], + cabal_extrafiles = [], + cabal_pkg_config_depends = ["libimplot3d"], + cabal_buildType = Simple + } + +imPlot3DFlags_ :: EnumType +imPlot3DFlags_ = + EnumType + { enum_name = "ImPlot3DFlags_", + enum_cases = + [ "ImPlot3DFlags_None", + "ImPlot3DFlags_NoTitle", + "ImPlot3DFlags_NoLegend", + "ImPlot3DFlags_NoMouseText", + "ImPlot3DFlags_NoClip", + "ImPlot3DFlags_NoMenus", + "ImPlot3DFlags_Equal", + "ImPlot3DFlags_NoRotate", + "ImPlot3DFlags_NoPan", + "ImPlot3DFlags_NoZoom", + "ImPlot3DFlags_NoInputs", + "ImPlot3DFlags_CanvasOnly" + ], + enum_header = "implot3d.h" + } + +imPlot3DAxisFlags_ :: EnumType +imPlot3DAxisFlags_ = + EnumType + { enum_name = "ImPlot3DAxisFlags_", + enum_cases = + [ "ImPlot3DAxisFlags_None", + "ImPlot3DAxisFlags_NoLabel", + "ImPlot3DAxisFlags_NoGridLines", + "ImPlot3DAxisFlags_NoTickMarks", + "ImPlot3DAxisFlags_NoTickLabels", + "ImPlot3DAxisFlags_LockMin", + "ImPlot3DAxisFlags_LockMax", + "ImPlot3DAxisFlags_AutoFit", + "ImPlot3DAxisFlags_Invert", + "ImPlot3DAxisFlags_PanStretch", + "ImPlot3DAxisFlags_Lock", + "ImPlot3DAxisFlags_NoDecorations" + ], + enum_header = "implot3d.h" + } + +imPlot3DLineFlags_ :: EnumType +imPlot3DLineFlags_ = + EnumType + { enum_name = "ImPlot3DLineFlags_", + enum_cases = + [ "ImPlot3DLineFlags_None", + "ImPlot3DLineFlags_NoLegend", + "ImPlot3DLineFlags_NoFit", + "ImPlot3DLineFlags_Segments", + "ImPlot3DLineFlags_Loop", + "ImPlot3DLineFlags_SkipNaN" + ], + enum_header = "implot3d.h" + } + +imPlot3DSurfaceFlags_ :: EnumType +imPlot3DSurfaceFlags_ = + EnumType + { enum_name = "ImPlot3DSurfaceFlags_", + enum_cases = + [ "ImPlot3DSurfaceFlags_None", + "ImPlot3DSurfaceFlags_NoLegend", + "ImPlot3DSurfaceFlags_NoFit", + "ImPlot3DSurfaceFlags_NoLines", + "ImPlot3DSurfaceFlags_NoFill", + "ImPlot3DSurfaceFlags_NoMarkers" + ], + enum_header = "implot3d.h" + } + +classes = [] + +enums = + [ imPlot3DFlags_, + imPlot3DAxisFlags_, + imPlot3DLineFlags_, + imPlot3DSurfaceFlags_ + ] + +toplevelfunctions :: [TopLevel] +toplevelfunctions = + [ TLOrdinary (TopLevelFunction FFIUnsafe void_ "CreateContext" [] (Just "createContext")), + TLOrdinary (TopLevelFunction FFIUnsafe void_ "ShowDemoWindow" [star CTBool "p_open"] (Just "showDemoWindow")), + TLOrdinary (TopLevelFunction FFIUnsafe bool_ "BeginPlot" [cstring "title_id", cppclassref imVec2 "size", int "flags"] (Just "beginPlot3D")), + TLOrdinary (TopLevelFunction FFIUnsafe void_ "EndPlot" [] (Just "EndPlot3D")), + TLOrdinary (TopLevelFunction FFIUnsafe void_ "SetupAxes" [cstring "x_label", cstring "y_label", cstring "z_label", int "x_flags", int "y_flags", int "z_flags"] (Just "setupAxes3D")), + TLTemplate + ( TopLevelTemplateFunction + { topleveltfunc_safety = FFIUnsafe, + topleveltfunc_params = ["t1"], + topleveltfunc_ret = void_, + topleveltfunc_name = "plotLine3D", + topleveltfunc_oname = "ImPlot3D::PlotLine", + topleveltfunc_args = + [ cstring "label_id", + Arg (TemplateParamPointer "t1") "xs", + Arg (TemplateParamPointer "t1") "ys", + Arg (TemplateParamPointer "t1") "zs", + int "count", + int "flags", + int "offset", + int "stride" + ] + } + ), + TLTemplate + ( TopLevelTemplateFunction + { topleveltfunc_safety = FFIUnsafe, + topleveltfunc_params = ["t1"], + topleveltfunc_ret = void_, + topleveltfunc_name = "plotSurface", + topleveltfunc_oname = "ImPlot3D::PlotSurface", + topleveltfunc_args = + [ cstring "label_id", + Arg (TemplateParamPointer "t1") "xs", + Arg (TemplateParamPointer "t1") "ys", + Arg (TemplateParamPointer "t1") "zs", + int "x_count", + int "y_count", + double "scale_min", + double "scale_max", + int "flags", + int "offset", + int "stride" + ] + } + ) + ] + +templates = [] + +headers = + [ ( MU_TopLevel, + ModuleUnitImports + { muimports_namespaces = ["ImPlot3D"], + muimports_headers = + [ "implot3d.h" + ] + } + ) + ] + +extraLib = [] + +extraDep = [] + +-- +-- +-- + +data CLIMode + = Gen (Maybe FilePath) + | DepGraph (Maybe FilePath) + +genMode :: OA.Mod OA.CommandFields CLIMode +genMode = + OA.command "gen" $ + OA.info + ( Gen + <$> OA.optional + (OA.strOption (OA.long "template" <> OA.short 't' <> OA.help "template directory")) + ) + (OA.progDesc "Generate source code") + +depGraphMode :: OA.Mod OA.CommandFields CLIMode +depGraphMode = + OA.command "depgraph" $ + OA.info + ( DepGraph + <$> OA.optional + (OA.strOption (OA.long "dotfile" <> OA.short 'f' <> OA.help "output dot file")) + ) + (OA.progDesc "Generate dependency graph") + +optsParser :: OA.ParserInfo CLIMode +optsParser = + OA.info + (OA.subparser (genMode <> depGraphMode) OA.<**> OA.helper) + OA.fullDesc + +main :: IO () +main = do + mode <- OA.execParser optsParser + case mode of + Gen mtmplDir -> do + let tmplDir = fromMaybe "../template" mtmplDir + cwd <- getCurrentDirectory + let fficfg = + FFICXXConfig + { fficxxconfig_workingDir = cwd "tmp" "working", + fficxxconfig_installBaseDir = cwd "implot3d", + fficxxconfig_staticFileDir = tmplDir + } + sbcfg = + SimpleBuilderConfig + { sbcTopModule = "ImPlot3D", + sbcModUnitMap = ModuleUnitMap (HM.fromList headers), + sbcCabal = cabal, + sbcClasses = classes, + sbcEnums = enums, + sbcTopLevels = toplevelfunctions, + sbcTemplates = templates, + sbcExtraLibs = extraLib, + sbcCxxOpts = ["-std=c++17"], + sbcExtraDeps = extraDep, + sbcStaticFiles = ["LICENSE"] + } + simpleBuilder fficfg sbcfg + DepGraph mdotFile -> do + let allclasses = fmap Right classes <> fmap (Left . tcihTClass) templates + drawAction h = do + hPutStrLn h $ + drawDepGraph allclasses toplevelfunctions + case mdotFile of + Nothing -> drawAction stdout + Just dotFile -> withFile dotFile WriteMode drawAction diff --git a/nix/implot3d/default.nix b/nix/implot3d/default.nix new file mode 100644 index 0000000..99565f3 --- /dev/null +++ b/nix/implot3d/default.nix @@ -0,0 +1,82 @@ +{ + stdenv, + lib, + fetchFromGitHub, + pkg-config, + frameworks, + glfw, + imgui, + implot, + libGL ? null, +}: +stdenv.mkDerivation rec { + pname = "implot3d"; + version = "0.3"; + + src = fetchFromGitHub { + owner = "wavewave"; + repo = "implot3d"; + #rev = "v${version}"; + rev = "7b0606a8d949d4997f28c2b376c35fbbecedda46"; + sha256 = "sha256-44BZhLGBheGPW1/m4Rrk9H7OJ1oKbP9IXivVgxuqUVE="; + }; + + nativeBuildInputs = [pkg-config]; + + buildInputs = + [ + glfw + imgui + implot + ] + ++ ( + if stdenv.isDarwin + then [ + frameworks.Cocoa + frameworks.Metal + frameworks.MetalKit + ] + else [libGL] + ); + + buildPhase = + if stdenv.isDarwin + then '' + $CXX -std=c++11 -I. -I./backends -c implot3d.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_demo.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_items.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_meshes.cpp `pkg-config --cflags libimgui libimplot` + $CXX -dynamiclib -undefined suppress -flat_namespace -install_name $out/lib/libimplot3d.dylib -o libimplot3d.dylib implot3d.o implot3d_demo.o implot3d_items.o implot3d_meshes.o + '' + else '' + $CXX -std=c++11 -I. -I./backends -c implot3d.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_demo.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_items.cpp `pkg-config --cflags libimgui libimplot` + $CXX -std=c++11 -I. -I./backends -c implot3d_meshes.cpp `pkg-config --cflags libimgui libimplot` + $CXX -shared -o libimplot3d.so implot3d.o implot3d_demo.o implot3d_items.o implot3d_meshes.o + ''; + + installPhase = '' + mkdir -p $out/include/implot3d + mkdir -p $out/lib + cp *.h $out/include/implot3d + cp libimplot3d.* $out/lib + + mkdir -p $out/lib/pkgconfig + cat >> $out/lib/pkgconfig/libimplot3d.pc << EOF + Name: libimplot3d + Description: Dear ImPlot3d + Version: ${version} + Libs: -L$out/lib -limplot3d + Cflags: -I$out/include/implot3d + EOF + ''; + + meta = with lib; { + description = "Implot3d"; + homepage = "https://github.com/brenocq/implot3d"; + license = licenses.mit; + maintainers = with maintainers; [ianwookim]; + platforms = platforms.all; + }; +} diff --git a/workspace/build.sh b/workspace/build.sh index bf049ad..7f3a4a6 100755 --- a/workspace/build.sh +++ b/workspace/build.sh @@ -1,14 +1,19 @@ #!/bin/sh ghc ../imgui-gen/Gen.hs -package optparse-applicative && \ - ../imgui-gen/Gen gen --template=../imgui-gen/template && \ - cabal build imgui && \ - ghc ../implot-gen/Gen.hs -package optparse-applicative && \ - ../implot-gen/Gen gen --template=../implot-gen/template && \ - cabal build implot && \ - cabal exec -- ghc demo-imgui-builtin.hs -framework OpenGL -lglfw -lGL -package extra && \ - cabal exec -- ghc demo-implot-builtin.hs -framework OpenGL -lglfw -lGL -package extra && \ - ./demo-imgui-builtin && \ - ./demo-implot-builtin && \ - cabal run draw-demo && \ - cabal run plot-demo +../imgui-gen/Gen gen --template=../imgui-gen/template && \ +ghc ../implot-gen/Gen.hs -package optparse-applicative && \ +../implot-gen/Gen gen --template=../implot-gen/template && \ +ghc ../implot3d-gen/Gen.hs -package optparse-applicative && \ +../implot3d-gen/Gen gen --template=../implot3d-gen/template && \ +cabal build imgui && \ +cabal build implot && \ +cabal build implot3d && \ +cabal run draw-demo && \ +cabal run plot-demo && \ +cabal run plot3d-demo + +#cabal exec -- ghc demo-imgui-builtin.hs -framework OpenGL -lglfw -lGL -package extra && \ +#cabal exec -- ghc demo-implot-builtin.hs -framework OpenGL -lglfw -lGL -package extra && \ +#./demo-imgui-builtin && \ +#./demo-implot-builtin && \ diff --git a/workspace/cabal.project b/workspace/cabal.project index 863ce93..a0d568c 100644 --- a/workspace/cabal.project +++ b/workspace/cabal.project @@ -1,3 +1,7 @@ packages: + ./imgui + ./implot + ./implot3d ../examples/plot-demo ../examples/draw-demo + ../examples/plot3d-demo