Skip to content

Instantly share code, notes, and snippets.

@jemc
Last active September 5, 2021 02:03
Show Gist options
  • Save jemc/b5744165ae4ff7d1adb49cd2854f43ce to your computer and use it in GitHub Desktop.
Save jemc/b5744165ae4ff7d1adb49cd2854f43ce to your computer and use it in GitHub Desktop.
pony-sdl-wrapper
*.so
*.o
TAGS
pony-sdl-example

pony-sdl-example

This is a work in progress / experiment to show feasibility.

use "collections"
actor Main
new create(env: Env) =>
let ui = UI("Pony SDL Example")
// Create a grid of squares in a gradient, with the upper-left being black,
// the lower-left being fully red, the upper-right being blue, and the
// lower-right being the mix of them (magenta).
// The colors of each square will do an independent random walk over time.
let size: USize = 40
let window_width: USize = 640
let window_height: USize = 480
let x_count = window_width / size
let y_count = window_height / size
ui.access({(ui: UI ref) =>
for x_index in Range(0, x_count) do
for y_index in Range(0, y_count) do
ui.renderables.push(
RenderableSquareWithRandomWalkingColor(
(x_index * size).i32(),
(y_index * size).i32(),
size.i32(),
RGBA(
((y_index * 0xff) / y_count).u8(),
0,
((x_index * 0xff) / x_count).u8(),
0xff
)
)
)
end
end
} val)
.PHONY: default
default: pony-sdl-example
./pony-sdl-example
pony-sdl-example: libsdlnative.so $(shell find . -name '*.pony')
ponyc -b pony-sdl-example
libsdlnative.so: sdl_native.o
CFLAGS="-O0 -ggdb3" gcc -shared -o libsdlnative.so sdl_native.o
sdl_native.o:
CFLAGS="-O0 -ggdb3" gcc -c -Wall -Werror -fpic -lSDL2 sdl_native.c
clean:
rm -f pony-sdl-example
rm -f libsdlnative.so
rm -f sdl_native.o
use "random"
trait Renderable
fun ref render_next(renderer: SDLRenderer)
class RenderableSeizureBackground is Renderable
var n: U32 = 0
fun ref render_next(renderer: SDLRenderer) =>
n = n + 1
if (n % 2) == 0 then
renderer.set_draw_color(RGBA(255, 0, 0, 0))
else
renderer.set_draw_color(RGBA(0, 0, 255, 0))
end
renderer.fill_entire()
class RenderableSquareWithRandomWalkingColor is Renderable
let _rect: SDLRect
var _color: RGBA
let _rand: Rand
new iso create(x: I32, y: I32, diameter: I32, color: RGBA) =>
_rect = SDLRect(x, y, diameter, diameter)
_color = color
_rand = Rand(color.r.u64(), color.b.u64())
fun ref render_next(renderer: SDLRenderer) =>
renderer.set_draw_color(_next_color())
renderer.fill_rect(_rect)
fun ref _next_color(): RGBA =>
var r = _color.r
var g = _color.g
var b = _color.b
if (r > 0x00) and (_rand.i8() > 0) then r = r - 1 end
if (r < 0xff) and (_rand.i8() > 0) then r = r + 1 end
if (g > 0x00) and (_rand.i8() > 0) then g = g - 1 end
if (g < 0xff) and (_rand.i8() > 0) then g = g + 1 end
if (b > 0x00) and (_rand.i8() > 0) then b = b - 1 end
if (b < 0xff) and (_rand.i8() > 0) then b = b + 1 end
_color = RGBA(r, g, b, _color.a)
use "lib:SDL2"
use "path:./"
use "lib:sdlnative"
use @SDL_Init[I32](flags: U32)
use @SDL_CreateWindow[Pointer[_SDLWindow]](title: Pointer[U8] tag, x: I32, y: I32, w: I32, h: I32, flags: U32)
use @SDL_CreateRenderer[Pointer[_SDLRenderer]](window: Pointer[_SDLWindow], index: I32, flags: U32)
use @SDL_DestroyRenderer[None](renderer: Pointer[_SDLRenderer] tag)
use @SDL_DestroyWindow[None](window: Pointer[_SDLWindow] tag)
use @SDL_GL_GetCurrentContext[Pointer[_SDLGLContext]]()
use @SDL_GL_MakeCurrent[I32](window: Pointer[_SDLWindow], context: Pointer[_SDLGLContext])
use @SDL_RenderClear[I32](renderer: Pointer[_SDLRenderer])
use @SDL_RenderPresent[None](renderer: Pointer[_SDLRenderer])
use @SDL_CreateRGBSurface[Pointer[_SDLSurface]](flags: U32, width: I32, height: I32, depth: I32, rmask: U32, gmask: U32, bmask: U32, amask: U32)
use @SDL_GetWindowSize[None](window: Pointer[_SDLWindow], width: Pointer[I32], height: Pointer[I32])
use @SDL_FreeSurface[None](surface: Pointer[_SDLSurface])
use @SDL_GetRendererOutputSize[None](renderer: Pointer[_SDLRenderer] , width: Pointer[I32], height: Pointer[I32])
use @sdl_get_surface_info[None](info: NullablePointer[SDLSurfaceInfo], surface: Pointer[_SDLSurface])
use @SDL_SetRenderDrawColor[None](renderer: Pointer[_SDLRenderer] , r: U8, g: U8, b: U8, a: U8)
use @SDL_CreateTextureFromSurface[Pointer[_SDLTexture]](renderer: Pointer[_SDLRenderer] , surface: Pointer[_SDLSurface])
use @SDL_DestroyTexture[None](texture: Pointer[_SDLTexture])
use @SDL_Quit[None]()
use @SDL_Delay[None](ms: U32)
// use @SDL_RenderCopy[None](renderer: Pointer[_SDLRenderer], texture: Pointer[_SDLTexture], a: NullablePointer[_SDLRect], b: NullablePointer[_SDLRect])
use @sdl_poll_event_type[U32]()
use @sdl_poll_event[U32](e: Pointer[_SDLEvent])
use @sdl_get_event_type[U32](e: Pointer[_SDLEvent] box)
use @new_sdl_event[Pointer[_SDLEvent]]()
use @free_sdl_event[None](e: Pointer[_SDLEvent] tag)
use @sdl_quit_event[U32]()
use @update_texture_from_surface[None](t: Pointer[_SDLTexture], s: Pointer[_SDLSurface])
use @SDL_RenderFillRect[I32](renderer: Pointer[_SDLRenderer], rect: NullablePointer[SDLRect])
primitive _SDLWindow
primitive _SDLRenderer
primitive _SDLGLContext
primitive _SDLSurface
primitive _SDLTexture
primitive _SDLEvent
struct val RGBA
var r: U8 = 0
var g: U8 = 0
var b: U8 = 0
var a: U8 = 0
new val create(r': U8, g': U8, b': U8, a': U8) =>
r = r'
g = g'
b = b'
a = a'
struct val SDLRect
var x: I32 = 0
var y: I32 = 0
var w: I32 = 0
var h: I32 = 0
new val create(x': I32, y': I32, w': I32, h': I32) =>
x = x'
y = y'
w = w'
h = h'
struct SDLSurfaceInfo
var w: I32 = 0
var h: I32 = 0
var pitch: I32 = 0
new create() => None
class SDLWindow
let _ptr: Pointer[_SDLWindow]
let _gl: Pointer[_SDLGLContext]
fun ref _get_ptr(): Pointer[_SDLWindow] => _ptr
new iso create(title: String, x: I32, y: I32, w: I32, h: I32, flags: U32) =>
_ptr = @SDL_CreateWindow(title.cstring(), x, y, w, h, flags)
_gl = @SDL_GL_GetCurrentContext()
fun _final() =>
@SDL_DestroyWindow(_ptr)
fun ref begin_behavior() =>
@SDL_GL_MakeCurrent(_ptr, _gl)
fun ref finish_behavior() =>
@SDL_GL_MakeCurrent(_ptr.create(), _gl.create()) // these are NULL pointers
class SDLRenderer
let _window: SDLWindow
let _ptr: Pointer[_SDLRenderer]
fun ref _get_ptr(): Pointer[_SDLRenderer] => _ptr
new create(window': SDLWindow, index: I32, flags: U32) =>
_window = window'
_ptr = @SDL_CreateRenderer(window'._get_ptr(), index, flags)
fun _final() =>
None // TODO: SDL_DestroyRenderer but ensure window is not finalized first
fun ref begin_behavior() => _window.begin_behavior()
fun ref finish_behavior() => _window.finish_behavior()
fun ref clear() => @SDL_RenderClear(_ptr)
fun ref present() => @SDL_RenderPresent(_ptr)
fun ref set_draw_color(color: RGBA) =>
@SDL_SetRenderDrawColor(_ptr, color.r, color.g, color.b, color.a)
fun ref fill_entire() =>
@SDL_RenderFillRect(_ptr, NullablePointer[SDLRect].none())
fun ref fill_rect(rect: SDLRect) =>
var rect' = rect
@SDL_RenderFillRect(_ptr, NullablePointer[SDLRect](rect'))
class SDLEvent
let _ptr: Pointer[_SDLEvent]
fun ref _get_ptr(): Pointer[_SDLEvent] => _ptr
new create() =>
_ptr = @new_sdl_event()
fun _final() =>
@free_sdl_event(_ptr)
fun ref poll(): Bool => @sdl_poll_event(_ptr) != 0
fun get_type(): U32 => @sdl_get_event_type(_ptr)
fun is_quit(): Bool => get_type() == 0x100
primitive Sdl
fun init_video(): U32 => 0x00000020
fun window_shown(): U32 => 0x00000004
fun renderer_accelerated(): U32 => 0x00000002
fun renderer_presentvsync(): U32 => 0x00000004
fun windowpos_undefined(): I32 =>
0x1FFF0000.op_or(0)
fun windowpos_centered(): U32 =>
0x2FFF0000.op_or(0)
fun window_allow_highdpi(): U32 => 0x00002000
fun init(flags: U32): I32 =>
@SDL_Init(flags)
fun create_rgb_surface(flags: U32, width: I32, height: I32, depth: I32, rmask: U32, gmask: U32, bmask: U32, amask: U32): Pointer[_SDLSurface] =>
@SDL_CreateRGBSurface(flags, width, height, depth, rmask, gmask, bmask, amask)
fun get_window_size(window: Pointer[_SDLWindow]): (I32, I32) =>
var width: I32 = 0
var height: I32 = 0
@SDL_GetWindowSize(window, addressof width, addressof height)
(width, height)
fun free_surface(surface: Pointer[_SDLSurface]) =>
@SDL_FreeSurface(surface)
fun get_renderer_output_size(renderer: Pointer[_SDLRenderer]): (I32, I32) =>
var width: I32 = 0
var height: I32 = 0
@SDL_GetRendererOutputSize(renderer, addressof width, addressof height)
(width, height)
fun get_surface_info(surface: Pointer[_SDLSurface]): SDLSurfaceInfo =>
let surface_info = SDLSurfaceInfo
@sdl_get_surface_info(NullablePointer[SDLSurfaceInfo](surface_info), surface)
surface_info
fun create_texture_from_surface(renderer: Pointer[_SDLRenderer], surface: Pointer[_SDLSurface]): Pointer[_SDLTexture] =>
@SDL_CreateTextureFromSurface(renderer, surface)
fun destroy_texture(texture: Pointer[_SDLTexture]) =>
@SDL_DestroyTexture(texture)
fun quit() =>
@SDL_Quit()
fun delay(ms: U32) =>
@SDL_Delay(ms)
// fun render_copy(renderer: Pointer[_SDLRenderer], texture: Pointer[_SDLTexture]) =>
// @SDL_RenderCopy(renderer, texture, NullablePointer[_SDLRect].none(), NullablePointer[_SDLRect].none())
fun poll_event_type(): U32 =>
@sdl_poll_event_type()
fun poll_event(e: Pointer[_SDLEvent]): U32 =>
@sdl_poll_event(e)
fun update_texture_from_surface(texture: Pointer[_SDLTexture], surface: Pointer[_SDLSurface]) =>
@update_texture_from_surface(texture, surface)
#include <SDL2/SDL.h>
Uint32
sdl_poll_event_type(void)
{
SDL_Event e;
SDL_PollEvent(&e);
return e.type;
}
Uint32
sdl_poll_event(SDL_Event *e)
{
return SDL_PollEvent(e);
}
Uint32
sdl_get_event_type(SDL_Event *e)
{
return e->type;
}
SDL_Event *
new_sdl_event(void)
{
return (SDL_Event *)malloc(sizeof(SDL_Event));
}
void
free_sdl_event(SDL_Event *e)
{
free(e);
}
Uint32
sdl_quit_event(void)
{
return SDL_QUIT;
}
Uint32
sdl_textureaccess_target(void)
{
return SDL_TEXTUREACCESS_TARGET;
}
// Todo pass rect to define struct
void
update_texture_from_surface(SDL_Texture *texture, SDL_Surface *surface)
{
SDL_UpdateTexture(texture, NULL, (unsigned char *)surface->pixels, surface->pitch);
}
use "time"
class UIFrameNotify is TimerNotify
let _ui: UI
new iso create(ui: UI) => _ui = ui
fun ref apply(timer: Timer, count: U64): Bool =>
_ui.frame()
true
actor UI
let _renderer: SDLRenderer
let _event: SDLEvent
let _timers: Timers
let renderables: Array[Renderable] = Array[Renderable]
new create(window_title: String) =>
Sdl.init(Sdl.init_video())
let window = SDLWindow(window_title, Sdl.windowpos_undefined(), Sdl.windowpos_undefined(), 640, 480, Sdl.window_shown() or Sdl.window_allow_highdpi())
_renderer = SDLRenderer(consume window, -1, Sdl.renderer_accelerated())
_event = SDLEvent
_timers = Timers
_timers(Timer(UIFrameNotify(this), 5_000_000, 5_000_000))
be dispose() =>
_timers.dispose()
be access(fn: {(UI ref)} val) =>
fn(this)
be frame() =>
let quit = poll()
if quit then
dispose()
else
render()
end
fun ref poll(): Bool =>
var quit: Bool = false
while _event.poll() do
if _event.is_quit() then
quit = true
end
end
quit
fun ref render() =>
_renderer.begin_behavior()
_renderer.set_draw_color(RGBA(0, 0, 0, 0xff))
_renderer.clear()
for r in renderables.values() do
r.render_next(_renderer)
end
_renderer.present()
_renderer.finish_behavior()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment