Browse Source

Most functionality wrapped.

Beoran 6 years ago
parent
commit
4c21652912
20 changed files with 878 additions and 90 deletions
  1. 45 0
      al/aid.go
  2. 0 1
      al/al.go
  3. 0 1
      al/bitmap.go
  4. 0 1
      al/bitmap_draw.go
  5. 0 1
      al/bitmap_io.go
  6. 0 1
      al/blender.go
  7. 0 16
      al/callbacks.c
  8. 9 31
      al/callbacks.go
  9. 0 1
      al/clipboard.go
  10. 0 1
      al/color.go
  11. 177 32
      al/config.go
  12. 0 1
      al/cpu.go
  13. 0 1
      al/event.go
  14. 0 1
      al/file.go
  15. 0 1
      al/mode.go
  16. 8 0
      al/mouse.go
  17. 58 0
      al/render.go
  18. 167 0
      al/shader.go
  19. 231 0
      al/threads.go
  20. 183 0
      al/transformations.go

+ 45 - 0
al/aid.go

@@ -106,6 +106,16 @@ func cd(f float64) C.double {
     return C.double(f)
 }
 
+// Sometimes I need many floats..
+func cf2(f1, f2 float32) (C.float, C.float) {
+    return C.float(f1), C.float(f2)
+}
+
+// Sometimes I need many floats..
+func cf3(f1, f2, f3 float32) (C.float, C.float, C.float) {
+    return C.float(f1), C.float(f2), C.float(f3)
+}
+
 
 // this is too for laziness, but it's quite handy
 func cui16(f int) C.uint16_t {
@@ -145,6 +155,41 @@ func CStringsFree(argc C.int, argv **C.char) {
     free(unsafe.Pointer(argv))
 }
 
+//Converts an array of go ints to an array of C ints and a length 
+func CInts(args []int) (argc C.int, argv *C.int) {
+    length := len(args)
+    argv = (*C.int)(malloc(length * int(unsafe.Sizeof(argv))))
+    tmpslice := (*[1 << 30]C.int)(unsafe.Pointer(argv))[:length:length]
+    for i, v := range args {
+        tmpslice[i] = C.int(v)
+    }
+    argc = C.int(length)
+    return argc, argv
+}
+
+// frees the data allocated by Cints
+func CIntsFree(argc C.int, argv *C.int) {
+    free(unsafe.Pointer(argv))
+}
+
+
+//Converts an array of go float32 to an array of C float and a length 
+func CFloats(args []float32) (argc C.int, argv *C.float) {
+    length := len(args)
+    argv = (*C.float)(malloc(length * int(unsafe.Sizeof(*argv))))
+    tmpslice := (*[1 << 30]C.float)(unsafe.Pointer(argv))[:length:length]
+    for i, v := range args {
+        tmpslice[i] = C.float(v)
+    }
+    argc = C.int(length)
+    return argc, argv
+}
+
+// frees the data allocated by Cints
+func CFloatsFree(argc C.int, argv *C.float) {
+    free(unsafe.Pointer(argv))
+}
+
 
 
 

+ 0 - 1
al/al.go

@@ -194,7 +194,6 @@ AL_FUNC(bool, al_make_path_canonical, (ALLEGRO_PATH *path));
 
 // Not wrapped yet: 
 // AL_FUNC(SYSTEM *, al_get_system_driver, (void));
-// AL_FUNC(CONFIG *, al_get_system_config, (void));
 
 const (
     RESOURCES_PATH          = C.ALLEGRO_RESOURCES_PATH

+ 0 - 1
al/bitmap.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/bitmap_draw.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/bitmap_io.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/blender.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 16
al/callbacks.c

@@ -1,16 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <allegro5/allegro.h>
-#include "helpers.h"
-#include "callbacks.h"
-#include "_cgo_export.h"
-
-/* This wraps the C api function that takes a callback, to take go_take_callback_callback
- as the callback */
-int go_take_callback(void * context) {
-    return take_callback((function_pointer)go_take_callback_callback, context);
-}
-
- 
-
-

+ 9 - 31
al/callbacks.go

@@ -4,7 +4,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 
@@ -45,39 +44,18 @@ func go_run_main_callback(argc C.int, argv ** C.char) C.int {
     return C.int(runMain.fn(args, runMain.data))
 }
 
+type ThreadCallbackFunction func(*Thread, unsafe.Pointer) unsafe.Pointer
 
-// generic function pointer caller
-
-var CallbackInt func() int = nil
-
-//export go_generic_callback_int
-func go_generic_callback_int() int {
-    if CallbackInt != nil {
-        return CallbackInt()
-    }
-    return 0
-}
-
-type CallbackFunction func() int
-
-type callbackData struct {
-    fn   CallbackFunction
+type threadCallbackData struct {
+    fn   ThreadCallbackFunction
     data unsafe.Pointer
 }
 
-// the function below is the C callback that will be given to the 
-// C api that needs a callback. It uses a callback context with a 
-// Go function pointer in it to call that go function.
-
-//export go_take_callback_callback
-func go_take_callback_callback(context unsafe.Pointer) int {
-    cbd := (*callbackData)(context)
-    fn := cbd.fn
-    return fn()
+//export go_create_thread_callback
+func go_create_thread_callback(thread * C.ALLEGRO_THREAD, arg unsafe.Pointer) unsafe.Pointer {
+    cbd := (*threadCallbackData)(arg)
+    fn  := cbd.fn
+    res := fn(wrapThreadRaw(thread), cbd.data)
+    return unsafe.Pointer(res)
 }
 
-// Finally wrap the C callback caller function.
-func TakeCallback(fn CallbackFunction) int {
-    ctx := unsafe.Pointer(&callbackData{fn, nil})
-    return int(C.go_take_callback(ctx))
-}

+ 0 - 1
al/clipboard.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/color.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 177 - 32
al/config.go

@@ -1,45 +1,190 @@
-// TODO configuration support
+// configuration support
 package al
 
 /*
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
+import "runtime"
 
 
-/*
-typedef struct ALLEGRO_CONFIG ALLEGRO_CONFIG;
-
-typedef struct ALLEGRO_CONFIG_SECTION ALLEGRO_CONFIG_SECTION;
-
-typedef struct ALLEGRO_CONFIG_ENTRY ALLEGRO_CONFIG_ENTRY;
-
-AL_FUNC(ALLEGRO_CONFIG *, al_create_config, (void));
-AL_FUNC(void, al_add_config_section, (ALLEGRO_CONFIG *config, const char *name));
-AL_FUNC(void, al_set_config_value, (ALLEGRO_CONFIG *config, const char *section, const char *key, const char *value));
-AL_FUNC(void, al_add_config_comment, (ALLEGRO_CONFIG *config, const char *section, const char *comment));
-AL_FUNC(const char*, al_get_config_value, (const ALLEGRO_CONFIG *config, const char *section, const char *key));
-AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file, (const char *filename));
-AL_FUNC(ALLEGRO_CONFIG*, al_load_config_file_f, (ALLEGRO_FILE *filename));
-AL_FUNC(bool, al_save_config_file, (const char *filename, const ALLEGRO_CONFIG *config));
-AL_FUNC(bool, al_save_config_file_f, (ALLEGRO_FILE *file, const ALLEGRO_CONFIG *config));
-AL_FUNC(void, al_merge_config_into, (ALLEGRO_CONFIG *master, const ALLEGRO_CONFIG *add));
-AL_FUNC(ALLEGRO_CONFIG *, al_merge_config, (const ALLEGRO_CONFIG *cfg1, const ALLEGRO_CONFIG *cfg2));
-AL_FUNC(void, al_destroy_config, (ALLEGRO_CONFIG *config));
-AL_FUNC(bool, al_remove_config_section, (ALLEGRO_CONFIG *config,
-        char const *section));
-AL_FUNC(bool, al_remove_config_key, (ALLEGRO_CONFIG *config,
-        char const *section, char const *key));
-
-AL_FUNC(char const *, al_get_first_config_section, (ALLEGRO_CONFIG const *config, ALLEGRO_CONFIG_SECTION **iterator));
-AL_FUNC(char const *, al_get_next_config_section, (ALLEGRO_CONFIG_SECTION **iterator));
-AL_FUNC(char const *, al_get_first_config_entry, (ALLEGRO_CONFIG const *config, char const *section,
-    ALLEGRO_CONFIG_ENTRY **iterator));
-AL_FUNC(char const *, al_get_next_config_entry, (ALLEGRO_CONFIG_ENTRY **iterator));
+type Config struct {
+    handle * C.ALLEGRO_CONFIG
+}
 
-*/
+// Converts a config to it's underlying C pointer
+func (self * Config) toC() *C.ALLEGRO_CONFIG {
+    return (*C.ALLEGRO_CONFIG)(self.handle)
+}
+
+// Destroys the config.
+func (self *Config) Destroy() {
+    if self.handle != nil {
+        C.al_destroy_config(self.toC())
+    }
+    self.handle = nil
+}
+
+// Wraps a C config into a go config
+func wrapConfigRaw(data *C.ALLEGRO_CONFIG) *Config {
+    if data == nil {
+        return nil
+    }
+    return &Config{data}
+}
+
+// Sets up a finalizer for this Config that calls Destroy()
+func (self *Config) SetDestroyFinalizer() *Config {
+    if self != nil {
+        runtime.SetFinalizer(self, func(me *Config) { me.Destroy() })
+    }
+    return self
+}
+
+// Wraps a C config into a go config and sets up a finalizer that calls Destroy()
+func wrapConfig(data *C.ALLEGRO_CONFIG) *Config {
+    self := wrapConfigRaw(data)
+    return self.SetDestroyFinalizer()
+}
+
+type ConfigSection C.ALLEGRO_CONFIG_SECTION
+
+func (cs * ConfigSection) toC() * C.ALLEGRO_CONFIG_SECTION {
+    return (*C.ALLEGRO_CONFIG_SECTION)(cs)
+}
+
+func wrapConfigSectionRaw(ccs * C.ALLEGRO_CONFIG_SECTION) * ConfigSection {
+    return (*ConfigSection)(ccs)
+}
+
+type ConfigEntry C.ALLEGRO_CONFIG_ENTRY
+
+func (cs * ConfigEntry) toC() * C.ALLEGRO_CONFIG_ENTRY {
+    return (*C.ALLEGRO_CONFIG_ENTRY)(cs)
+}
+
+func wrapConfigEntryRaw(ccs * C.ALLEGRO_CONFIG_ENTRY) * ConfigEntry {
+    return (*ConfigEntry)(ccs)
+}
+
+
+
+func SystemConfig() * Config {
+    return wrapConfig(C.al_get_system_config())
+}
+
+
+func CreateConfig() * Config {
+    return wrapConfig(C.al_create_config())
+}
+
+func (cf * Config) AddSection(name string) {
+    cname := cstr(name); defer cstrFree(cname)
+    C.al_add_config_section(cf.toC(), cname) 
+} 
+
+
+func (cf * Config) SetValue(section, key, value string) {
+    csection    := cstr(section);   defer cstrFree(csection)
+    ckey        := cstr(key);       defer cstrFree(ckey)
+    cvalue      := cstr(value);     defer cstrFree(cvalue)
+    C.al_set_config_value(cf.toC(), csection, ckey, cvalue) 
+} 
+
+func (cf * Config) AddComment(section, key, comment string) {
+    csection    := cstr(section);   defer cstrFree(csection)
+    ckey        := cstr(key);       defer cstrFree(ckey)
+    ccomment    := cstr(comment);   defer cstrFree(ccomment)
+    C.al_set_config_value(cf.toC(), csection, ckey, ccomment) 
+}
+
+func (cf * Config) Value(section, key string) string {
+    csection    := cstr(section);   defer cstrFree(csection)
+    ckey        := cstr(key);       defer cstrFree(ckey)
+    return C.GoString(C.al_get_config_value(cf.toC(), csection, ckey)) 
+} 
+
+func LoadConfig(filename string) * Config{
+    cfilename := cstr(filename); defer cstrFree(cfilename)
+    return wrapConfig(C.al_load_config_file(cfilename))
+}
+
+func LoadConfigFile(file * File) * Config{
+    return wrapConfig(C.al_load_config_file_f(file.toC()))
+}
+
+
+func (cf * Config) Save(filename string) bool {
+    cfilename := cstr(filename); defer cstrFree(cfilename)
+    return bool(C.al_save_config_file(cfilename, cf.toC()))
+}
+
+func (cf * Config) SaveFile(file * File) bool {
+    return bool(C.al_save_config_file_f(file.toC(), cf.toC()))
+}
+
+func (cf * Config) MergeInto(add * Config) {
+    C.al_merge_config_into(cf.toC(), add.toC())
+}
+
+func (cf * Config) Merge(cf2 * Config) * Config {
+    return wrapConfig(C.al_merge_config(cf.toC(), cf2.toC()))
+}
+
+
+func (cf * Config) RemoveSection(name string) bool {
+    cname := cstr(name); defer cstrFree(cname)
+    return bool(C.al_remove_config_section(cf.toC(), cname)) 
+} 
+
+
+func (cf * Config) RemoveKey(section, key string) bool {
+    csection    := cstr(section);   defer cstrFree(csection)
+    ckey        := cstr(key);       defer cstrFree(ckey)
+    return bool(C.al_remove_config_key(cf.toC(), csection, ckey))
+} 
+
+func (cf * Config) FirstSection() (name string, section * ConfigSection) {
+    section   = &ConfigSection{}
+    csection := section.toC()
+    name = C.GoString(C.al_get_first_config_section(cf.toC(), &csection))
+    return name, section
+}
+
+func (section * ConfigSection) Next() (name string, ok bool) {
+    csection := section.toC()
+    cname := C.al_get_next_config_section(&csection)
+    if cname == nil {
+        name    = ""
+        ok      = false
+    } else {
+        name    = C.GoString(cname)
+        ok      = true
+    }
+    return name, ok
+}
+
+func (cf * Config) FirstEntry(section string) (name string, entry * ConfigEntry) {
+    csection := cstr(section);   defer cstrFree(csection)
+    entry   = &ConfigEntry{}
+    centry := entry.toC()
+    name = C.GoString(C.al_get_first_config_entry(cf.toC(), csection, &centry))
+    return name, entry
+}
+
+func (entry * ConfigEntry) Next() (name string, ok bool) {
+    centry := entry.toC()
+    cname  := C.al_get_next_config_entry(&centry)
+    if cname == nil {
+        name    = ""
+        ok      = false
+    } else {
+        name    = C.GoString(cname)
+        ok      = true
+    }
+    return name, ok
+}
 
 

+ 0 - 1
al/cpu.go

@@ -5,7 +5,6 @@ package al
 #include <stdlib.h>
 #include <allegro5/allegro.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/event.go

@@ -8,7 +8,6 @@ package al
 #include <allegro5/allegro.h>
 #include <allegro5/events.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/file.go

@@ -9,7 +9,6 @@ package al
 #include <allegro5/allegro.h>
 #include <allegro5/file.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 

+ 0 - 1
al/mode.go

@@ -9,7 +9,6 @@ package al
 #include <allegro5/allegro.h>
 #include <allegro5/fullscreen_mode.h>
 #include "helpers.h"
-#include "callbacks.h"
 */
 import "C"
 import "fmt"

+ 8 - 0
al/mouse.go

@@ -245,4 +245,12 @@ func UngrabMouse() bool {
     return cb2b(C.al_ungrab_mouse())
 }
 
+func SetMouseWheelPrecision(precision int) {
+    C.al_set_mouse_wheel_precision(C.int(precision))
+}
+
+func MouseWheelPrecision() int {
+    return int(C.al_get_mouse_wheel_precision())
+}
+
 

+ 58 - 0
al/render.go

@@ -0,0 +1,58 @@
+package al
+
+/*
+#include <stdlib.h>
+#include <allegro5/allegro.h>
+#include "helpers.h"
+*/
+import "C"
+
+type RenderState = C.ALLEGRO_RENDER_STATE
+
+const (
+   ALPHA_TEST       = RenderState(C.ALLEGRO_ALPHA_TEST      )
+   WRITE_MASK       = RenderState(C.ALLEGRO_WRITE_MASK      )
+   DEPTH_TEST       = RenderState(C.ALLEGRO_DEPTH_TEST      )
+   DEPTH_FUNCTION   = RenderState(C.ALLEGRO_DEPTH_FUNCTION  )
+   ALPHA_FUNCTION   = RenderState(C.ALLEGRO_ALPHA_FUNCTION  )
+   ALPHA_TEST_VALUE = RenderState(C.ALLEGRO_ALPHA_TEST_VALUE)
+)
+
+func (rs RenderState) toC() C.ALLEGRO_RENDER_STATE {
+    return C.ALLEGRO_RENDER_STATE(rs)
+}
+
+// not usable as such, cast to int in stead
+
+// type RenderFunction = C.ALLEGRO_RENDER_FUNCTION
+
+const (
+   RENDER_NEVER         = int(C.ALLEGRO_RENDER_NEVER        )  
+   RENDER_ALWAYS        = int(C.ALLEGRO_RENDER_ALWAYS       ) 
+   RENDER_LESS          = int(C.ALLEGRO_RENDER_LESS         )
+   RENDER_EQUAL         = int(C.ALLEGRO_RENDER_EQUAL        )
+   RENDER_LESS_EQUAL    = int(C.ALLEGRO_RENDER_LESS_EQUAL   )    
+   RENDER_GREATER       = int(C.ALLEGRO_RENDER_GREATER      ) 
+   RENDER_NOT_EQUAL     = int(C.ALLEGRO_RENDER_NOT_EQUAL    )
+   RENDER_GREATER_EQUAL = int(C.ALLEGRO_RENDER_GREATER_EQUAL)
+)
+
+
+// not usable as such, cast to int in stead
+
+// type WriteMaskFlags C.ALLEGRO_WRITE_MASK_FLAGS
+
+const (
+   MASK_RED   = int(C.ALLEGRO_MASK_RED  ) 
+   MASK_GREEN = int(C.ALLEGRO_MASK_GREEN) 
+   MASK_BLUE  = int(C.ALLEGRO_MASK_BLUE ) 
+   MASK_ALPHA = int(C.ALLEGRO_MASK_ALPHA) 
+   MASK_DEPTH = int(C.ALLEGRO_MASK_DEPTH) 
+   MASK_RGB   = int(C.ALLEGRO_MASK_RGB  ) 
+   MASK_RGBA  = int(C.ALLEGRO_MASK_RGBA ) 
+)
+
+func SetRenderState(state RenderState, value int) { 
+    C.al_set_render_state(state.toC(), C.int(value))
+}
+

+ 167 - 0
al/shader.go

@@ -0,0 +1,167 @@
+package al
+
+/*
+#include <stdlib.h>
+#include <allegro5/allegro.h>
+#include "helpers.h"
+*/
+import "C"
+
+// import "unsafe"
+import "runtime"
+
+type ShaderType C.ALLEGRO_SHADER_TYPE
+
+const (
+   VertexShader = ShaderType(C.ALLEGRO_VERTEX_SHADER)
+   PixelShader  = ShaderType(C.ALLEGRO_PIXEL_SHADER)
+)
+
+func (st ShaderType) toC() C.ALLEGRO_SHADER_TYPE {
+    return (C.ALLEGRO_SHADER_TYPE)(st)
+}
+
+type ShaderPlatform C.ALLEGRO_SHADER_PLATFORM
+
+const (
+   ShaderAuto = ShaderPlatform(C.ALLEGRO_SHADER_AUTO)
+   ShaderGLSL = ShaderPlatform(C.ALLEGRO_SHADER_GLSL)
+   ShaderHLSL = ShaderPlatform(C.ALLEGRO_SHADER_HLSL)
+)
+
+func (sp ShaderPlatform) toC() C.ALLEGRO_SHADER_PLATFORM {
+    return (C.ALLEGRO_SHADER_PLATFORM)(sp)
+}
+
+
+/* Shader variable names */
+const  (
+    ShaderVarColor          = "al_color"
+    ShaderVarPos            = "al_pos"
+    ShaderVarProjviewMatrix = "al_projview_matrix"
+    ShaderVarTex            = "al_tex"
+    ShaderVarTextcoord      = "al_texcoord"
+    ShaderVarTextMatrix     = "al_tex_matrix"
+    ShaderVarUserAttr       = "al_user_attr_"
+    ShaderVarUseTex         = "al_use_tex"
+    ShaderVarUseTexMatrix   = "al_use_tex_matrix"
+)
+
+
+type Shader struct {
+    handle * C.ALLEGRO_SHADER
+}
+
+// Converts a shader to it's underlying C pointer
+func (self * Shader) toC() *C.ALLEGRO_SHADER {
+    return (*C.ALLEGRO_SHADER)(self.handle)
+}
+
+// Destroys the shader.
+func (self *Shader) Destroy() {
+    if self.handle != nil {
+        C.al_destroy_shader(self.toC())
+    }
+    self.handle = nil
+}
+
+// Wraps a C shader into a go shader
+func wrapShaderRaw(data *C.ALLEGRO_SHADER) *Shader {
+    if data == nil {
+        return nil
+    }
+    return &Shader{data}
+}
+
+// Sets up a finalizer for this Shader that calls Destroy()
+func (self *Shader) SetDestroyFinalizer() *Shader {
+    if self != nil {
+        runtime.SetFinalizer(self, func(me *Shader) { me.Destroy() })
+    }
+    return self
+}
+
+// Wraps a C shader into a go shader and sets up a finalizer that calls Destroy()
+func wrapShader(data *C.ALLEGRO_SHADER) *Shader {
+    self := wrapShaderRaw(data)
+    return self.SetDestroyFinalizer()
+}
+
+
+func (sp ShaderPlatform) Create() *Shader {
+    return wrapShader(C.al_create_shader(sp.toC()))
+}
+
+func (sh * Shader) AttachSource(shatype ShaderType, source string) bool {
+    csource := cstr(source); defer cstrFree(csource)
+    return bool(C.al_attach_shader_source(sh.toC(), shatype.toC(), csource))
+}
+
+func (sh * Shader) AttachSourceFile(shatype ShaderType, source string) bool {
+    csource := cstr(source); defer cstrFree(csource)
+    return bool(C.al_attach_shader_source_file(sh.toC(), shatype.toC(), csource))
+}
+
+func (sh * Shader) Build() bool {
+    return bool(C.al_build_shader(sh.toC()))
+}
+
+func (sh * Shader) Log() string {
+    return C.GoString(C.al_get_shader_log(sh.toC()))
+}
+
+func (sh * Shader) Platform() ShaderPlatform {
+    return ShaderPlatform(C.al_get_shader_platform(sh.toC()))
+}
+
+func (sh * Shader) Use() bool { 
+    return bool(C.al_use_shader(sh.toC()))
+}
+
+func SetShaderSampler(name string, bitmap * Bitmap, unit int) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    return bool(C.al_set_shader_sampler(cname, bitmap.toC(), C.int(unit)))
+}
+
+/*
+func (sh * Shader) SetMatrix(name string, matrix * Matrix) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    return bool(C.al_set_shader_matrix(sh.toC(), cname, matrix.toC()))
+}
+*/ 
+
+func SetShaderInt(name string, i int) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    return bool(C.al_set_shader_int(cname, C.int(i)))
+}
+
+func SetShaderFloat(name string, f float32) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    return bool(C.al_set_shader_float(cname, C.float(f)))
+}
+
+func SetShaderBool(name string, b bool) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    return bool(C.al_set_shader_bool(cname, C.bool(b)))
+}
+
+func (sh * Shader) SetIntVector(name string, nc int, i []int) bool {
+    cname := cstr(name); defer cstrFree(cname)
+    csize, cvec := CInts(i) ; defer CIntsFree(csize, cvec) 
+    /* XXX, I doubt this will work for nc > 1 ... */
+    return bool(C.al_set_shader_int_vector(cname, C.int(nc), cvec, csize / C.int(nc)))
+}
+
+func (sh * Shader) SetFloatVector(name string, nc int, f []float32) bool {
+    cname := cstr(name); defer cstrFree(cname) 
+    csize, cvec := CFloats(f) ; defer CFloatsFree(csize, cvec) 
+    /* XXX, I doubt this will work for nc > 1 ... */
+    return bool(C.al_set_shader_float_vector(cname, C.int(nc), cvec, csize / C.int(nc)))
+}
+
+
+func GetDefaultShaderSource(pla ShaderPlatform, ty ShaderType) string {
+    return C.GoString(C.al_get_default_shader_source(pla.toC(), ty.toC()))
+}
+
+

+ 231 - 0
al/threads.go

@@ -0,0 +1,231 @@
+// threads and tls support
+package al
+
+/*
+#include <stdlib.h>
+#include <allegro5/allegro.h>
+#include "helpers.h"
+#include "callbacks.h"
+*/
+import "C"
+import "runtime"
+import "unsafe"
+
+
+type Thread struct {
+    handle * C.ALLEGRO_THREAD
+}
+
+// Converts a thread to it's underlying C pointer
+func (self * Thread) toC() *C.ALLEGRO_THREAD {
+    return (*C.ALLEGRO_THREAD)(self.handle)
+}
+
+// Destroys the thread.
+func (self *Thread) Destroy() {
+    if self.handle != nil {
+        C.al_destroy_thread(self.toC())
+    }
+    self.handle = nil
+}
+
+// Wraps a C thread into a go thread
+func wrapThreadRaw(data *C.ALLEGRO_THREAD) *Thread {
+    if data == nil {
+        return nil
+    }
+    return &Thread{data}
+}
+
+// Sets up a finalizer for this Thread that calls Destroy()
+func (self *Thread) SetDestroyFinalizer() *Thread {
+    if self != nil {
+        runtime.SetFinalizer(self, func(me *Thread) { me.Destroy() })
+    }
+    return self
+}
+
+// Wraps a C thread into a go thread and sets up a finalizer that calls Destroy()
+func wrapThread(data *C.ALLEGRO_THREAD) *Thread {
+    self := wrapThreadRaw(data)
+    return self.SetDestroyFinalizer()
+}
+
+type Cond struct {
+    handle * C.ALLEGRO_COND
+}
+
+// Converts a cond to it's underlying C pointer
+func (self * Cond) toC() *C.ALLEGRO_COND {
+    return (*C.ALLEGRO_COND)(self.handle)
+}
+
+// Destroys the cond.
+func (self *Cond) Destroy() {
+    if self.handle != nil {
+        C.al_destroy_cond(self.toC())
+    }
+    self.handle = nil
+}
+
+// Wraps a C cond into a go cond
+func wrapCondRaw(data *C.ALLEGRO_COND) *Cond {
+    if data == nil {
+        return nil
+    }
+    return &Cond{data}
+}
+
+// Sets up a finalizer for this Cond that calls Destroy()
+func (self *Cond) SetDestroyFinalizer() *Cond {
+    if self != nil {
+        runtime.SetFinalizer(self, func(me *Cond) { me.Destroy() })
+    }
+    return self
+}
+
+// Wraps a C cond into a go cond and sets up a finalizer that calls Destroy()
+func wrapCond(data *C.ALLEGRO_COND) *Cond {
+    self := wrapCondRaw(data)
+    return self.SetDestroyFinalizer()
+}
+
+type Mutex struct {
+    handle * C.ALLEGRO_MUTEX
+}
+
+// Converts a mutex to it's underlying C pointer
+func (self * Mutex) toC() *C.ALLEGRO_MUTEX {
+    return (*C.ALLEGRO_MUTEX)(self.handle)
+}
+
+// Destroys the mutex.
+func (self *Mutex) Destroy() {
+    if self.handle != nil {
+        C.al_destroy_mutex(self.toC())
+    }
+    self.handle = nil
+}
+
+// Wraps a C mutex into a go mutex
+func wrapMutexRaw(data *C.ALLEGRO_MUTEX) *Mutex {
+    if data == nil {
+        return nil
+    }
+    return &Mutex{data}
+}
+
+// Sets up a finalizer for this Mutex that calls Destroy()
+func (self *Mutex) SetDestroyFinalizer() *Mutex {
+    if self != nil {
+        runtime.SetFinalizer(self, func(me *Mutex) { me.Destroy() })
+    }
+    return self
+}
+
+// Wraps a C mutex into a go mutex and sets up a finalizer that calls Destroy()
+func wrapMutex(data *C.ALLEGRO_MUTEX) *Mutex {
+    self := wrapMutexRaw(data)
+    return self.SetDestroyFinalizer()
+}
+
+
+func CreateThread(fn ThreadCallbackFunction, data unsafe.Pointer) *Thread {
+    cbd := & threadCallbackData{fn , data}
+    ct := C.al_create_thread((*[0]byte)(C.go_create_thread_callback), unsafe.Pointer(cbd))
+    return wrapThread(ct)
+}
+
+func (thread * Thread) Start() {
+    C.al_start_thread(thread.toC())
+}
+
+func (thread * Thread) Join() (data interface {}) {
+    gdata:= make([]byte, 64)
+    gptr := unsafe.Pointer(&gdata)
+    cptr := &gptr 
+    /* XXX: I am not sure this hack will work. */
+    C.al_join_thread(thread.toC(), cptr)
+    return gdata
+}
+
+func (thread * Thread) ShouldStop() (bool) {
+    return bool(C.al_get_thread_should_stop(thread.toC())) 
+}
+
+func (thread * Thread) SetShouldStop() {
+    C.al_set_thread_should_stop(thread.toC()) 
+}
+
+func RunDetachedThread(fn ThreadCallbackFunction, data unsafe.Pointer) {
+    cbd := & threadCallbackData{fn , data}
+    C.al_run_detached_thread((*[0]byte)(C.go_create_thread_callback), unsafe.Pointer(cbd))
+}
+
+func CreateMutex() * Mutex {
+    return wrapMutex(C.al_create_mutex())
+}
+
+func CreateMutexRecursive() * Mutex {
+    return wrapMutex(C.al_create_mutex_recursive())
+}
+
+func (mutex * Mutex) Lock() {
+    C.al_lock_mutex(mutex.toC())
+} 
+
+func (mutex * Mutex) Unlock() {
+    C.al_unlock_mutex(mutex.toC())
+} 
+
+func CreateCond() * Cond {
+    return wrapCond(C.al_create_cond())
+}
+
+func (cond * Cond) Wait(mutex * Mutex) {
+    C.al_wait_cond(cond.toC(), mutex.toC())
+} 
+
+func (cond * Cond) WaitUntil(mutex * Mutex, timeout * Timeout) {
+    C.al_wait_cond_until(cond.toC(), mutex.toC(), timeout.toC())
+} 
+
+func (cond * Cond) Broadcast(mutex * Mutex) {
+    C.al_broadcast_cond(cond.toC())
+} 
+
+func (cond * Cond) Signal(mutex * Mutex) {
+    C.al_signal_cond(cond.toC())
+} 
+
+
+
+const (
+    STATE_NEW_DISPLAY_PARAMETERS= C.ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS
+    STATE_NEW_BITMAP_PARAMETERS = C.ALLEGRO_STATE_NEW_BITMAP_PARAMETERS 
+    STATE_DISPLAY               = C.ALLEGRO_STATE_DISPLAY               
+    STATE_TARGET_BITMAP         = C.ALLEGRO_STATE_TARGET_BITMAP         
+    STATE_BLENDER               = C.ALLEGRO_STATE_BLENDER               
+    STATE_NEW_FILE_INTERFACE    = C.ALLEGRO_STATE_NEW_FILE_INTERFACE    
+    STATE_TRANSFORM             = C.ALLEGRO_STATE_TRANSFORM             
+    STATE_PROJECTION_TRANSFORM  = C.ALLEGRO_STATE_PROJECTION_TRANSFORM  
+    STATE_BITMAP                = C.ALLEGRO_STATE_BITMAP                
+    STATE_ALL                   = C.ALLEGRO_STATE_ALL                   
+)
+
+
+
+type State C.ALLEGRO_STATE;
+
+func StoreState(flags int) * State {
+    state := &C.ALLEGRO_STATE{}
+    C.al_store_state(state, C.int(flags))
+    return (*State)(state)
+} 
+
+func (state * State) Restore() {
+    cstate := (*C.ALLEGRO_STATE)(state)
+    C.al_restore_state(cstate);
+}
+
+

+ 183 - 0
al/transformations.go

@@ -0,0 +1,183 @@
+package al
+
+/*
+#include <stdlib.h>
+#include <allegro5/allegro.h>
+#include "helpers.h"
+#include "callbacks.h"
+*/
+import "C"
+
+
+type Transform C.ALLEGRO_TRANSFORM
+
+func wrapTransformRaw(ctrans * C.ALLEGRO_TRANSFORM) * Transform {
+    return (*Transform)(ctrans)
+}
+
+func (trans * Transform) toC() * C.ALLEGRO_TRANSFORM {
+    return (* C.ALLEGRO_TRANSFORM)(trans)
+}
+
+
+func (trans * Transform) Init(matrix [4][4]float32) {
+    for i:=0; i <4; i ++ {
+        for j:=0; j < 4; j ++ {
+            trans.Put(i, j, matrix[i][j])
+        }
+    }
+}
+
+func (trans * Transform) Matrix() (matrix [4][4]float32) {    
+    for i:=0; i <4; i ++ {
+        for j:=0; j < 4; j ++ {
+            matrix[i][j] = trans.Get(i,j)
+        }
+    }
+    return matrix
+}
+
+func (trans * Transform) Get(i, j int) float32 {
+    return float32(trans.m[i][j])
+}
+
+func (trans * Transform) Put(i, j int, v float32) {
+    trans.m[i][j] = C.float(v)
+}
+
+func CreateIdentityTransform() * Transform {
+    trans := &Transform{}
+    return trans.Identity()
+}
+
+
+func CreateTransform(x, y, sx, sy, theta float32) * Transform {
+    trans := &Transform{}
+    return trans.Build(x, y, sx, sy, theta)
+}
+
+func (trans * Transform) Identity() * Transform {
+    C.al_identity_transform(trans.toC())
+    return trans
+}
+
+
+func (trans * Transform) Build(x, y, sx, sy, theta float32) * Transform {
+    C.al_build_transform(trans.toC(), C.float(x), C.float(y), C.float(sx), C.float(sy), C.float(theta))
+    return trans
+}
+
+func (trans * Transform) Use() {
+    C.al_use_transform(trans.toC())
+}
+
+func (trans * Transform) UseProjection() {
+    C.al_use_projection_transform(trans.toC())
+}
+
+func (trans * Transform) BuildCamera(px, py, pz, 
+    lx, ly, lz, ux, uy, uz float32) * Transform {
+    cpx, cpy, cpz := cf3(px, py, pz)
+    clx, cly, clz := cf3(lx, ly, lz)
+    cux, cuy, cuz := cf3(ux, uy, uz)
+    C.al_build_camera_transform(trans.toC(), cpx, cpy, cpz, clx, cly, clz, cux, cuy, cuz)
+    return trans
+}
+
+
+func (trans * Transform) Translate(x, y float32) * Transform {
+    C.al_translate_transform(trans.toC(), C.float(x), C.float(y))
+    return trans
+}
+
+func (trans * Transform) Translate3D(x, y, z float32) * Transform {
+    C.al_translate_transform_3d(trans.toC(), C.float(x), C.float(y), C.float(z))
+    return trans
+}
+
+
+func (trans * Transform) Rotate(theta float32) * Transform {
+    C.al_rotate_transform(trans.toC(), C.float(theta))
+    return trans
+}
+
+func (trans * Transform) Rotate3D(x, y, z, angle float32) * Transform {
+    C.al_rotate_transform_3d(trans.toC(), C.float(x), C.float(y), C.float(z), C.float(angle))
+    return trans
+}
+
+
+func (trans * Transform) Scale(x, y float32) * Transform {
+    C.al_scale_transform(trans.toC(), C.float(x), C.float(y))
+    return trans
+}
+
+func (trans * Transform) Scale3D(x, y, z float32) * Transform {
+    C.al_scale_transform_3d(trans.toC(), C.float(x), C.float(y), C.float(z))
+    return trans
+}
+
+func (trans * Transform) Coordinates(x, y float32) (float32, float32) {
+    cx, cy := cf2(x, y)
+    C.al_transform_coordinates(trans.toC(), &cx, &cy)    
+    return float32(cx), float32(cy)
+}
+
+func (trans * Transform) Coordinates3D(x, y, z float32) (float32, float32, float32) {
+    cx, cy, cz := cf3(x, y, z)
+    C.al_transform_coordinates_3d(trans.toC(), &cx, &cy, &cz)    
+    return float32(cx), float32(cy), float32(cz)
+}
+
+
+func (trans * Transform) Compose(other * Transform)  * Transform {
+    C.al_compose_transform(trans.toC(), other.toC())    
+    return trans
+}
+
+
+func (trans * Transform) CheckInverse(tolerance float32) bool {
+    return 1 == (C.al_check_inverse(trans.toC(), C.float(tolerance))) 
+}
+
+
+func (trans * Transform) Invert()  * Transform {
+    if trans.CheckInverse(1.0e-7) { 
+        C.al_invert_transform(trans.toC())
+        return trans
+    } else {
+        return nil
+    }
+}
+func CurrentTransform() * Transform {
+    return wrapTransformRaw(C.al_get_current_transform())
+}
+
+func CurrentProjectionTransform() * Transform {
+    return wrapTransformRaw(C.al_get_current_projection_transform())
+}
+
+func (trans * Transform) Orthographic(l, t, n, r, b, f float32) * Transform {
+    cl, ct, cn := cf3(l,t,n)
+    cr, cb, cf := cf3(r,b,f)
+    C.al_orthographic_transform(trans.toC(), cl, ct, cn, cr, cb, cf)
+    return trans
+}
+
+func (trans * Transform) Perspective(l, t, n, r, b, f float32) * Transform {
+    cl, ct, cn := cf3(l,t,n)
+    cr, cb, cf := cf3(r,b,f)
+    C.al_perspective_transform(trans.toC(), cl, ct, cn, cr, cb, cf)
+    return trans
+}
+
+func (trans * Transform) HorizontalShear(theta float32) * Transform {
+    C.al_horizontal_shear_transform(trans.toC(), C.float(theta))
+    return trans
+}
+
+func (trans * Transform) VerticalShear(theta float32) * Transform {
+    C.al_horizontal_shear_transform(trans.toC(), C.float(theta))
+    return trans
+}
+