Created new repository.

This commit is contained in:
Sander Schobers 2019-12-19 07:08:52 +01:00
commit 6151f28ef3
18 changed files with 1316 additions and 0 deletions

37
audio.go Normal file
View File

@ -0,0 +1,37 @@
package allg5
/*
#define ALLEGRO_KCM_AUDIO_SRC
#include <allegro5/allegro_audio.h>
*/
import "C"
type Recorder struct {
recorder *C.ALLEGRO_AUDIO_RECORDER
Frequency int
Depth int
}
func NewRecorder(fragments, samples, frequency, depth int) *Recorder {
var depthC C.ALLEGRO_AUDIO_DEPTH
switch depth {
case 16:
depthC = C.ALLEGRO_AUDIO_DEPTH_INT16
default:
depthC = C.ALLEGRO_AUDIO_DEPTH_UINT8
}
var rec = C.al_create_audio_recorder(C.size_t(fragments), C.uint(samples), C.uint(frequency), depthC, C.ALLEGRO_CHANNEL_CONF_1)
if rec == nil {
return nil
}
return &Recorder{rec, frequency, depth}
}
func (r *Recorder) Start() {
C.al_start_audio_recorder(r.recorder)
}
func (r *Recorder) Destroy() {
C.al_destroy_audio_recorder(r.recorder)
}

260
bitmap.go Normal file
View File

@ -0,0 +1,260 @@
package allg5
// #include <allegro5/allegro.h>
// #include <stdlib.h>
import "C"
import (
"errors"
"image"
"unsafe"
)
// Bitmap represents an in memory bitmap
type Bitmap struct {
bitmap *C.ALLEGRO_BITMAP
width int
height int
subs []*Bitmap
}
type DrawOptions struct {
Center bool
Scale *Scale
Tint *Color
Rotation *Rotation
}
type Scale struct {
Horizontal float32
Vertical float32
}
func NewScale(hor, ver float32) *Scale {
return &Scale{hor, ver}
}
func NewUniformScale(s float32) *Scale {
return &Scale{s, s}
}
type Rotation struct {
Angle float32
Center bool
}
func newBitmap(width, height int, mut func(m FlagMutation), flags []NewBitmapFlag) (*Bitmap, error) {
var newBmpFlags = CaptureNewBitmapFlags()
defer newBmpFlags.Revert()
newBmpFlags.Mutate(func(m FlagMutation) {
if mut != nil {
mut(m)
}
for _, f := range flags {
m.Set(f)
}
})
b := C.al_create_bitmap(C.int(width), C.int(height))
if b == nil {
return nil, errors.New("error creating bitmap")
}
return &Bitmap{b, width, height, nil}, nil
}
// NewBitmap creates a new bitmap of given width and height and optional flags
func NewBitmap(width, height int, flags ...NewBitmapFlag) (*Bitmap, error) {
return newBitmap(width, height, nil, flags)
}
// NewVideoBitmap creates a new video bitmap of given width and height and optional flags
func NewVideoBitmap(width, height int, flags ...NewBitmapFlag) (*Bitmap, error) {
return newBitmap(width, height, func(m FlagMutation) {
m.Unset(NewBitmapFlagMemoryBitmap)
m.Set(NewBitmapFlagVideoBitmap)
}, flags)
}
// NewMemoryBitmap creates a new video bitmap of given width and height and optional flags
func NewMemoryBitmap(width, height int, flags ...NewBitmapFlag) (*Bitmap, error) {
return newBitmap(width, height, func(m FlagMutation) {
m.Unset(NewBitmapFlagVideoBitmap)
m.Set(NewBitmapFlagMemoryBitmap)
}, flags)
}
// NewBitmapFromImage creates a new bitmap starting from a Go native image (image.Image)
func NewBitmapFromImage(src image.Image, video bool) (*Bitmap, error) {
var newBmpFlags = CaptureNewBitmapFlags()
defer newBmpFlags.Revert()
newBmpFlags.Mutate(func(m FlagMutation) {
m.Unset(NewBitmapFlagVideoBitmap)
m.Set(NewBitmapFlagMemoryBitmap)
m.Set(NewBitmapFlagMinLinear)
})
var bnd = src.Bounds()
width, height := bnd.Dx(), bnd.Dy()
var b = C.al_create_bitmap(C.int(width), C.int(height))
if b == nil {
return nil, errors.New("error creating memory bitmap")
}
region := C.al_lock_bitmap(b, C.ALLEGRO_PIXEL_FORMAT_ABGR_8888, C.ALLEGRO_LOCK_WRITEONLY)
if region == nil {
C.al_destroy_bitmap(b)
return nil, errors.New("unable to lock bitmap")
}
dst := (*[1 << 30]uint8)(region.data)
left, top := bnd.Min.X, bnd.Min.Y
for y := 0; y < height; y++ {
row := dst[y*int(region.pitch):]
for x := 0; x < width; x++ {
r, g, b, a := src.At(left+x, top+y).RGBA()
row[x*4] = uint8(r >> 8)
row[x*4+1] = uint8(g >> 8)
row[x*4+2] = uint8(b >> 8)
row[x*4+3] = uint8(a >> 8)
}
}
C.al_unlock_bitmap(b)
if video {
newBmpFlags.Mutate(func(m FlagMutation) {
m.Unset(NewBitmapFlagMemoryBitmap)
m.Set(NewBitmapFlagVideoBitmap)
m.Set(NewBitmapFlagMinLinear)
})
C.al_convert_bitmap(b)
}
return &Bitmap{b, width, height, nil}, nil
}
// LoadBitmap tries to load the image at the specified path as a bitmap
func LoadBitmap(path string) (*Bitmap, error) {
p := C.CString(path)
defer C.free(unsafe.Pointer(p))
b := C.al_load_bitmap(p)
if b == nil {
return nil, errors.New("error loading bitmap")
}
width := int(C.al_get_bitmap_width(b))
height := int(C.al_get_bitmap_height(b))
return &Bitmap{b, width, height, nil}, nil
}
// Draw draws the bitmap at the given location
func (b *Bitmap) Draw(left, top float32) {
C.al_draw_bitmap(b.bitmap, C.float(left), C.float(top), 0)
}
func (b *Bitmap) DrawOptions(left, top float32, options DrawOptions) {
width := float32(b.width)
height := float32(b.height)
scale := options.Scale != nil
if scale {
width *= options.Scale.Horizontal
height *= options.Scale.Vertical
}
if options.Center {
left -= width * 0.5
top -= height * 0.5
}
rotated := options.Rotation != nil
var centerX C.float
var centerY C.float
if rotated && options.Rotation.Center {
centerX = C.float(b.width) * 0.5
centerY = C.float(b.height) * 0.5
}
if scale {
if options.Tint == nil { // scaled
if rotated { // scaled & rotated
C.al_draw_scaled_rotated_bitmap(b.bitmap, centerX, centerY, C.float(left), C.float(top), C.float(options.Scale.Horizontal), C.float(options.Scale.Vertical), C.float(options.Rotation.Angle), 0)
} else { // scaled
C.al_draw_scaled_bitmap(b.bitmap, 0, 0, C.float(b.width), C.float(b.height), C.float(left), C.float(top), C.float(width), C.float(height), 0)
}
} else { // tinted & scaled
if rotated { // scaled, tinted & rotated
C.al_draw_tinted_scaled_rotated_bitmap(b.bitmap, options.Tint.color, centerX, centerY, C.float(left), C.float(top), C.float(options.Scale.Horizontal), C.float(options.Scale.Vertical), C.float(options.Rotation.Angle), 0)
} else { // tinted, scaled
C.al_draw_tinted_scaled_bitmap(b.bitmap, options.Tint.color, 0, 0, C.float(b.width), C.float(b.height), C.float(left), C.float(top), C.float(width), C.float(height), 0)
}
}
} else {
if options.Tint == nil {
if rotated { // rotated
C.al_draw_rotated_bitmap(b.bitmap, centerX, centerY, C.float(left), C.float(top), C.float(options.Rotation.Angle), 0)
} else {
C.al_draw_bitmap(b.bitmap, C.float(left), C.float(top), 0)
}
} else { // tinted
if rotated { // tinted & rotated
C.al_draw_tinted_rotated_bitmap(b.bitmap, options.Tint.color, centerX, centerY, C.float(left), C.float(top), C.float(options.Rotation.Angle), 0)
} else {
C.al_draw_tinted_bitmap(b.bitmap, options.Tint.color, C.float(left), C.float(top), 0)
}
}
}
}
// Sub creates a sub-bitmap of the original bitmap
func (b *Bitmap) Sub(x, y, w, h int) *Bitmap {
var sub = C.al_create_sub_bitmap(b.bitmap, C.int(x), C.int(y), C.int(w), C.int(h))
if sub == nil {
return nil
}
var bmp = &Bitmap{sub, w, h, nil}
b.subs = append(b.subs, bmp)
return bmp
}
// Subs returns the slice of sub-bitmaps
func (b *Bitmap) Subs() []*Bitmap {
return b.subs
}
func (b *Bitmap) Width() int {
return b.width
}
func (b *Bitmap) Height() int {
return b.height
}
func (b *Bitmap) IsVideo() bool {
return C.al_get_bitmap_flags(b.bitmap)&C.ALLEGRO_VIDEO_BITMAP == C.ALLEGRO_VIDEO_BITMAP
}
func (b *Bitmap) Image() image.Image {
im := image.NewRGBA(image.Rect(0, 0, b.width, b.height))
region := C.al_lock_bitmap(b.bitmap, C.ALLEGRO_PIXEL_FORMAT_ABGR_8888, C.ALLEGRO_LOCK_READONLY)
if region == nil {
return nil
}
defer C.al_unlock_bitmap(b.bitmap)
src := (*[1 << 30]uint8)(region.data)
dst := im.Pix
var srcOff, dstOff int
for y := 0; y < b.height; y++ {
copy(dst[dstOff:], src[srcOff:srcOff+b.width*4])
srcOff += int(region.pitch)
dstOff += im.Stride
}
return im
}
func (b *Bitmap) SetAsTarget() {
C.al_set_target_bitmap(b.bitmap)
}
// Destroy destroys the bitmap
func (b *Bitmap) Destroy() {
var bmp = b.bitmap
if bmp == nil {
return
}
b.bitmap = nil
for _, sub := range b.subs {
sub.Destroy()
}
C.al_destroy_bitmap(bmp)
}

6
c.go Normal file
View File

@ -0,0 +1,6 @@
// +build !windows
package allg5
// #cgo pkg-config: allegro-5 allegro_audio-5 allegro_font-5 allegro_image-5 allegro_primitives-5 allegro_ttf-5
import "C"

6
c_windows.go Normal file
View File

@ -0,0 +1,6 @@
// +build windows,!static
package allg5
// #cgo LDFLAGS: -lallegro -lallegro_audio -lallegro_font -lallegro_image -lallegro_primitives -lallegro_ttf
import "C"

6
c_windows_static.go Normal file
View File

@ -0,0 +1,6 @@
// +build windows,static
package allg5
// #cgo LDFLAGS: -lallegro_monolith-static -static -ljpeg -ldumb -lFLAC -lfreetype -lvorbisfile -lvorbis -logg -lphysfs -lpng16 -lzlib -luuid -lkernel32 -lwinmm -lpsapi -lopengl32 -lglu32 -luser32 -lcomdlg32 -lgdi32 -lshell32 -lole32 -ladvapi32 -lws2_32 -lshlwapi -lstdc++ -lwebp
import "C"

36
color.go Normal file
View File

@ -0,0 +1,36 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
import "image/color"
var _ color.Color = &Color{}
type Color struct {
color C.ALLEGRO_COLOR
}
func NewColor(r, g, b byte) Color {
return Color{C.al_map_rgb(C.uchar(r), C.uchar(g), C.uchar(b))}
}
func NewColorAlpha(r, g, b, a byte) Color {
return Color{C.al_map_rgba(C.uchar(r), C.uchar(g), C.uchar(b), C.uchar(a))}
}
func NewColorGo(c color.Color) Color {
r, g, b, a := c.RGBA()
return Color{C.al_premul_rgba(C.uchar(r>>8), C.uchar(g>>8), C.uchar(b>>8), C.uchar(a>>8))}
}
// RGBA implements the color.Color interface.
func (c Color) RGBA() (r, g, b, a uint32) {
var cr, cg, cb, ca C.uchar
C.al_unmap_rgba(c.color, &cr, &cg, &cb, &ca)
a = uint32(ca)
r = uint32(cr) * a
g = uint32(cg) * a
b = uint32(cb) * a
a *= a
return
}

129
display.go Normal file
View File

@ -0,0 +1,129 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
import (
"errors"
"unsafe"
)
// Display represents a display
type Display struct {
display *C.ALLEGRO_DISPLAY
}
type NewDisplayOptions struct {
Fullscreen bool
Resizable bool
Windowed bool
Maximized bool
Frameless bool
Vsync bool
Shaders bool
OpenGL bool
}
// NewDisplay creates a display
func NewDisplay(width, height int, options NewDisplayOptions) (*Display, error) {
var flags C.int = C.ALLEGRO_WINDOWED
if options.Fullscreen {
if options.Windowed {
flags |= C.ALLEGRO_FULLSCREEN_WINDOW
} else {
flags = C.ALLEGRO_FULLSCREEN
}
} else if options.Frameless {
flags |= C.ALLEGRO_FRAMELESS
}
if options.Resizable {
flags |= C.ALLEGRO_RESIZABLE
if options.Maximized {
flags |= C.ALLEGRO_MAXIMIZED
}
}
if options.Vsync {
C.al_set_new_display_option(C.ALLEGRO_VSYNC, 1, C.ALLEGRO_SUGGEST)
}
if options.OpenGL {
flags |= C.ALLEGRO_OPENGL
}
if options.Shaders {
flags |= C.ALLEGRO_PROGRAMMABLE_PIPELINE
}
C.al_set_new_display_flags(flags)
d := C.al_create_display(C.int(width), C.int(height))
if d == nil {
return nil, errors.New("error creating display")
}
return &Display{d}, nil
}
// Flip flips the buffer to the display
func (d *Display) Flip() {
C.al_flip_display()
}
func (d *Display) Width() int {
return int(C.al_get_display_width(d.display))
}
func (d *Display) Height() int {
return int(C.al_get_display_height(d.display))
}
func (d *Display) Position() (int, int) {
var x, y C.int
C.al_get_window_position(d.display, &x, &y)
return int(x), int(y)
}
func (d *Display) Resize(w, h int) {
C.al_resize_display(d.display, C.int(w), C.int(h))
}
func (d *Display) SetAsTarget() {
C.al_set_target_backbuffer(d.display)
}
func (d *Display) SetIcon(i *Bitmap) {
C.al_set_display_icon(d.display, i.bitmap)
}
func (d *Display) SetMouseCursor(c MouseCursor) {
C.al_set_system_mouse_cursor(d.display, C.ALLEGRO_SYSTEM_MOUSE_CURSOR(c))
}
func (d *Display) SetMousePosition(x, y int) {
C.al_set_mouse_xy(d.display, C.int(x), C.int(y))
}
func (d *Display) SetPosition(x, y int) {
C.al_set_window_position(d.display, C.int(x), C.int(y))
}
func (d *Display) SetWindowTitle(title string) {
t := C.CString(title)
defer C.free(unsafe.Pointer(t))
C.al_set_window_title(d.display, t)
}
func (d *Display) Target() *Bitmap {
return &Bitmap{C.al_get_backbuffer(d.display), d.Width(), d.Height(), nil}
}
// Destroy destroys the display
func (d *Display) Destroy() {
C.al_destroy_display(d.display)
}
func CurrentTarget() *Bitmap {
var bmp = C.al_get_target_bitmap()
return &Bitmap{bmp, int(C.al_get_bitmap_width(bmp)), int(C.al_get_bitmap_height(bmp)), nil}
}
func SetNewWindowTitle(title string) {
t := C.CString(title)
defer C.free(unsafe.Pointer(t))
C.al_set_new_window_title(t)
}

265
event.go Normal file
View File

@ -0,0 +1,265 @@
package allg5
/*
#define ALLEGRO_KCM_AUDIO_SRC
#include <allegro5/allegro.h>
#include <allegro5/allegro_audio.h>
#define USER_EVENT_TYPE ALLEGRO_GET_EVENT_TYPE('u', 's', 'e', 'r')
void init_user_event(ALLEGRO_EVENT* e)
{
e->user.type = USER_EVENT_TYPE;
}
*/
import "C"
import (
"errors"
"unsafe"
)
type EventQueue struct {
queue *C.ALLEGRO_EVENT_QUEUE
}
type Event interface {
Stamp() float64
}
type EventBase struct {
stamp float64
}
func (eb EventBase) Stamp() float64 {
return eb.stamp
}
type DisplayCloseEvent struct {
EventBase
}
type DisplayResizeEvent struct {
EventBase
X, Y int
Width int
Height int
}
type DisplayOrientation int
const (
DisplayOrientation0Degrees DisplayOrientation = iota
DisplayOrientation90Degrees
DisplayOrientation180Degrees
DisplayOrientation270Degrees
DisplayOrientationFaceUp
DisplayOrientationFaceDown
)
func toDisplayOrientation(o C.int) DisplayOrientation {
switch o {
case C.ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES:
return DisplayOrientation0Degrees
case C.ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES:
return DisplayOrientation90Degrees
case C.ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES:
return DisplayOrientation180Degrees
case C.ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES:
return DisplayOrientation270Degrees
case C.ALLEGRO_DISPLAY_ORIENTATION_FACE_UP:
return DisplayOrientationFaceUp
case C.ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN:
return DisplayOrientationFaceDown
default:
panic("not supported")
}
}
type DisplayOrientationEvent struct {
EventBase
Orientation DisplayOrientation
}
type KeyEvent struct {
EventBase
KeyCode Key
Display *Display
}
type KeyCharEvent struct {
KeyEvent
UnicodeCharacter rune
Modifiers KeyMod
Repeat bool
}
type KeyDownEvent struct {
KeyEvent
}
type KeyUpEvent struct {
KeyEvent
}
type MouseButtonDownEvent struct {
MouseEvent
Button MouseButton
Pressure float32
}
type MouseButtonUpEvent struct {
MouseEvent
Button MouseButton
Pressure float32
}
type MouseEnterEvent struct {
MouseEvent
}
type MouseEvent struct {
EventBase
X, Y int
Z, W int
Display *Display
}
type MouseLeaveEvent struct {
MouseEvent
}
type MouseMoveEvent struct {
MouseEvent
DeltaX, DeltaY int
DeltaZ, DeltaW int
Pressure float32
}
type RecorderFragmentEvent struct {
EventBase
Buffer unsafe.Pointer
Samples int
}
type UserEvent struct {
EventBase
}
type UserEventSource struct {
source *C.ALLEGRO_EVENT_SOURCE
}
func NewEventQueue() (*EventQueue, error) {
q := C.al_create_event_queue()
if q == nil {
return nil, errors.New("unable to create event queue")
}
return &EventQueue{q}, nil
}
func (eq *EventQueue) register(source *C.ALLEGRO_EVENT_SOURCE) {
C.al_register_event_source(eq.queue, source)
}
func (eq *EventQueue) RegisterDisplay(d *Display) {
eq.register(C.al_get_display_event_source(d.display))
}
func (eq *EventQueue) RegisterMouse() {
eq.register(C.al_get_mouse_event_source())
}
func (eq *EventQueue) RegisterKeyboard() {
eq.register(C.al_get_keyboard_event_source())
}
func (eq *EventQueue) RegisterRecorder(rec *Recorder) {
eq.register(C.al_get_audio_recorder_event_source(rec.recorder))
}
func (eq *EventQueue) RegisterUserEvents(source *UserEventSource) {
eq.register(source.source)
}
func (eq *EventQueue) mapEvent(e *C.ALLEGRO_EVENT) Event {
any := (*C.ALLEGRO_ANY_EVENT)(unsafe.Pointer(e))
eb := EventBase{float64(any.timestamp)}
switch any._type {
case C.ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT:
recorder := (*C.ALLEGRO_AUDIO_RECORDER_EVENT)(unsafe.Pointer(e))
return &RecorderFragmentEvent{eb, unsafe.Pointer(recorder.buffer), int(recorder.samples)}
case C.ALLEGRO_EVENT_DISPLAY_CLOSE:
return &DisplayCloseEvent{eb}
case C.ALLEGRO_EVENT_DISPLAY_ORIENTATION:
display := (*C.ALLEGRO_DISPLAY_EVENT)(unsafe.Pointer(e))
return &DisplayOrientationEvent{eb, toDisplayOrientation(display.orientation)}
case C.ALLEGRO_EVENT_DISPLAY_RESIZE:
display := (*C.ALLEGRO_DISPLAY_EVENT)(unsafe.Pointer(e))
C.al_acknowledge_resize(display.source)
return &DisplayResizeEvent{eb, int(display.x), int(display.y), int(display.width), int(display.height)}
case C.ALLEGRO_EVENT_MOUSE_AXES:
mouse := (*C.ALLEGRO_MOUSE_EVENT)(unsafe.Pointer(e))
return &MouseMoveEvent{MouseEvent{eb, int(mouse.x), int(mouse.y), int(mouse.z), int(mouse.w), nil}, int(mouse.dx), int(mouse.dy), int(mouse.dz), int(mouse.dw), float32(mouse.pressure)}
case C.ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
mouse := (*C.ALLEGRO_MOUSE_EVENT)(unsafe.Pointer(e))
return &MouseButtonDownEvent{MouseEvent{eb, int(mouse.x), int(mouse.y), int(mouse.z), int(mouse.w), nil}, MouseButton(mouse.button), float32(mouse.pressure)}
case C.ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY:
mouse := (*C.ALLEGRO_MOUSE_EVENT)(unsafe.Pointer(e))
return &MouseEnterEvent{MouseEvent{eb, int(mouse.x), int(mouse.y), int(mouse.z), int(mouse.w), nil}}
case C.ALLEGRO_EVENT_MOUSE_BUTTON_UP:
mouse := (*C.ALLEGRO_MOUSE_EVENT)(unsafe.Pointer(e))
return &MouseButtonUpEvent{MouseEvent{eb, int(mouse.x), int(mouse.y), int(mouse.z), int(mouse.w), nil}, MouseButton(mouse.button), float32(mouse.pressure)}
case C.ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
mouse := (*C.ALLEGRO_MOUSE_EVENT)(unsafe.Pointer(e))
return &MouseLeaveEvent{MouseEvent{eb, int(mouse.x), int(mouse.y), int(mouse.z), int(mouse.w), nil}}
case C.ALLEGRO_EVENT_KEY_DOWN:
key := (*C.ALLEGRO_KEYBOARD_EVENT)(unsafe.Pointer(e))
return &KeyDownEvent{KeyEvent{eb, Key(key.keycode), nil}}
case C.ALLEGRO_EVENT_KEY_UP:
key := (*C.ALLEGRO_KEYBOARD_EVENT)(unsafe.Pointer(e))
return &KeyUpEvent{KeyEvent{eb, Key(key.keycode), nil}}
case C.ALLEGRO_EVENT_KEY_CHAR:
key := (*C.ALLEGRO_KEYBOARD_EVENT)(unsafe.Pointer(e))
return &KeyCharEvent{KeyEvent{eb, Key(key.keycode), nil}, rune(key.unichar), KeyMod(key.modifiers), bool(key.repeat)}
case C.USER_EVENT_TYPE:
return &UserEvent{eb}
}
return nil
}
func (eq *EventQueue) Get() Event {
var event C.ALLEGRO_EVENT
if !bool(C.al_get_next_event(eq.queue, &event)) {
return nil
}
return eq.mapEvent(&event)
}
func (eq *EventQueue) GetWait() Event {
var event C.ALLEGRO_EVENT
C.al_wait_for_event(eq.queue, &event)
return eq.mapEvent(&event)
}
func (eq *EventQueue) Destroy() {
C.al_destroy_event_queue(eq.queue)
}
func NewUserEventSource() *UserEventSource {
s := (*C.ALLEGRO_EVENT_SOURCE)(C.malloc(C.sizeof_ALLEGRO_EVENT_SOURCE))
source := &UserEventSource{s}
C.al_init_user_event_source(s)
return source
}
func (s *UserEventSource) Destroy() {
C.al_destroy_user_event_source(s.source)
C.free(unsafe.Pointer(s.source))
}
func (s *UserEventSource) EmitEvent() bool {
e := (*C.ALLEGRO_EVENT)(C.malloc(C.sizeof_ALLEGRO_EVENT))
C.init_user_event(e)
return bool(C.al_emit_user_event(s.source, e, nil))
}

23
flagmut.go Normal file
View File

@ -0,0 +1,23 @@
package allg5
// #include <stdlib.h>
import "C"
type FlagMutation interface {
Set(f NewBitmapFlag)
Unset(f NewBitmapFlag)
}
type flagMut struct {
flg C.int
}
func (m *flagMut) Set(f NewBitmapFlag) {
m.flg |= C.int(f)
}
func (m *flagMut) Unset(f NewBitmapFlag) {
if m.flg&C.int(f) == C.int(f) {
m.flg ^= C.int(f)
}
}

107
font.go Normal file
View File

@ -0,0 +1,107 @@
package allg5
// #include <allegro5/allegro.h>
// #include <allegro5/allegro_font.h>
// #include <allegro5/allegro_ttf.h>
import "C"
import (
"fmt"
"unsafe"
)
type Font struct {
font *C.ALLEGRO_FONT
hght float32
asc float32
desc float32
}
type HorizontalAlignment int
const (
AlignLeft HorizontalAlignment = iota
AlignCenter
AlignRight
)
func LoadTTFFont(path string, size int) (*Font, error) {
p := C.CString(path)
defer C.free(unsafe.Pointer(p))
f := C.al_load_ttf_font(p, C.int(size), 0)
if f == nil {
return nil, fmt.Errorf("unable to load ttf font '%s'", path)
}
return &Font{f, 0, 0, 0}, nil
}
func (f *Font) drawFlags(a HorizontalAlignment) C.int {
switch a {
case AlignLeft:
return C.ALLEGRO_ALIGN_LEFT
case AlignCenter:
return C.ALLEGRO_ALIGN_CENTRE
case AlignRight:
return C.ALLEGRO_ALIGN_RIGHT
}
return C.ALLEGRO_ALIGN_LEFT
}
func (f *Font) Draw(left, top float32, color Color, align HorizontalAlignment, text string) {
t := C.CString(text)
defer C.free(unsafe.Pointer(t))
flags := f.drawFlags(align)
C.al_draw_text(f.font, color.color, C.float(left), C.float(top), flags, t)
}
// Ascent returns the ascent of the font
func (f *Font) Ascent() float32 {
if f.asc == 0 {
f.asc = float32(C.al_get_font_ascent(f.font))
}
return f.asc
}
// Descent returns the descent of the font.
func (f *Font) Descent() float32 {
if f.desc == 0 {
f.desc = float32(C.al_get_font_descent(f.font))
}
return f.desc
}
// Height returns the height of the font
func (f *Font) Height() float32 {
if f.hght == 0 {
f.hght = f.Ascent() + f.Descent()
}
return f.hght
}
// TextDimensions returns the bounding box of the rendered text.
func (f *Font) TextDimensions(text string) (x, y, w, h float32) {
t := C.CString(text)
defer C.free(unsafe.Pointer(t))
var bbx, bby, bbw, bbh C.int
C.al_get_text_dimensions(f.font, t, &bbx, &bby, &bbw, &bbh)
x = float32(bbx)
y = float32(bby)
w = float32(bbw)
h = float32(bbh)
return
}
// TextWidth returns the width of the rendered text.
func (f *Font) TextWidth(text string) float32 {
t := C.CString(text)
defer C.free(unsafe.Pointer(t))
return float32(C.al_get_text_width(f.font, t))
}
func (f *Font) Destroy() {
C.al_destroy_font(f.font)
}

26
graphics.go Normal file
View File

@ -0,0 +1,26 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
// BitmapFlag is extra information provided for creating a bitmap
type BitmapFlag int
const (
// BitmapFlagLinearScaleDown enables linear scaling when scaling down. Gives better results when combined with BitmapFlagMipMap
BitmapFlagLinearScaleDown BitmapFlag = C.ALLEGRO_MIN_LINEAR
// BitmapFlagLinearScaleUp enables linear scaling when scaling up.
BitmapFlagLinearScaleUp = C.ALLEGRO_MAG_LINEAR
// BitmapFlagMipMap enables mipmaps for drawing a scaled down version. Bitmap must square and its sides must be a power of two.
BitmapFlagMipMap = C.ALLEGRO_MIPMAP
)
// ClearToColor clears the target bitmap to the color
func ClearToColor(c Color) {
C.al_clear_to_color(c.color)
}
// SetNewBitmapFlags sets the default bitmap flags for a newly created bitmap
func SetNewBitmapFlags(flags BitmapFlag) {
C.al_set_new_bitmap_flags(C.int(flags))
}

188
keyboard.go Normal file
View File

@ -0,0 +1,188 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
type Key int
const (
KeyA Key = 1
KeyB = 2
KeyC = 3
KeyD = 4
KeyE = 5
KeyF = 6
KeyG = 7
KeyH = 8
KeyI = 9
KeyJ = 10
KeyK = 11
KeyL = 12
KeyM = 13
KeyN = 14
KeyO = 15
KeyP = 16
KeyQ = 17
KeyR = 18
KeyS = 19
KeyT = 20
KeyU = 21
KeyV = 22
KeyW = 23
KeyX = 24
KeyY = 25
KeyZ = 26
Key0 = 27
Key1 = 28
Key2 = 29
Key3 = 30
Key4 = 31
Key5 = 32
Key6 = 33
Key7 = 34
Key8 = 35
Key9 = 36
KeyPad0 = 37
KeyPad1 = 38
KeyPad2 = 39
KeyPad3 = 40
KeyPad4 = 41
KeyPad5 = 42
KeyPad6 = 43
KeyPad7 = 44
KeyPad8 = 45
KeyPad9 = 46
KeyF1 = 47
KeyF2 = 48
KeyF3 = 49
KeyF4 = 50
KeyF5 = 51
KeyF6 = 52
KeyF7 = 53
KeyF8 = 54
KeyF9 = 55
KeyF10 = 56
KeyF11 = 57
KeyF12 = 58
KeyEscape = 59
KeyTilde = 60
KeyMinus = 61
KeyEquals = 62
KeyBackspace = 63
KeyTab = 64
KeyOpenBrace = 65
KeyCloseBrace = 66
KeyEnter = 67
KeySemicolon = 68
KeyQuote = 69
KeyBackslash = 70
KeyBackslash2 = 71 /* DirectInput calls this DIK_OEM_102: "< > | on UK/Germany keyboards" */
KeyComma = 72
KeyFullstop = 73
KeySlash = 74
KeySpace = 75
KeyInsert = 76
KeyDelete = 77
KeyHome = 78
KeyEnd = 79
KeyPageUp = 80
KeyPageDown = 81
KeyLeft = 82
KeyRight = 83
KeyUp = 84
KeyDown = 85
KeyPadSlash = 86
KeyPadAsterisk = 87
KeyPadMinus = 88
KeyPadPlus = 89
KeyPadDelete = 90
KeyPadEnter = 91
KeyPrintScreen = 92
KeyPause = 93
KeyAbntC1 = 94
KeyYen = 95
KeyKana = 96
KeyConvert = 97
KeyNoConvert = 98
KeyAt = 99
KeyCircumflex = 100
KeyColon2 = 101
KeyKanji = 102
KeyPadEquals = 103 /* MacOS X */
KeyBackQuote = 104 /* MacOS X */
KeySemicolon2 = 105 /* MacOS X -- TODO: ask lillo what this should be */
KeyCommand = 106 /* MacOS X */
KeyBack = 107 /* Android back key */
KeyVolumeUp = 108
KeyVolumeDown = 109
KeySearch = 110
KeyDPadCenter = 111
KeyButtonX = 112
KeyButtonY = 113
KeyDPadUp = 114
KeyDPadDown = 115
KeyDPadLeft = 116
KeyDPadRight = 117
KeySelect = 118
KeyStart = 119
KeyButtonL1 = 120
KeyButtonR1 = 121
KeyButtonL2 = 122
KeyButtonR2 = 123
KeyButtonA = 124
KeyButtonB = 125
KeyThumbL = 126
KeyThumbR = 127
KeyUnknown = 128
KeyModifiers = 215
KeyLShift = 215
KeyRShift = 216
KeyLCtrl = 217
KeyRCtrl = 218
KeyAlt = 219
KeyAltGr = 220
KeyLWin = 221
KeyRWin = 222
KeyMenu = 223
KeyScrollLock = 224
KeyNumLock = 225
KeyCapsLock = 226
)
type KeyMod uint
const (
KeyModShift KeyMod = 0x00001
KeyModCtrl = 0x00002
KeyModAlt = 0x00004
KeyModLWin = 0x00008
KeyModRWin = 0x00010
KeyModMenu = 0x00020
KeyModAltGr = 0x00040
KeyModCommand = 0x00080
KeyModScrollLock = 0x00100
KeyModNumlock = 0x00200
KeyModCapsLock = 0x00400
KeyModInaltseq = 0x00800
KeyModAccent1 = 0x01000
KeyModAccent2 = 0x02000
KeyModAccent3 = 0x04000
KeyModAccent4 = 0x08000
)
func IsKeyDown(k Key) bool {
var state C.ALLEGRO_KEYBOARD_STATE
C.al_get_keyboard_state(&state)
return bool(C.al_key_down(&state, C.int(k)))
}
func IsAnyKeyDown(keys ...Key) bool {
var state C.ALLEGRO_KEYBOARD_STATE
C.al_get_keyboard_state(&state)
for _, k := range keys {
if bool(C.al_key_down(&state, C.int(k))) {
return true
}
}
return false
}

34
monitor.go Normal file
View File

@ -0,0 +1,34 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
type Monitor struct {
X1, Y1 int
X2, Y2 int
}
func monitor(m *C.ALLEGRO_MONITOR_INFO) Monitor {
return Monitor{int(m.x1), int(m.y1), int(m.x2), int(m.y2)}
}
func DefaultMonitor() Monitor {
var m C.ALLEGRO_MONITOR_INFO
C.al_get_monitor_info(C.ALLEGRO_DEFAULT_DISPLAY_ADAPTER, &m)
return monitor(&m)
}
func Monitors() []Monitor {
var n = NumberOfVideoAdapters()
var mons []Monitor
var m C.ALLEGRO_MONITOR_INFO
for i := 0; i < n; i++ {
C.al_get_monitor_info(C.int(i), &m)
mons = append(mons, monitor(&m))
}
return mons
}
func NumberOfVideoAdapters() int {
return int(C.al_get_num_video_adapters())
}

54
mouse.go Normal file
View File

@ -0,0 +1,54 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
type MouseButton uint
const (
MouseButtonLeft MouseButton = 1
MouseButtonRight = 2
MouseButtonMiddle = 3
)
type MouseCursor uint
const (
MouseCursorNone MouseCursor = 0
MouseCursorDefault = 1
MouseCursorArrow = 2
MouseCursorBusy = 3
MouseCursorQuestion = 4
MouseCursorEdit = 5
MouseCursorMove = 6
MouseCursorResizeN = 7
MouseCursorResizeW = 8
MouseCursorResizeS = 9
MouseCursorResizeE = 10
MouseCursorResizeNW = 11
MouseCursorResizeSW = 12
MouseCursorResizeSE = 13
MouseCursorResizeNE = 14
MouseCursorProgress = 15
MouseCursorPrecision = 16
MouseCursorLink = 17
MouseCursorAltSelect = 18
MouseCursorUnavailable = 19
)
func IsMouseButtonDown(b MouseButton) bool {
var state C.ALLEGRO_MOUSE_STATE
C.al_get_mouse_state(&state)
return bool(C.al_mouse_button_down(&state, C.int(b)))
}
func IsAnyMouseButtonDown(buttons ...MouseButton) bool {
var state C.ALLEGRO_MOUSE_STATE
C.al_get_mouse_state(&state)
for _, b := range buttons {
if bool(C.al_mouse_button_down(&state, C.int(b))) {
return true
}
}
return false
}

31
newbitmapflag.go Normal file
View File

@ -0,0 +1,31 @@
package allg5
// #include <allegro5/allegro.h>
import "C"
type NewBitmapFlag int
const (
NewBitmapFlagMemoryBitmap = NewBitmapFlag(C.ALLEGRO_MEMORY_BITMAP)
NewBitmapFlagVideoBitmap = NewBitmapFlag(C.ALLEGRO_VIDEO_BITMAP)
NewBitmapFlagMinLinear = NewBitmapFlag(C.ALLEGRO_MIN_LINEAR)
)
type NewBitmapFlagsCapture struct {
cap C.int
}
func CaptureNewBitmapFlags() *NewBitmapFlagsCapture {
var cap = C.al_get_new_bitmap_flags()
return &NewBitmapFlagsCapture{cap}
}
func (c *NewBitmapFlagsCapture) Mutate(mut func(FlagMutation)) {
var m = &flagMut{c.cap}
mut(m)
C.al_set_new_bitmap_flags(m.flg)
}
func (c *NewBitmapFlagsCapture) Revert() {
C.al_set_new_bitmap_flags(c.cap)
}

12
platform_windows.go Normal file
View File

@ -0,0 +1,12 @@
// +build windows
package allg5
// #include <allegro5/allegro.h>
// #include <allegro5/allegro_windows.h>
import "C"
import "unsafe"
func (d *Display) WindowHandle() unsafe.Pointer {
return unsafe.Pointer(C.al_get_win_window_handle(d.display))
}

30
primitives.go Normal file
View File

@ -0,0 +1,30 @@
package allg5
// #include <allegro5/allegro.h>
// #include <allegro5/allegro_primitives.h>
import "C"
import "unsafe"
func DrawFilledRectangle(x1, y1, x2, y2 float32, c Color) {
C.al_draw_filled_rectangle(C.float(x1), C.float(y1), C.float(x2), C.float(y2), c.color)
}
func DrawFilledTriangle(x1, y1, x2, y2, x3, y3 float32, c Color) {
C.al_draw_filled_triangle(C.float(x1), C.float(y1), C.float(x2), C.float(y2), C.float(x3), C.float(y3), c.color)
}
func DrawLine(x1, y1, x2, y2 float32, c Color, thickness float32) {
C.al_draw_line(C.float(x1), C.float(y1), C.float(x2), C.float(y2), c.color, C.float(thickness))
}
func DrawPolyline(vertices []float32, c Color, thickness float32) {
C.al_draw_polyline((*C.float)(unsafe.Pointer(&vertices[0])), 8, C.int(len(vertices)>>1), C.ALLEGRO_LINE_JOIN_ROUND, C.ALLEGRO_LINE_CAP_ROUND, c.color, C.float(thickness), 1)
}
func DrawRectangle(x1, y1, x2, y2 float32, c Color, thickness float32) {
C.al_draw_rectangle(C.float(x1), C.float(y1), C.float(x2), C.float(y2), c.color, C.float(thickness))
}
func DrawTriangle(x1, y1, x2, y2, x3, y3 float32, c Color, thickness float32) {
C.al_draw_triangle(C.float(x1), C.float(y1), C.float(x2), C.float(y2), C.float(x3), C.float(y3), c.color, C.float(thickness))
}

66
system.go Normal file
View File

@ -0,0 +1,66 @@
package allg5
/*
#define ALLEGRO_KCM_AUDIO_SRC
#include <allegro5/allegro.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_ttf.h>
bool init() {
return al_init();
}
*/
import "C"
import (
"errors"
"runtime"
)
func init() {
runtime.LockOSThread()
}
type InitConfig struct {
Audio bool
Font bool
Image bool
Primitives bool
Keyboard bool
Mouse bool
}
var InitAll = InitConfig{true, true, true, true, true, true}
// Init initializes the Allegro system
func Init(config InitConfig) error {
if !bool(C.init()) {
return errors.New("failed to initialize Allegro")
}
if config.Audio && !bool(C.al_install_audio()) {
return errors.New("failed to initialize audio addon")
}
if config.Font && !bool(C.al_init_font_addon()) {
return errors.New("failed to initialize font addon")
}
if config.Font && !bool(C.al_init_ttf_addon()) {
return errors.New("failed to initialize ttf addon")
}
if config.Image && !bool(C.al_init_image_addon()) {
return errors.New("failed to initialize image addon")
}
if config.Primitives && !bool(C.al_init_primitives_addon()) {
return errors.New("failed to initialize primitives addon")
}
if config.Keyboard && !bool(C.al_install_keyboard()) {
return errors.New("failed to install keyboard")
}
if config.Mouse && !bool(C.al_install_mouse()) {
return errors.New("failed to install mouse")
}
return nil
}