Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
# Introduction

This is an improved version of 0xe2-0x9a-0x9b's [Go-SDL](https://github.com/0xe2-0x9a-0x9b/Go-SDL)
currently mantained by neagix.
This is an improved version of neagix's improved version of 0xe2-0x9a-0x9b's [Go-SDL](https://github.com/0xe2-0x9a-0x9b/Go-SDL).

The improvements/differences are:
The improvements over/differences to neagix's version are:

* audio callback support
* downstreaming support

There is a nice and fully working PC speaker buzzer example in examples/callback.

# Known issues

The re-designed audio system supports only signed 16bit samples, but writing the others is as easy as a copy/paste.
* working event loop under Windows
* support for RWops

# Installation

Make sure you have SDL, SDL-image, SDL-mixer and SDL-ttf (all in -dev version).

Installing libraries and examples:

go get -v github.com/neagix/Go-SDL/sdl
go get -v github.com/neagix/Go-SDL/sdl/audio
go get -v github.com/asig/Go-SDL/sdl
go get -v github.com/asig/Go-SDL/ttf
go get -v github.com/asig/Go-SDL/sdl/audio


# Credits
Expand Down
13 changes: 13 additions & 0 deletions mixer/mixer.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ package mixer
import "C"
import "unsafe"

import "github.com/asig/Go-SDL/sdl"

// A music file.
type Music struct {
cmusic *C.Mix_Music
}

type cast unsafe.Pointer

// Initializes SDL_mixer. Return 0 if successful and -1 if there were
// initialization errors.
func OpenAudio(frequency int, format uint16, channels, chunksize int) int {
Expand All @@ -40,6 +44,15 @@ func LoadMUS(file string) *Music {
return &Music{cmusic}
}

// Loads a music file to use.
func LoadMUS_RW(rwOps *sdl.RWops) *Music {
cmusic := C.Mix_LoadMUS_RW((*C.SDL_RWops)(cast(rwOps.CRWops)))
if cmusic == nil {
return nil
}
return &Music{cmusic}
}

// Frees the loaded music file.
func (m *Music) Free() { C.Mix_FreeMusic(m.cmusic) }

Expand Down
81 changes: 31 additions & 50 deletions sdl/event.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,46 @@
package sdl

import "time"

var events chan interface{} = make(chan interface{})

// This channel delivers SDL events. Each object received from this channel
// has one of the following types: sdl.QuitEvent, sdl.KeyboardEvent,
// sdl.MouseButtonEvent, sdl.MouseMotionEvent, sdl.ActiveEvent,
// sdl.ResizeEvent, sdl.JoyAxisEvent, sdl.JoyButtonEvent, sdl.JoyHatEvent,
// sdl.JoyBallEvent
var Events <-chan interface{} = events

// Polling interval, in milliseconds
const poll_interval_ms = 10

// Polls SDL events in periodic intervals.
// This function does not return.
func pollEvents() {
// It is more efficient to create the event-object here once,
// rather than multiple times within the loop
// Polls all SDL events that are currently available.
func PollEvents() []interface{} {
events := make([]interface{}, 0)
event := &Event{}
for event.Poll() {
var cookedEvent interface{}
switch event.Type {
case QUIT:
cookedEvent = *(*QuitEvent)(cast(event))

for {
for event.poll() {
switch event.Type {
case QUIT:
events <- *(*QuitEvent)(cast(event))

case KEYDOWN, KEYUP:
events <- *(*KeyboardEvent)(cast(event))
case KEYDOWN, KEYUP:
cookedEvent = *(*KeyboardEvent)(cast(event))

case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
events <- *(*MouseButtonEvent)(cast(event))
case MOUSEBUTTONDOWN, MOUSEBUTTONUP:
cookedEvent = *(*MouseButtonEvent)(cast(event))

case MOUSEMOTION:
events <- *(*MouseMotionEvent)(cast(event))
case MOUSEMOTION:
cookedEvent = *(*MouseMotionEvent)(cast(event))

case JOYAXISMOTION:
events <- *(*JoyAxisEvent)(cast(event))
case JOYAXISMOTION:
cookedEvent = *(*JoyAxisEvent)(cast(event))

case JOYBUTTONDOWN, JOYBUTTONUP:
events <- *(*JoyButtonEvent)(cast(event))
case JOYBUTTONDOWN, JOYBUTTONUP:
cookedEvent = *(*JoyButtonEvent)(cast(event))

case JOYHATMOTION:
events <- *(*JoyHatEvent)(cast(event))
case JOYHATMOTION:
cookedEvent = *(*JoyHatEvent)(cast(event))

case JOYBALLMOTION:
events <- *(*JoyBallEvent)(cast(event))
case JOYBALLMOTION:
cookedEvent = *(*JoyBallEvent)(cast(event))

case ACTIVEEVENT:
events <- *(*ActiveEvent)(cast(event))
case ACTIVEEVENT:
cookedEvent = *(*ActiveEvent)(cast(event))

case VIDEORESIZE:
events <- *(*ResizeEvent)(cast(event))
}
case VIDEORESIZE:
cookedEvent = *(*ResizeEvent)(cast(event))
}

time.Sleep(poll_interval_ms * 1e6)
if cookedEvent != nil {
events = append(events, cookedEvent)
}
event = &Event{}
}
}

func init() {
go pollEvents()
return events
}
38 changes: 38 additions & 0 deletions sdl/event_generic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// +build !windows

// On Windows, events must be handled in the thread that created
// the window, which is most probably the thread that called sdl.Init().
// Therefore. the Events channel is not provided on Windows, and you
// need to set up your own ticker and call sdl.PollEvents() from the
// main thread.

package sdl

import "time"

var events chan interface{} = make(chan interface{})

// This channel delivers SDL events. Each object received from this channel
// has one of the following types: sdl.QuitEvent, sdl.KeyboardEvent,
// sdl.MouseButtonEvent, sdl.MouseMotionEvent, sdl.ActiveEvent,
// sdl.ResizeEvent, sdl.JoyAxisEvent, sdl.JoyButtonEvent, sdl.JoyHatEvent,
// sdl.JoyBallEvent
var Events <-chan interface{} = events

// Polling interval, in milliseconds
const poll_interval_ms = 10

// Polls SDL events in periodic intervals.
// This function does not return.
func pollEvents() {
for {
for _, event := range PollEvents() {
events <- event
}
time.Sleep(poll_interval_ms * 1e6)
}
}

func init() {
go pollEvents()
}
10 changes: 5 additions & 5 deletions sdl/rwops.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import (
import "C"

type RWops struct {
cRWops *C.SDL_RWops
CRWops *C.SDL_RWops

gcBytes []byte // Prevents garbage collection of memory passed to RWFromMem
}

func (s *RWops) destroy() {
s.cRWops = nil
s.CRWops = nil
s.gcBytes = nil
}

Expand All @@ -26,7 +26,7 @@ func RWFromMem(buf []byte) *RWops {

p := C.SDL_RWFromMem(unsafe.Pointer(&buf[0]), C.int(len(buf)))
var rwops RWops
rwops.cRWops = (*C.SDL_RWops)(p)
rwops.CRWops = (*C.SDL_RWops)(p)
rwops.gcBytes = buf
return &rwops

Expand All @@ -36,7 +36,7 @@ func (self *RWops) Free() {
GlobalMutex.Lock()
defer GlobalMutex.Unlock()

C.SDL_FreeRW(self.cRWops)
self.cRWops = nil
C.SDL_FreeRW(self.CRWops)
self.CRWops = nil
self.gcBytes = nil
}
4 changes: 2 additions & 2 deletions sdl/sdl.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ func Load(file string) *Surface {
func Load_RW(rwOps *RWops) *Surface {
GlobalMutex.Lock()

var screen = C.IMG_Load_RW((*C.SDL_RWops)(cast(rwOps.cRWops)), 0)
var screen = C.IMG_Load_RW((*C.SDL_RWops)(cast(rwOps.CRWops)), 0)

GlobalMutex.Unlock()

Expand Down Expand Up @@ -703,7 +703,7 @@ func GetKeyName(key Key) string {
// ======

// Polls for currently pending events
func (event *Event) poll() bool {
func (event *Event) Poll() bool {
GlobalMutex.Lock()

var ret = C.SDL_PollEvent((*C.SDL_Event)(cast(event)))
Expand Down
43 changes: 29 additions & 14 deletions ttf/ttf.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ package ttf
import "C"

import (
"github.com/neagix/Go-SDL/sdl"
"github.com/asig/Go-SDL/sdl"
"sync"
"unsafe"
)

type cast unsafe.Pointer

// The version of Go-SDL TTF bindings.
// The version descriptor changes into a new unique string
// after a semantically incompatible Go-SDL update.
Expand All @@ -43,6 +45,13 @@ func wrap(cSurface *C.SDL_Surface) *sdl.Surface {
return s
}

func wrapFont(cfont *C.TTF_Font) *Font {
if cfont == nil {
return nil
}
return &Font{cfont: cfont}
}

// A ttf or otf font.
type Font struct {
cfont *C.TTF_Font
Expand Down Expand Up @@ -75,47 +84,53 @@ func Quit() {
// Loads a font from a file at the specified point size.
func OpenFont(file string, ptsize int) *Font {
sdl.GlobalMutex.Lock()
defer sdl.GlobalMutex.Unlock()

cfile := C.CString(file)
cfont := C.TTF_OpenFont(cfile, C.int(ptsize))
C.free(unsafe.Pointer(cfile))

sdl.GlobalMutex.Unlock()
return wrapFont(cfont)
}

if cfont == nil {
return nil
}
// Loads a font from an RWops at the specified point size.
func OpenFontRW(rwOps *sdl.RWops, ptsize int) *Font {
sdl.GlobalMutex.Lock()
defer sdl.GlobalMutex.Unlock()

return &Font{cfont: cfont}
return wrapFont(C.TTF_OpenFontRW((*C.SDL_RWops)(cast(rwOps.CRWops)), 0, C.int(ptsize)))
}

// Loads a font from a file containing multiple font faces at the specified
// point size.
func OpenFontIndex(file string, ptsize, index int) *Font {
sdl.GlobalMutex.Lock()
defer sdl.GlobalMutex.Unlock()

cfile := C.CString(file)
cfont := C.TTF_OpenFontIndex(cfile, C.int(ptsize), C.long(index))
C.free(unsafe.Pointer(cfile))

sdl.GlobalMutex.Unlock()
return wrapFont(cfont)
}

if cfont == nil {
return nil
}
// Loads a font from an RWops containing multiple font faces at the specified
// point size.
func OpenFontIndexRW(rwOps *sdl.RWops, ptsize, index int) *Font {
sdl.GlobalMutex.Lock()
defer sdl.GlobalMutex.Unlock()

return &Font{cfont: cfont}
return wrapFont(C.TTF_OpenFontIndexRW((*C.SDL_RWops)(cast(rwOps.CRWops)), 0, C.int(ptsize), C.long(index)))
}

// Frees the pointer to the font.
func (f *Font) Close() {
sdl.GlobalMutex.Lock()
defer sdl.GlobalMutex.Unlock()
f.mutex.Lock()
defer f.mutex.Unlock()

C.TTF_CloseFont(f.cfont)

f.mutex.Unlock()
sdl.GlobalMutex.Unlock()
}

// Renders Latin-1 text in the specified color and returns an SDL surface. Solid
Expand Down