在 MacOS X 上的 GHCi 中工作的 Haskell 图形库

发布于 2024-11-04 14:32:43 字数 899 浏览 1 评论 0原文

是否存在满足以下要求的 Haskell 图形库或绑定到外部库:

  1. 可以从 ghci 使用,即我不必链接并重新启动程序。
  2. 适用于 MacOS X。(与 1 结合使用很棘手!)
  3. 可以制作简单的矢量图形(线条、多边形、简单的填充和描边)。
  4. 可以将位图图像放在屏幕上。示例:blit 17x12 .bmp 图像。

请包含一个最小的源代码示例或对其的引用(只是屏幕上的一个窗口,可能在里面画了一条绿线),以便我可以特别检查第 1 点和第 2 点。另外,如果这些功能请求之一更详细(例如 OpenGL + 4),请提供一份很好的参考。


PS:关于1和2,我知道enableGUI技巧并且我愿意使用它。但是,大多数库都存在无法多次运行 main 函数的问题,因此不符合资格。


编辑:为了避免浪费您的时间,这里列出了我尝试过的软件包:

  • wx - ghci 在 libstdc++ 上被阻塞
  • sdl - 重新定义main 是一个宏。仅编译时。
  • GLFW (OpenGL) - 无法运行 main 两次,关于“失败,因为它无法安装鼠标事件处理程序”。

Does there exist a Haskell graphics library or binding to an external library that fulfills the following requirements:

  1. Can be used from ghci, i.e. I don't have to link and restart the program.
  2. Works on MacOS X. (Tricky in conjunction with 1!)
  3. Can do simple vector graphics (lines, polygons, simple fills and strokes).
  4. Can put bitmap images on screen. Example: blit a 17x12 .bmp image.

?

Please include a minimal source code example or a reference to it (just a window on screen, maybe with a green line drawn inside it) so that I can check the points 1. and 2. in particular. Also, if one of these feature requests is more elaborate (for example OpenGL + 4), please include a good reference.

PS: Concerning 1 and 2, I know about the enableGUI trick and I am willing to use it. However, most libraries have the problem that you can't run the main function multiple times and hence don't qualify.

Edit: To avoid wasting your time, here a list of packages that I've tried:

  • wx - ghci chokes on libstdc++
  • sdl - redefines main to be a macro. Compile-time only.
  • GLFW (OpenGL) - Can't run main twice, something about "failing because it can't install mouse event handler".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一指流沙 2024-11-11 14:32:47

您是否看到过引用的 GLFW http://plucky.cs.yale.edu/soe/软件1.htm

Have you seen the GLFW as referenced http://plucky.cs.yale.edu/soe/software1.htm

孤君无依 2024-11-11 14:32:47

有关 Haskell+GUI+OpenGL 的更多信息可在此讨论中找到:
http://www.haskell.org/pipermail/haskell-cafe /2011年5月/091991.html

More information on Haskell+GUI+OpenGL is available in this discussion:
http://www.haskell.org/pipermail/haskell-cafe/2011-May/091991.html

Spring初心 2024-11-11 14:32:46

编辑:实际上,我不再确定。几个版本之后,GLFW 似乎不再适用于 OS X 上的 GHCi。

事实证明,GLFW+OpenGL 满足了所有四个要求!

  1. 您需要使用 ghci -framework Carbon 调用 ghci。
  2. 您需要 EnableGUI.hs 文件,您可以通过 此处。请注意,您无法将其直接加载到 GHCi 中,您必须首先对其进行编译。
  3. OpenGL 有一个 2D 投影模式,您可以在其中绘制直线和多边形。
  4. 位图可以作为纹理加载并放置在多边形上。

这是一个将位图放到屏幕上的小示例。位图有一些限制:其尺寸必须是 2 的幂(此处为 256)并且必须是 .tga 文件(此处为 "Bitmap.tga") 。但由于支持透明度,所以这不是什么大问题。

您应该能够毫无问题地多次调用 main 。关键点是您不应该调用GLFW.terminate

import Graphics.Rendering.OpenGL as GL
import qualified Graphics.UI.GLFW as GLFW
import Graphics.Rendering.OpenGL (($=))

import Control.Monad
import EnableGUI

main = do
    enableGUI
    GLFW.initialize
    -- open window
    GLFW.openWindow (GL.Size 400 400) [GLFW.DisplayAlphaBits 8] GLFW.Window
    GLFW.windowTitle $= "Bitmap Test"

    -- enable alpha channel
    GL.blend         $= GL.Enabled
    GL.blendFunc     $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
    -- set the color to clear background
    GL.clearColor    $= GL.Color4 0.8 0.8 0.8 0

    -- set 2D orthogonal view inside windowSizeCallback because
    -- any change to the Window size should result in different
    -- OpenGL Viewport.
    GLFW.windowSizeCallback $= \ size@(GL.Size w h) ->
      do
        GL.viewport   $= (GL.Position 0 0, size)
        GL.matrixMode $= GL.Projection
        GL.loadIdentity
        GL.ortho2D 0 (realToFrac w) (realToFrac h) 0

    render <- initialize
    loop render

    GLFW.closeWindow

loop render = do
    -- draw the entire screen
    render
    -- swap buffer
    GLFW.swapBuffers
    -- check whether ESC is pressed for termination
    p <- GLFW.getKey GLFW.ESC
    unless (p == GLFW.Press) $ do
        -- sleep for 1ms to yield CPU to other applications
        GLFW.sleep 0.001
        -- only continue when the window is not closed
        windowOpenStatus <- GLFW.getParam GLFW.Opened
        unless (windowOpenStatus == False) $
            loop render

-- rendering
initialize = do
    -- load texture from file
    GL.texture GL.Texture2D $= Enabled
    [textureName] <- GL.genObjectNames 1
    GL.textureBinding GL.Texture2D $= Just textureName
    GL.textureFilter  GL.Texture2D $= ((GL.Nearest, Nothing), GL.Nearest)
    GLFW.loadTexture2D "Bitmap.tga" []

    return $ do
        GL.clear [GL.ColorBuffer]
        GL.renderPrimitive GL.Quads $ do
            GL.texCoord $ texCoord2 0 0
            GL.vertex   $ vertex3 (0) 256 0
            GL.texCoord $ texCoord2 0 1
            GL.vertex   $ vertex3 (0) (0) 0
            GL.texCoord $ texCoord2 1 1
            GL.vertex   $ vertex3 256 (0) 0
            GL.texCoord $ texCoord2 1 0
            GL.vertex   $ vertex3 256 256 0

-- type signatures to avoid ambiguity
vertex3 :: GLfloat -> GLfloat -> GLfloat -> GL.Vertex3 GLfloat
vertex3 = GL.Vertex3

texCoord2 :: GLfloat -> GLfloat -> GL.TexCoord2 GLfloat
texCoord2 = GL.TexCoord2

color3 :: GLfloat -> GLfloat -> GLfloat -> GL.Color3 GLfloat
color3 = GL.Color3

这是一个示例位图(您需要将其转换为 .tga)。

示例位图

EDIT: Actually, I'm no longer sure. Several versions later, it seems that GLFW no longer works in GHCi on OS X.

It turns out that GLFW+OpenGL fulfills all four requirements!

  1. You need to invoke ghci with ghci -framework Carbon.
  2. You need the EnableGUI.hs file, which you can get here. Note that you can't load it right into GHCi, you have to comiple it, first.
  3. OpenGL has a 2D projection mode where you can draw lines and polygons.
  4. Bitmaps can be loaded as textures and put on polygons.

Here is a small example that puts a bitmap onto the screen. There are some restrictions on the bitmap: its dimensions must be a power of two (here 256) and it must be a .tga file (here "Bitmap.tga"). But since transparency is supported, this is not much of a problem.

You should be able to call main multiple times without problem. The key point is that you should not call GLFW.terminate.

import Graphics.Rendering.OpenGL as GL
import qualified Graphics.UI.GLFW as GLFW
import Graphics.Rendering.OpenGL (($=))

import Control.Monad
import EnableGUI

main = do
    enableGUI
    GLFW.initialize
    -- open window
    GLFW.openWindow (GL.Size 400 400) [GLFW.DisplayAlphaBits 8] GLFW.Window
    GLFW.windowTitle $= "Bitmap Test"

    -- enable alpha channel
    GL.blend         $= GL.Enabled
    GL.blendFunc     $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
    -- set the color to clear background
    GL.clearColor    $= GL.Color4 0.8 0.8 0.8 0

    -- set 2D orthogonal view inside windowSizeCallback because
    -- any change to the Window size should result in different
    -- OpenGL Viewport.
    GLFW.windowSizeCallback $= \ size@(GL.Size w h) ->
      do
        GL.viewport   $= (GL.Position 0 0, size)
        GL.matrixMode $= GL.Projection
        GL.loadIdentity
        GL.ortho2D 0 (realToFrac w) (realToFrac h) 0

    render <- initialize
    loop render

    GLFW.closeWindow

loop render = do
    -- draw the entire screen
    render
    -- swap buffer
    GLFW.swapBuffers
    -- check whether ESC is pressed for termination
    p <- GLFW.getKey GLFW.ESC
    unless (p == GLFW.Press) $ do
        -- sleep for 1ms to yield CPU to other applications
        GLFW.sleep 0.001
        -- only continue when the window is not closed
        windowOpenStatus <- GLFW.getParam GLFW.Opened
        unless (windowOpenStatus == False) $
            loop render

-- rendering
initialize = do
    -- load texture from file
    GL.texture GL.Texture2D $= Enabled
    [textureName] <- GL.genObjectNames 1
    GL.textureBinding GL.Texture2D $= Just textureName
    GL.textureFilter  GL.Texture2D $= ((GL.Nearest, Nothing), GL.Nearest)
    GLFW.loadTexture2D "Bitmap.tga" []

    return $ do
        GL.clear [GL.ColorBuffer]
        GL.renderPrimitive GL.Quads $ do
            GL.texCoord $ texCoord2 0 0
            GL.vertex   $ vertex3 (0) 256 0
            GL.texCoord $ texCoord2 0 1
            GL.vertex   $ vertex3 (0) (0) 0
            GL.texCoord $ texCoord2 1 1
            GL.vertex   $ vertex3 256 (0) 0
            GL.texCoord $ texCoord2 1 0
            GL.vertex   $ vertex3 256 256 0

-- type signatures to avoid ambiguity
vertex3 :: GLfloat -> GLfloat -> GLfloat -> GL.Vertex3 GLfloat
vertex3 = GL.Vertex3

texCoord2 :: GLfloat -> GLfloat -> GL.TexCoord2 GLfloat
texCoord2 = GL.TexCoord2

color3 :: GLfloat -> GLfloat -> GLfloat -> GL.Color3 GLfloat
color3 = GL.Color3

Here an example bitmap (which you need to convert to .tga).

Sample bitmap

孤千羽 2024-11-11 14:32:46

如果您使用 X11 版本的 gtk2 框架,Gtk2Hs 库可以满足所有要求。

关于要求:

  1. 使用X11可以避免很多问题。
  2. 通过 MacPorts 安装 gtk2 并使用 +x11 选项(默认)。 (也就是说,我过去在安装 gtk2 时遇到了很多问题,但这一次似乎有效。)
  3. 如果 GTK+ 不能做到这一点,我会感到惊讶。
  4. 同上。

这是一个最小的例子

import Graphics.UI.Gtk

hello :: (ButtonClass o) => o -> IO ()
hello b = set b [buttonLabel := "Hello World"]

main :: IO ()
main = do
    initGUI
    window <- windowNew
    button <- buttonNew
    set window [windowDefaultWidth := 200, windowDefaultHeight := 200,
              containerChild := button, containerBorderWidth := 10]
    onClicked button (hello button)
    onDestroy window mainQuit
    widgetShowAll window
    mainGUI

The Gtk2Hs library fulfills all the requirements if you use the X11 version of the gtk2 framework.

Concerning the requirements:

  1. Using X11 avoids many problems.
  2. Install gtk2 via MacPorts and use the +x11 option (default). (That said, I've had numerous problems installing gtk2 in the past, but this time it seemed to work.)
  3. I would be surprised if GTK+ can't do that.
  4. Ditto.

Here a minimal example

import Graphics.UI.Gtk

hello :: (ButtonClass o) => o -> IO ()
hello b = set b [buttonLabel := "Hello World"]

main :: IO ()
main = do
    initGUI
    window <- windowNew
    button <- buttonNew
    set window [windowDefaultWidth := 200, windowDefaultHeight := 200,
              containerChild := button, containerBorderWidth := 10]
    onClicked button (hello button)
    onDestroy window mainQuit
    widgetShowAll window
    mainGUI
我喜欢麦丽素 2024-11-11 14:32:46

截至 2014 年初,我无法在 Mac OS X 中使用 @heinrich-apfelmus 答案。这个 GLFW-b 示例 (链接)但是有效。

因此,请确保您拥有:

$ cabal install glfw-b

并且,如果您尝试了 Apfelmus 的答案,您可能需要

$ ghc-pkg list
$ ghc-pkg unregister GLFW-x.x.x.x

提供 Graphics.UI.GLFW,并且您将得到一个“不明确的模块名称 'Graphics.UI.GLFW” ’”来自 ghc。然后我尝试了上面的示例程序并且它有效(Mac OS X,10.9,Mavericks)

As of early 2014, I wasn't able to use @heinrich-apfelmus answer in Mac OS X. This GLFW-b example (link) however worked.

So, ensure you have:

$ cabal install glfw-b

and, if you tried Apfelmus' answer, you may need to

$ ghc-pkg list
$ ghc-pkg unregister GLFW-x.x.x.x

as both provide Graphics.UI.GLFW, and you will get an "Ambiguous module name 'Graphics.UI.GLFW'" from ghc. Then I just tried the sample program above and it worked (Mac OS X, 10.9, Mavericks)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文