Hi all,
i'm the person who's currently working on the D binding for SFML. The objective of this binding, is to preserve the SFML api but, C++ -> D is only possible on the D2 compiler, and D2 is, ATM, at experimental stage (and constantly changed ... you said "transitive const" =p). So, given the fact that D already has a C interface, i think it's the best option to bind through the C SFML interface instead of the C++ one. C use in D is easy and lot of other lib use it, the C++ way is too limited (maybe when D2 switch to stable release).
For the technics, at the beginning, i've used the Derelict way (aka dynamically load .dll or .so and instanciate function pointer) i.e. (from the DerelictSDL trunk) :
extern(C)
{
typedef int function(Uint32) pfSDL_Init;
typedef int function(Uint32) pfSDL_InitSubSystem;
typedef int function(Uint32) pfSDL_QuitSubSystem;
typedef int function(Uint32) pfSDL_WasInit;
typedef void function() pfSDL_Quit;
pfSDL_Init SDL_Init;
pfSDL_InitSubSystem SDL_InitSubSystem;
pfSDL_QuitSubSystem SDL_QuitSubSystem;
pfSDL_WasInit SDL_WasInit;
pfSDL_Quit SDL_Quit;
}
bindFunc(SDL_Init)("SDL_Init", lib);
bindFunc(SDL_InitSubSystem)("SDL_InitSubSystem", lib);
bindFunc(SDL_QuitSubSystem)("SDL_QuitSubSystem", lib);
bindFunc(SDL_WasInit)("SDL_WasInit", lib);
bindFunc(SDL_Quit)("SDL_Quit", lib);
GenericLoader DerelictSDL;
static this()
{
DerelictSDL.setup(
"sdl.dll",
"libSDL.so, libSDL.so.0, libSDL-1.2.so, libSDL-1.2.so.0",
"../Frameworks/SDL.framework/SDL, /Library/Frameworks/SDL.framework/SDL, /System/Library/Frameworks/SDL.framework/SDL",
&load
);
}
But i have some problems with this design. After some reading, I understand that OptLink (the Digital Mars D linker for
non-D folks =p) can link import lib of DLL but only if they are in OMF format (cl or lib, for visual, generate in COFF format). I tried to regenerate import lib from the C SFML dll in the correct format (with implib, a tool from the DMC utility suite), and it worked ! Now, the D lib looks like (from PostFX external definition) :
extern(C)
{
struct sfPostFX {};
sfPostFX* sfPostFX_CreateFromFile(char*);
sfPostFX* sfPostFX_CreateFromMemory(char*);
void sfPostFX_Destroy(sfPostFX*);
void sfPostFX_SetParameter1(sfPostFX*, char*, float);
void sfPostFX_SetParameter2(sfPostFX*, char*, float, float);
void sfPostFX_SetParameter3(sfPostFX*, char*, float, float, float);
void sfPostFX_SetParameter4(sfPostFX*, char*, float, float, float, float);
void sfPostFX_SetTexture(sfPostFX*, char*, sfImage*);
bool sfPostFX_CanUsePostFX();
}
No need of function pointers or static loader initialization, just link against the correct import lib. I keep working on the Derelict way because i can only test under Windows system and i don't know if the
import lib trick is possible with GDC.
For the current status, all packages are binded, except some system classes (like Thread or Mutex which use the phobos or tangos internal ancapsulated in the SFML api) because thread created outside D are not GC scanned (so the Terminate method become unusable because tango or phobos thread cannot be terminated, this is not a bad news, terminate a thread is not a good practices IMO =) ), and i'm currently testing it. For the openGL headers, i have adaptated headers from the
OpenGL Binding project.
As I said to Laurent earlier, the next step is 1) solidify the code (writing some unittest, clean the code, and some optimizing stuffs) 2) finish adapting the documentation from doxygen comments to ddoc one 3) rewrite some samples. I hope i can release a first version (tested for windows) this weekend or early during the next week.
It's
screenshot time ! =p (you can't see, but quad move with arrow keys =) ).
The code :
module test;
import sfml.window.all;
import sfml.system.all;
import sfml.graphics.all;
import sfml.GL.gl;
import sfml.GL.glu;
GLfloat rx = 0.f;
GLfloat ry = 0.f;
GLfloat xspeed = 0.f;
GLfloat yspeed = 0.f;
Input i;
void main()
{
RenderWindow w = new RenderWindow(VideoMode(1024, 768, 32), "Test");
i = w.GetInput();
String hello = new String("Duke, say hello to D folks !"w, "comic.ttf", 30.f);
hello.SetColor(Color.White);
hello.SetPosition(50.f, 50.f);
Image img = new Image();
if (!img.LoadFromFile("DukeNukem-3d.tga"))
assert(0, "Error");
img.CreateMaskFromColor(Color.White);
Sprite sprite = new Sprite();
sprite.SetImage(img);
sprite.SetSubRect(new Rect!(int)(0, 0, 42, 85));
sprite.SetPosition(hello.GetRect().GetWidth() + hello.GetRect().GetLeft() + 30.f, 50.f);
glClearDepth(1.f);
glClearColor(0.f, 0.f, 0.f, 0.f);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, 1.f, 1.f, 500.f);
bool cont = true;
while (cont)
{
Event evt;
while (w.GetEvent(evt))
{
switch (evt.Type)
{
case Event.EventType.Closed :
cont = false;
break;
case Event.EventType.Resized :
glViewport(0, 0, evt.Size.Width, evt.Size.Height);
break;
case Event.EventType.KeyPressed :
if (evt.Key.Code == KeyCode.Escape)
cont = false;
HandleKey(i);
break;
default :
break;
}
}
w.SetCurrent();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, -200.f);
glRotatef(rx, 1.f, 0.f, 0.f);
glRotatef(ry, 0.f, 1.f, 0.f);
glBegin(GL_QUADS);
glColor3f(0.f, 1.f, 0.f);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, -50.f);
glVertex3f( 50.f, -50.f, -50.f);
glColor3f(0.f, 1.f, 1.f);
glVertex3f(-50.f, -50.f, 50.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f( 50.f, 50.f, 50.f);
glVertex3f( 50.f, -50.f, 50.f);
glColor3f(1.f, 1.f, 0.f);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f(-50.f, -50.f, 50.f);
glColor3f(0.f, 0.5f, 0.f);
glVertex3f(50.f, -50.f, -50.f);
glVertex3f(50.f, 50.f, -50.f);
glVertex3f(50.f, 50.f, 50.f);
glVertex3f(50.f, -50.f, 50.f);
glColor3f(1.f, 0.f, 0.f);
glVertex3f(-50.f, -50.f, 50.f);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f( 50.f, -50.f, -50.f);
glVertex3f( 50.f, -50.f, 50.f);
glColor3f(0.f, 0.f, 1.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, 50.f);
glEnd();
w.Draw(hello);
w.Draw(sprite);
rx += xspeed;
ry += yspeed;
w.Display();
}
}
void HandleKey(Input i)
{
if (i.IsKeyDown(KeyCode.Up))
{
xspeed -= 0.1f;
}
if (i.IsKeyDown(KeyCode.Down))
{
xspeed += 0.1f;
}
if (i.IsKeyDown(KeyCode.Left))
{
yspeed -= 0.1f;
}
if (i.IsKeyDown(KeyCode.Right))
{
yspeed += 0.1f;
}
}
generated with :
dmd program.d program.def libd/sfmlsystem.lib libd/sfmlwindow.lib libd/sfmlgraphics.lib lib/dsfml-system.lib lib/dsfml-window.lib lib/dsfml-graphics.lib lib/opengl32d.lib lib/glu32d.lib tango-user-dmd.lib -g -debug -w -v
If you have any question. =)[/code]