Skip to content

Instantly share code, notes, and snippets.

@nadako
Created June 24, 2015 19:36
Show Gist options
  • Star 32 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nadako/c8aec20c2a7751348f91 to your computer and use it in GitHub Desktop.
Save nadako/c8aec20c2a7751348f91 to your computer and use it in GitHub Desktop.
Haxe + SDL = native love \o/
class Main {
static function main() {
Sdl.init(Sdl.INIT_EVERYTHING);
var win = Sdl.createWindow("Hello", 100, 100, 800, 600, Sdl.WINDOW_OPENGL);
var ren = Sdl.createRenderer(win, -1, Sdl.RENDERER_ACCELERATED);
var bmp = Sdl.loadBMP("test.bmp");
var tex = Sdl.createTextureFromSurface(ren, bmp);
Sdl.freeSurface(bmp);
for (i in 0...3) {
Sdl.renderClear(ren);
Sdl.renderCopy(ren, tex, cast 0, cast 0);
Sdl.renderPresent(ren);
Sdl.delay(1000);
}
}
}
import cpp.ConstCharStar;
@:include("./SDLSupport.h")
@:buildXml('<target id="haxe"><lib name="../SDL2-2.0.3/lib/x86/SDL2.lib"/></target>')
extern class Sdl {
@:native("SDL_INIT_EVERYTHING")
static var INIT_EVERYTHING(default,null):InitFlag;
inline static var WINDOW_NONE:CreateWindowFlag = cast 0;
@:native("SDL_WINDOW_OPENGL")
static var WINDOW_OPENGL(default,null):CreateWindowFlag;
inline static var RENDERER_NONE:CreateRendererFlag = cast 0;
@:native("SDL_RENDERER_ACCELERATED")
static var RENDERER_ACCELERATED(default,null):CreateRendererFlag;
@:native("SDL_Init")
static function init(flags:InitFlag):Int;
@:native("SDL_CreateWindow")
static function createWindow(title:ConstCharStar, x:Int, y:Int, w:Int, h:Int, flags:CreateWindowFlag):WindowPointer;
@:native("SDL_CreateRenderer")
static function createRenderer(win:WindowPointer, index:Int, flags:CreateRendererFlag):RendererPointer;
@:native("SDL_LoadBMP")
static function loadBMP(file:ConstCharStar):SurfacePointer;
@:native("SDL_CreateTextureFromSurface")
static function createTextureFromSurface(renderer:RendererPointer, surface:SurfacePointer):TexturePointer;
@:native("SDL_FreeSurface")
static function freeSurface(surface:SurfacePointer):Void;
@:native("SDL_RenderClear")
static function renderClear(renderer:RendererPointer):Int;
@:native("SDL_RenderCopy")
static function renderCopy(renderer:RendererPointer, texture:TexturePointer, srcRect:RectPointer, dstRect:RectPointer):Int;
@:native("SDL_RenderPresent")
static function renderPresent(renderer:RendererPointer):Void;
@:native("SDL_Delay")
static function delay(ms:cpp.UInt32):Void;
}
abstract InitFlag(cpp.UInt32) {
@:op(A|B) static function _(a:InitFlag, b:InitFlag):InitFlag;
}
abstract CreateWindowFlag(cpp.UInt32) {
@:op(A|B) static function _(a:CreateWindowFlag, b:CreateWindowFlag):WindowPointer;
}
abstract CreateRendererFlag(cpp.UInt32) {
@:op(A|B) static function _(a:CreateRendererFlag, b:CreateRendererFlag):CreateRendererFlag;
}
@:native("::cpp::Reference<SDL_Window>")
extern class WindowPointer {}
@:native("::cpp::Reference<SDL_Renderer>")
extern class RendererPointer {}
@:native("::cpp::Reference<SDL_Surface>")
extern class SurfacePointer {}
@:native("::cpp::Reference<SDL_Texture>")
extern class TexturePointer {}
@:native("::cpp::Reference<SDL_Rect>")
extern class RectPointer {}
#include "SDL2-2.0.3/include/SDL.h"
#undef main
@nadako
Copy link
Author

nadako commented Jun 24, 2015

Now we only need to autogenerate that!

@fullofcaffeine
Copy link

That's pretty cool, man! So, as long as we have access to the header files, we can avoid CFFI?

@porfirioribeiro
Copy link

This is great! Why use ndll CFFI layer when you can do native calls, targeting CPP? 😔

For auto generate externs from headers maybe something like http://www.swig.org/ will help.

I remember that being used to generate FreeBasic headers from C 😄

@ruby0x1
Copy link

ruby0x1 commented Jul 2, 2015

@porfirioribeiro CFFI still works with neko, these do not (and can't)

@nadako Nice gist! Now I have to fast track an announcement for a set of libraries (including SDL) which i've already bound 😳 hah

There are some problems with autogenerating btw, if you want the API to be "haxe friendly" (for example SDL_GetWindowSize( window, int* w, int* h ), a better alternative is GetWindowSize(window):{w:Int, h:Int} which requires specific rules about the c api's that don't fit haxe usage. Another example: stack values (now better with cpp.Reference but can still be a problem) and allocations in general skipping GC - these type of details need care and attention to be stable.

Anyway I'll make a blog post about this - aside from some few endpoints I've already bound the whole of SDL for use with "just" haxe/hxcpp :)

@nadako
Copy link
Author

nadako commented Aug 24, 2015

oh, this gist has comments! too bad I didn't receive any notifications :-(

yeah probably autogenerating is not the way here, but we can greatly simplify the extern class syntax through macros. In the other version I played with, I made a @:build macro that automatically inserts @:native metadatas and static modifiers for methods and vars in the extern class, so it's quite easy to write.

@nadako
Copy link
Author

nadako commented Aug 24, 2015

As for "haxe-friendliness". I would make a plain 1-to-1 SDL API bindings and then add an additional layer over that that wraps stuff into classes and structures.

@Aurel300
Copy link

Thank you! You just saved me an hour or two of figuring out external .cpp code with haxe and SDL2, etc … This works pretty much out of the box.

Copy link

ghost commented May 23, 2019

Line 62 is probably wrong.
@:op(A|B) static function _(a:CreateRendererFlag, b:CreateRendererFlag):CreateRendererFlag;
should be
@:op(A|B) static function _(a:CreateRendererFlag, b:CreateRendererFlag):RendererPointer;
by analogy with the line 58
@:op(A|B) static function _(a:CreateWindowFlag, b:CreateWindowFlag):WindowPointer;
However, I'm not sure. I'm not so familiar with Haxe yet to understand this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment