Convert Figma logo to code with AI

veandco logogo-sdl2

SDL2 binding for Go

2,197
218
2,197
82

Top Related Projects

9,377

Simple Directmedia Layer

10,770

Ebitengine - A dead simple 2D game engine for Go

4,448

A hand-crafted 2D game library in Go

1,559

Go bindings for GLFW 3

1,541

A pure Go game engine

Quick Overview

Go-SDL2 is a Go binding for the Simple DirectMedia Layer 2 (SDL2) library. It provides Go developers with access to SDL2's functionality for creating multimedia applications, particularly games and audio/video playback software. This project allows Go programmers to leverage SDL2's cross-platform capabilities for graphics, audio, and input handling.

Pros

  • Cross-platform compatibility (Windows, macOS, Linux, iOS, Android)
  • Comprehensive bindings for SDL2 and its extension libraries
  • Active development and community support
  • Good performance for multimedia applications

Cons

  • Requires C libraries to be installed on the system
  • Learning curve for developers new to SDL2 concepts
  • May have occasional version compatibility issues with SDL2 updates
  • Limited high-level abstractions compared to some game engines

Code Examples

  1. Creating a window and renderer:
package main

import "github.com/veandco/go-sdl2/sdl"

func main() {
    if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
        panic(err)
    }
    defer sdl.Quit()

    window, err := sdl.CreateWindow("SDL2 Example", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
        800, 600, sdl.WINDOW_SHOWN)
    if err != nil {
        panic(err)
    }
    defer window.Destroy()

    renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
    if err != nil {
        panic(err)
    }
    defer renderer.Destroy()

    // Main loop and rendering code would go here
}
  1. Handling events:
running := true
for running {
    for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
        switch t := event.(type) {
        case *sdl.QuitEvent:
            running = false
        case *sdl.KeyboardEvent:
            if t.Keysym.Sym == sdl.K_ESCAPE {
                running = false
            }
        }
    }
    // Update and render code would go here
}
  1. Drawing a rectangle:
renderer.SetDrawColor(255, 0, 0, 255)
rect := sdl.Rect{X: 300, Y: 200, W: 200, H: 200}
renderer.FillRect(&rect)
renderer.Present()

Getting Started

  1. Install SDL2 and its development libraries for your operating system.
  2. Install Go-SDL2 using:
    go get -v github.com/veandco/go-sdl2/sdl@latest
    
  3. Import the package in your Go code:
    import "github.com/veandco/go-sdl2/sdl"
    
  4. Initialize SDL2 in your main() function:
    if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
        panic(err)
    }
    defer sdl.Quit()
    
  5. Start building your application using the SDL2 functions provided by the binding.

Competitor Comparisons

9,377

Simple Directmedia Layer

Pros of SDL

  • Native C library with extensive platform support and optimizations
  • Comprehensive multimedia functionality (audio, video, input, etc.)
  • Large community and ecosystem of tools and extensions

Cons of SDL

  • Requires C programming knowledge and manual memory management
  • More complex setup and compilation process
  • Steeper learning curve for developers new to low-level graphics programming

Code Comparison

SDL (C):

SDL_Window* window = SDL_CreateWindow("SDL Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);

go-sdl2 (Go):

window, _ := sdl.CreateWindow("Go-SDL2 Example", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 640, 480, sdl.WINDOW_SHOWN)
renderer, _ := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
renderer.SetDrawColor(255, 0, 0, 255)
renderer.Clear()
renderer.Present()

The go-sdl2 library provides Go bindings for SDL, offering a more Go-idiomatic approach with simplified error handling and memory management. It allows developers to leverage SDL's capabilities while working in a higher-level language. However, it may have slightly reduced performance compared to native C SDL and might lag behind in supporting the latest SDL features.

10,770

Ebitengine - A dead simple 2D game engine for Go

Pros of Ebiten

  • Pure Go implementation, no C dependencies
  • Simpler API, easier to get started for beginners
  • Cross-platform support, including WebAssembly

Cons of Ebiten

  • Less feature-rich compared to SDL2
  • May have performance limitations for complex games
  • Smaller community and ecosystem

Code Comparison

Ebiten example:

func (g *Game) Update() error {
    // Game logic here
    return nil
}

func (g *Game) Draw(screen *ebiten.Image) {
    // Drawing logic here
}

SDL2 example:

func main() {
    window, _ := sdl.CreateWindow("SDL2 Example", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 800, 600, sdl.WINDOW_SHOWN)
    renderer, _ := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
    
    for {
        // Event handling and rendering logic here
    }
}

Ebiten offers a more straightforward approach with predefined Update and Draw methods, while SDL2 provides lower-level control over window creation and rendering. Ebiten's simplicity makes it attractive for smaller projects and beginners, while SDL2's extensive features and performance make it suitable for larger, more complex games.

4,448

A hand-crafted 2D game library in Go

Pros of Pixel

  • Pure Go implementation, easier to build and deploy
  • Simpler API, designed specifically for 2D graphics
  • Better suited for small to medium-sized 2D games and applications

Cons of Pixel

  • Less feature-rich compared to SDL2
  • Smaller community and ecosystem
  • May have performance limitations for complex projects

Code Comparison

Pixel:

win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
    Title:  "Pixel Window",
    Bounds: pixel.R(0, 0, 1024, 768),
})

SDL2:

window, err := sdl.CreateWindow("SDL2 Window", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
    800, 600, sdl.WINDOW_SHOWN)

Pixel focuses on simplicity and ease of use, while SDL2 offers more low-level control and flexibility. Pixel is a good choice for developers who want a pure Go solution and are working on 2D projects. SDL2, being a more established library, provides broader functionality and may be better suited for larger, more complex applications or those requiring cross-platform support beyond just Go.

1,559

Go bindings for GLFW 3

Pros of GLFW

  • Focused on OpenGL and Vulkan support, making it ideal for 3D graphics applications
  • Lightweight and minimalistic, with a smaller API surface compared to SDL2
  • Better multi-monitor support and more fine-grained control over window creation

Cons of GLFW

  • Limited audio and input device support compared to SDL2's extensive capabilities
  • Lacks built-in 2D rendering functions, requiring additional libraries for 2D graphics
  • Smaller community and ecosystem compared to SDL2's widespread adoption

Code Comparison

SDL2 window creation:

window, err := sdl.CreateWindow("SDL2 Window", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
    800, 600, sdl.WINDOW_SHOWN)

GLFW window creation:

if err := glfw.Init(); err != nil {
    panic(err)
}
defer glfw.Terminate()
window, err := glfw.CreateWindow(800, 600, "GLFW Window", nil, nil)

Both libraries offer straightforward window creation, but GLFW requires explicit initialization and termination. SDL2 provides more options for window positioning and flags, while GLFW's approach is more minimalistic.

1,541

A pure Go game engine

Pros of oak

  • Higher-level game development framework with built-in scene management and entity-component system
  • Simplified API for common game development tasks like collision detection and event handling
  • Includes additional utilities like pathfinding and particle systems out of the box

Cons of oak

  • Less flexible than go-sdl2 for non-game applications or low-level graphics programming
  • Smaller community and ecosystem compared to SDL2
  • May have a steeper learning curve for developers familiar with SDL2 concepts

Code Comparison

oak example:

func main() {
    oak.Add("scene",
        func(string, interface{}) {
            oak.SetViewport(800, 600)
            oak.DrawColor = color.RGBA{255, 0, 0, 255}
        },
        func() bool {
            oak.DrawRect(100, 100, 200, 200)
            return true
        },
    )
    oak.Init("scene")
}

go-sdl2 example:

func main() {
    sdl.Init(sdl.INIT_EVERYTHING)
    window, _ := sdl.CreateWindow("SDL2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 800, 600, sdl.WINDOW_SHOWN)
    renderer, _ := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
    renderer.SetDrawColor(255, 0, 0, 255)
    renderer.FillRect(&sdl.Rect{100, 100, 200, 200})
    renderer.Present()
}

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

SDL2 binding for Go Build Status Go Report Card Reviewed by Hound Financial Contributors on Open Collective

go-sdl2 is SDL2 wrapped for Go users. It enables interoperability between Go and the SDL2 library which is written in C. That means the original SDL2 installation is required for this to work. Note that the first build may take several minutes on machines that are not powerful such as Raspberry Pi.

NOTE: For the latest versions of SDL2, please use the master branch!

Table of Contents

Documentation

Getting Started

If you haven't created a Go module for your program, you can do it by making a directory called, for example, app and running the following command inside it:

go mod init app

After that you can start writing code that uses go-sdl2, for example, like the following:

// main.go
package main

import (
	"github.com/veandco/go-sdl2/sdl"
)

func main() {
	sdl.Init(sdl.INIT_EVERYTHING)
}

Then to tell Go to fetch dependencies, you can run:

go mod tidy

and then the program can be built using:

go build

After that, you can execute your program:

./app

Requirements

On Ubuntu 22.04 and above, type:
apt install libsdl2{,-image,-mixer,-ttf,-gfx}-dev

On Fedora 36 and above, type:
dnf install SDL2{,_image,_mixer,_ttf,_gfx}-devel

On Arch Linux, type:
pacman -S sdl2{,_image,_mixer,_ttf,_gfx}

On Gentoo, type:
emerge -av libsdl2 sdl2-{image,mixer,ttf,gfx}

On macOS, install SDL2 via Homebrew like so:
brew install sdl2{,_image,_mixer,_ttf,_gfx} pkg-config

On Windows,

  1. Install mingw-w64 from Mingw-builds. A 7z archive extractor software might be needed which can be downloaded here. In this example, we extract the content, which is mingw64, into C:\.
  2. Download and install SDL2-devel-[version]-mingw.zip files from https://github.com/libsdl-org/SDL/releases.
    • Extract the SDL2 folder from the archive using a tool like 7zip
    • Inside the extracted SDL2 folder, copy the i686-w64-mingw32 and/or x86_64-w64-mingw32 into mingw64 folder e.g. C:\mingw64
  3. Setup Path environment variable
    • Put mingw-w64 binaries location into system Path environment variable (e.g. C:\mingw64\bin)
  4. Close and open terminal again so the new Path environment variable takes effect. Now we should be able to run go build inside the project directory.
  5. Download and install SDL2 runtime libraries from https://github.com/libsdl-org/SDL/releases. Extract and copy the .dll file into the project directory. After that, the program should become runnable.
  6. (Optional) You can repeat Step 2 for SDL_image, SDL_mixer, SDL_ttf

Installation

To get the bindings, type:
go get -v github.com/veandco/go-sdl2/sdl
go get -v github.com/veandco/go-sdl2/img
go get -v github.com/veandco/go-sdl2/mix
go get -v github.com/veandco/go-sdl2/ttf
go get -v github.com/veandco/go-sdl2/gfx

or type this if you use Bash terminal:
go get -v github.com/veandco/go-sdl2/{sdl,img,mix,ttf}

Due to go-sdl2 being under active development, a lot of breaking changes are going to happen during v0.x. With versioning system coming to Go soon, we'll make use of semantic versioning to ensure stability in the future.

Static compilation

Since v0.3.0, it is possible to build statically against included libraries in .go-sdl2-libs. To build statically, run:

CGO_ENABLED=1 CC=gcc GOOS=linux GOARCH=amd64 go build -tags static -ldflags "-s -w"

You can also cross-compile to another OS. For example, to Windows:

CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 go build -tags static -ldflags "-s -w"

On Windows, if you would like to hide the Command Prompt window when running the statically-compiled program, you could append -H windowsgui to the -ldflags value.

For the list of OS and architecture, you can see inside the .go-sdl2-libs directory.

NOTE: If you're using the new Go Module system, you will need to refer to the master branch for now by running:

go get -v github.com/veandco/go-sdl2/sdl@master

Before building the program.

Cross-compiling

Linux to Windows

  1. Install MinGW toolchain.
    • On Arch Linux, it's simply pacman -S mingw-w64.
  2. Download the SDL2 development package for MinGW here (and the others like SDL_image, SDL_mixer, etc.. here if you use them).
  3. Extract the SDL2 development package and copy the x86_64-w64-mingw32 folder inside recursively to the system's MinGW x86_64-w64-mingw32 folder. You may also do the same for the i686-w64-mingw32 folder.
    • On Arch Linux, it's cp -r x86_64-w64-mingw32 /usr.
  4. Now you can start cross-compiling your Go program by running env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" go build -x main.go. You can change some of the parameters if you'd like to. In this example, it should produce a main.exe executable file.
  5. Before running the program, you need to put SDL2.dll from the SDL2 runtime package (For others like SDL_image, SDL_mixer, etc.., look for them here) for Windows in the same folder as your executable.
  6. Now you should be able to run the program using Wine or Windows!

macOS to Windows

  1. Install Homebrew
  2. Install MinGW through Homebrew via brew install mingw-w64
  3. Download the SDL2 development package for MinGW here (and the others like SDL_image, SDL_mixer, etc.. here if you use them).
  4. Extract the SDL2 development package and copy the x86_64-w64-mingw folder inside recursively to the system's MinGW x86_64-w64-mingw32 folder. You may also do the same for the i686-w64-mingw32 folder. The path to MinGW may be slightly different but the command should look something like cp -r x86_64-w64-mingw32 /usr/local/Cellar/mingw-w64/5.0.3/toolchain-x86_64.
  5. Now you can start cross-compiling your Go program by running env CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows CGO_LDFLAGS="-L/usr/local/Cellar/mingw-w64/5.0.3/toolchain-x86_64/x86_64-w64-mingw32/lib -lSDL2" CGO_CFLAGS="-I/usr/local/Cellar/mingw-w64/5.0.3/toolchain-x86_64/x86_64-w64-mingw32/include -D_REENTRANT" go build -x main.go. You can change some of the parameters if you'd like to. In this example, it should produce a main.exe executable file.
  6. Before running the program, you need to put SDL2.dll from the SDL2 runtime package (For others like SDL_image, SDL_mixer, etc.., look for them here) for Windows in the same folder as your executable.
  7. Now you should be able to run the program using Wine or Windows!

Linux to macOS

  1. Install macOS toolchain via osxcross
  2. Run the following build command (replace the values in parentheses):
CGO_ENABLED=1 CC=[path-to-osxcross]/target/bin/[arch]-apple-darwin[version]-clang GOOS=darwin GOARCH=[arch] go build -tags static -ldflags "-s -w" -a

Examples

NOTE: The following example is for the master branch. Please check the README of v0.4.x for the stable version.

package main

import "github.com/veandco/go-sdl2/sdl"

func main() {
	if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
		panic(err)
	}
	defer sdl.Quit()

	window, err := sdl.CreateWindow("test", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 800, 600, sdl.WINDOW_SHOWN)
	if err != nil {
		panic(err)
	}
	defer window.Destroy()

	surface, err := window.GetSurface()
	if err != nil {
		panic(err)
	}
	surface.FillRect(nil, 0)

	rect := sdl.Rect{0, 0, 200, 200}
	colour := sdl.Color{R: 255, G: 0, B: 255, A: 255} // purple
	pixel := sdl.MapRGBA(surface.Format, colour.R, colour.G, colour.B, colour.A)
	surface.FillRect(&rect, pixel)
	window.UpdateSurface()

	running := true
	for running {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch event.(type) {
			case sdl.QuitEvent: // NOTE: Please use `*sdl.QuitEvent` for `v0.4.x` (current version).
				println("Quit")
				running = false
				break
			}
		}

        sdl.Delay(33)
	}
}

There are two ways a game might be running: one that updates on user input using sdl.WaitEvent() and one that updates regardless of user input using sdl.PollEvent(). You can check the examples of those two loops here.

For more runnable examples, see https://github.com/veandco/go-sdl2-examples. You can run any of the .go files with go run.

FAQ

Why does the program not run on Windows? Try putting the runtime libraries (e.g. SDL2.dll and friends) in the same folder as your program.

Why does my program crash randomly or hang? Putting runtime.LockOSThread() at the start of your main() usually solves the problem (see SDL2 FAQ about multi-threading).

UPDATE: Recent update added a call queue system where you can put thread-sensitive code and have it called synchronously on the same OS thread. See the render_queue or render_goroutines examples from https://github.com/veandco/go-sdl2-examples to see how it works.

Why can't SDL_mixer seem to play MP3 audio file? Your installed SDL_mixer probably doesn't support MP3 file.

On macOS, this is easy to correct. First remove the faulty mixer: brew remove sdl2_mixer, then reinstall it with the MP3 option: brew install sdl2_mixer --with-flac --with-fluid-synth --with-libmikmod --with-libmodplug --with-smpeg2. If necessary, check which options you can enable with brew info sdl2_mixer. You could also try installing sdl2_mixer with mpg123 by running brew install sdl2_mixer --with-mpg123.

On Other Operating Systems, you will need to compile smpeg and SDL_mixer from source with the MP3 option enabled. You can find smpeg in the external directory of SDL_mixer. Refer to issue #148 for instructions.

Note that there seems to be a problem with SDL_mixer 2.0.2 so you can also try to revert back to 2.0.1 and see if it solves your problem

Does go-sdl2 support compiling on mobile platforms like Android and iOS? For Android, see https://github.com/veandco/go-sdl2-examples/tree/master/examples/android.

There is currently no support for iOS yet.

Why does my window not immediately render after creation? It appears the rendering subsystem needs some time to be able to present the drawn pixels. This can be workaround by adding delay using sdl.Delay() or put the rendering code inside a draw loop.

Contributors

Code Contributors

This project exists thanks to all the people who contribute. [Contribute].

Financial Contributors

Become a financial contributor and help us sustain our community. [Contribute]

Individuals

Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

License

Go-SDL2 is BSD 3-clause licensed.