Draw simple graphics using F#
Asked Answered
I

1

6

What is the easiest way to draw simple graphics using F# ?

I want to visualize a dynamic system (a simplified sample of my use case would be a red square going from one side of the screen to the other at a speed of one pixel per frame) so I need a way to draw simple geometric shapes.
As I will update the picture on a regular basis, a mechanism to avoid flickering will probably be needed.


The standard solution appears to be System.Drawing. I put together a working solution but the code is overly complex (it seems to require System.Windows.Forms, is there no direct way to put graphics in a windows ?), not great for a simple task, which led me to think that a better tool probably exists.

Am I doing something wrong, is there a simple way to draw and update pictures with System.Drawing? Or is there a library out there that better fits my needs ?

Inundate answered 15/2, 2017 at 12:22 Comment(4)
I'm not sure I fully understand the question. How important to you is cross-platform?Do you want to create a desktop app or something in browser or it's doesn't matter?Heathen
About the second part, I think System.Drawing is platform dependent element. But most likely you can get rid of the flicker.Heathen
I just simplified my question to make it clearer. Cross platform is not required (It is for personnal use and I have both a windows and a linux) however it would be more practical. (I did manage to get rid of the flicker but the solution is still not great)Inundate
If I were you I'd probably try one of the simpler 2D graphics libs. SDL has a few .net compatible wrappers floating around and has a pretty straightforward API.Doretha
N
1

One solution is to use MonoGame. This is a mature framework for game development, but it can be used as a general purpose renderer in .NET. Many of the other solutions are either not cross-platform or low-level (think OpenGL).

This is an F# script that creates a window containing a moving red box:

#r "nuget: MonoGame.Framework.DesktopGL, 3.8.1.303"

open Microsoft.Xna.Framework
open Microsoft.Xna.Framework.Graphics

type RedBoxApp() as this =
  inherit Game()

  let graphicsManager = new GraphicsDeviceManager(this)

  let mutable spriteBatch = Unchecked.defaultof<SpriteBatch>
  let mutable pixel = Unchecked.defaultof<Texture2D>

  with
    override this.Initialize() =
      this.IsMouseVisible <- true
      this.IsFixedTimeStep <- true
      this.Window.Title <- "Red Box"

      base.Initialize()

    override this.LoadContent() =
      graphicsManager.PreferredBackBufferWidth <- 640
      graphicsManager.PreferredBackBufferHeight <- 480

      graphicsManager.ApplyChanges()

      spriteBatch <- new SpriteBatch(this.GraphicsDevice)

      pixel <- new Texture2D(this.GraphicsDevice, 1, 1)
      pixel.SetData([| Color.White |])

    override this.Draw(gameTime : GameTime) =
      this.GraphicsDevice.Clear(Color.CornflowerBlue)

      let squareLeft = 64.0 + gameTime.TotalGameTime.TotalSeconds * 60.0

      spriteBatch.Begin()
      spriteBatch.Draw(pixel, Rectangle(int squareLeft, 64, 64, 64), Color.Red)
      spriteBatch.End()

let app = new RedBoxApp()

app.Run()

As you can see, the API is quite imperative and object-orientated. However, a more declarative layer could be built on top of this.

screenshot

Nonchalance answered 30/12, 2022 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.