3

I am new to Haskell and I am building a chess game using OpenGL (using Graphics.UI.GLUT) for UI. I am trying to render PNG images for chess pieces.

I read that images can be converted to TextureObject and then rendered, but could not find any helpful resources to know how to do it.

This is what my code looks like for generating the chess board

drawSquare :: BoardSquare -> IO ()
drawSquare ((x,y,z),(r,g,b)) = preservingMatrix $ do
    color $ Color3 r g b
    translate $ Vector3 x y z
    drawCube -- this will draw a square of appropriate size

-- Display Callback
display :: IORef GameState -> DisplayCallback
display gameState = do
    gstate <- get gameState
    clear [ColorBuffer]
    forM_ (getBoardPoints gstate) $ drawSquare -- drawing all 64 squares here
    flush

Can anyone help me render PNG image at any given x and y coordinates of the window with given file path?

codesome
  • 81
  • 5
  • 1
    Maybe not specific to your question, but did you have a look at the nehe tutorials (Haskell port: http://hackage.haskell.org/package/nehe-tuts, original in C can be found at: http://nehe.gamedev.net/)? I don't know, but maybe this helps... – MichaelO Apr 07 '17 at 12:36
  • Do you want it to be in OpenGL specifically, or do you just want 2D graphics on the screen? If the latter, SDL2 is a very simple alternative and there's good haskell bindings. – Ivan Perez Apr 08 '17 at 07:23
  • The total chess board with keyboards actions and gameplay is ready in OpenGL. Anything that would go with OpenGL to render PNG image should be fine, need not be in OpenGL. – codesome Apr 08 '17 at 13:33

2 Answers2

2

Suggestion: Since you are new to Haskell, instead of diving straight into raw OpenGL for your chess game, have you looked at libraries that could help you make OpenGL easier? I would recommend gloss and it looks like gloss-game has a helper function to load a .png file into memory ready to be used for your game. Good luck! :-)

basile-henry
  • 1,337
  • 7
  • 9
  • 1
    Yes, gloss would have been simpler. But I stumbled upon OpenGL first and as the total game is ready with it except the image rendering part, I cannot migrate to it now (or more like, I dont want to). Is it possible to use that helper function with OpenGL? – codesome Apr 08 '17 at 13:37
  • 1
    I am not really familiar with the OpenGL Haskell bindings myself, which is why I recommended something like gloss. After a bit of googling, it looks like the function you need to load a 2D texture is: `texImage2D`. It is very low level (you have to pass a pointer to where the image is held in memory). [Here](https://gist.github.com/danbst/470f7e23a14cab4e6e3e) is a gist I found online to load a texture from a `.bmp`. [JuicyPixels](https://hackage.haskell.org/package/JuicyPixels) might be able to help you get a bitmap from a `.png` file. Good luck! :-) – basile-henry Apr 08 '17 at 22:17
  • Thank you for the resources :) Hope this will help someone else too. Anyway, we decided to draw the figures by giving vertices instead, where we wont face any issues with flickering of screen. – codesome Apr 09 '17 at 15:08
2

Here is the way I use.

First, use the package gl-capture. It is old but it works well. It generates ppm images.

import           Graphics.Rendering.OpenGL.Capture (capturePPM)

Do you need help to apply the package ? You need a keyboard callback. I can help if necessary, please just ask.

Now, once you have a ppm image, you have two options: convert it with ImageMagick, or use a Haskell package to convert it. There is a good one: it is called hip. Here is the module I use:

module Utils.ConvertPPM
  where
import           Control.Monad    (when)
import           Graphics.Image
import           System.Directory (removeFile)

convert :: FilePath -> FilePath -> Bool -> IO ()
convert input output remove = do
  ppm <- readImageRGBA VU input
  writeImage output ppm
  when remove $ removeFile input

Do not hesitate if you need more help.

Here is the kind of keyboard callback I use:

keyboard :: IORef GLfloat -> IORef GLfloat -> IORef GLfloat -> IORef GLint
         -> KeyboardCallback
keyboard rot1 rot2 rot3 capture c _ =
  case c of
    'r' -> rot1 $~! subtract 1
    't' -> rot1 $~! (+1)
    'f' -> rot2 $~! subtract 1
    'g' -> rot2 $~! (+1)
    'v' -> rot3 $~! subtract 1
    'b' -> rot3 $~! (+1)
    'c' -> do
      i <- get capture
      let ppm = printf "pic%04d.ppm" i
          png = printf "pic%04d.png" i
      (>>=) capturePPM (B.writeFile ppm)
      convert ppm png True
      capture $~! (+1)
    'q' -> leaveMainLoop
    _   -> return ()

Then press 'c' to capture the image. Note that the conversion from ppm to png is slow. Especially if you intend to do some animations. For animations, I rather use ppm only and then I convert with ImageMagick.

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225