Support modular graphics engines
z0w0 opened this issue · 10 comments
The plan is to eventually have an OpenGL backed 2d renderer. But I think we should just make some sort of graphics system module out of the box. This could be extended somehow so that we could have a 2d and 3d renderer. They would all return Element
in the long run, or perhaps a new abstract Screen
type. This would allow us to have both a 2d cairo engine and 2d OpenGL engine in the one release, with the OpenGL one marked as experimental.
I had a play with making a Gtk back-end and what I did was replace the engine datatype with:
{-| A data structure describing the current engine state. -}
data Engine = EngineSDL { windowSDL :: SDL.Window
, renderer :: SDL.Renderer,
, cache :: Map.Map FilePath Cairo.Surface
}
| EngineGtk { windowGtk :: Gtk.Window
, drawWindowGtk :: Gtk.DrawWindow
, drawingAreaGtk :: Gtk.DrawingArea
, cache :: Map.Map FilePath Cairo.Surface
}
The problem with that is it's not modular. We want it so the backends are separate from Helm (basically).
Also, this issue was mainly about the rendering engines. I guess we could have two components for Helm to run: the window engine (SDL vs GTK) and the rendering engine (3D vs 2D)? I'm not sure. Sounds messy.
Yes, I guess what I did worked ok because it was still Cairo. I was thinking about it a bit more and a cleaner way to do all of this would be to have seperate modules. What would you say to letting the user choose by
import FRP.Helm.SDLCairo
and could then switch to
import FRP.Helm.GtkCairo
or
import FRP.Helm.SDLOpenGL
I would prefer FRP.Helm.{SDL,GTK}.{Cairo,OpenGL}
Yes, that would be nicer. Not sure quite how it would work but it's worth a shot.
Just giving my $0.2 here. You could try to abstract an "engine" into a type class Engine
. Inside this class you would define the interface to handle the engine (what are the main operations that are performed over an engine object; for example get the window position or whatnot) and then create various engines that implement such type class.
That seems the most idiomatic way. You keep it also open for users to extend.
Yep, that's definitely along the lines of what I'd expect.
How would functions like isDown
find the correct overload though?
Problem with using a record is that every Helm call becomes indirect. You don't want that for performance: use a type class.
Helm 1.0.0 added modular engines. Feel free to open a new issue if you don't think it covers it well enough.