Created
November 20, 2020 10:58
-
-
Save doccaico/a9a27ec452ff4a09e4b6e399171e8b77 to your computer and use it in GitHub Desktop.
Resource embedding in Nim (sdl2_nim)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import | |
| sdl2/sdl, | |
| sdl2/sdl_ttf as ttf | |
| const | |
| Title = "SDL2 App" | |
| ScreenW = 640 # Window width | |
| ScreenH = 480 # Window height | |
| WindowFlags = 0 | |
| RendererFlags = sdl.RendererAccelerated or sdl.RendererPresentVsync | |
| white = sdl.Color(r: 0xFF, g: 0xFF, b: 0xFF) | |
| black = sdl.Color(r: 0x00, g: 0x00, b: 0x00) | |
| type | |
| App = ref AppObj | |
| AppObj = object | |
| window*: sdl.Window # Window pointer | |
| renderer*: sdl.Renderer # Rendering state pointer | |
| FpsManager = ref FpsManagerObj | |
| FpsManagerObj = object | |
| counter, fps: int | |
| timer: sdl.TimerID | |
| ############## | |
| # FPSMANAGER # | |
| ############## | |
| # FPS timer | |
| # param is FpsManager casted to pointer | |
| proc fpsTimer(interval: uint32, param: pointer): uint32 {.cdecl.} = | |
| let obj = cast[FpsManager](param) | |
| obj.fps = obj.counter | |
| obj.counter = 0 | |
| return interval | |
| proc newFpsManager(): FpsManager = FpsManager(counter: 0, fps: 0, timer: 0) | |
| proc free(obj: FpsManager) = | |
| discard sdl.removeTimer(obj.timer) | |
| obj.timer = 0 | |
| proc start(obj: FpsManager) = | |
| obj.timer = sdl.addTimer(1000, fpsTimer, cast[pointer](obj)) | |
| proc count(obj: FpsManager) {.inline.} = inc(obj.counter) | |
| ########## | |
| # COMMON # | |
| ########## | |
| # Initialization sequence | |
| proc init(app: App): bool = | |
| # Init SDL | |
| if sdl.init(sdl.InitVideo or sdl.InitTimer) != 0: | |
| sdl.logCritical(sdl.LogCategoryError, | |
| "Can't initialize SDL: %s", | |
| sdl.getError()) | |
| return false | |
| # Init SDL_TTF | |
| if ttf.init() != 0: | |
| sdl.logCritical(sdl.LogCategoryError, | |
| "Can't initialize SDL_TTF: %s", | |
| ttf.getError()) | |
| # Create window | |
| app.window = sdl.createWindow( | |
| Title, | |
| sdl.WindowPosUndefined, | |
| sdl.WindowPosUndefined, | |
| ScreenW, | |
| ScreenH, | |
| WindowFlags) | |
| if app.window == nil: | |
| sdl.logCritical(sdl.LogCategoryError, | |
| "Can't create window: %s", | |
| sdl.getError()) | |
| return false | |
| # Create renderer | |
| app.renderer = sdl.createRenderer(app.window, -1, RendererFlags) | |
| if app.renderer == nil: | |
| sdl.logCritical(sdl.LogCategoryError, | |
| "Can't create renderer: %s", | |
| sdl.getError()) | |
| return false | |
| # Set draw color | |
| if app.renderer.setRenderDrawColor(0x00, 0x00, 0x00, 0xFF) != 0: | |
| sdl.logWarn(sdl.LogCategoryVideo, | |
| "Can't set draw color: %s", | |
| sdl.getError()) | |
| return false | |
| sdl.logInfo(sdl.LogCategoryApplication, "SDL initialized successfully") | |
| return true | |
| # Shutdown sequence | |
| proc exit(app: App) = | |
| app.renderer.destroyRenderer() | |
| app.window.destroyWindow() | |
| ttf.quit() | |
| # img.quit() | |
| sdl.logInfo(sdl.LogCategoryApplication, "SDL shutdown completed") | |
| sdl.quit() | |
| # Render surface | |
| proc render(renderer: sdl.Renderer, | |
| surface: sdl.Surface, x, y: int): bool = | |
| result = true | |
| var rect = sdl.Rect(x: x, y: y, w: surface.w, h: surface.h) | |
| # Convert to texture | |
| var texture = sdl.createTextureFromSurface(renderer, surface) | |
| if texture == nil: | |
| return false | |
| # Render texture | |
| if renderer.renderCopy(texture, nil, addr(rect)) != 0: | |
| result = false | |
| # Clean | |
| destroyTexture(texture) | |
| # Event handling | |
| # Return true on app shutdown request, otherwise return false | |
| proc events(pressed: var seq[sdl.Keycode]): bool = | |
| result = false | |
| var e: sdl.Event | |
| if pressed.len > 0: | |
| pressed = @[] | |
| while sdl.pollEvent(addr(e)) != 0: | |
| # Quit requested | |
| if e.kind == sdl.Quit: | |
| return true | |
| # Key pressed | |
| elif e.kind == sdl.KeyDown: | |
| # Add pressed key to sequence | |
| pressed.add(e.key.keysym.sym) | |
| # Exit on Escape key press | |
| if e.key.keysym.sym == sdl.K_Escape: | |
| return true | |
| ######## | |
| # MAIN # | |
| ######## | |
| var | |
| app = App(window: nil, renderer: nil) | |
| done = false # Main loop exit condition | |
| pressed: seq[sdl.Keycode] = @[] # Pressed keys | |
| if init(app): | |
| var font: ttf.Font | |
| # embedded at compile-time | |
| const f = staticRead"fnt/PixelMplus12-Regular.ttf" | |
| font = ttf.openFontRW(rwFromConstMem(cast[ptr byte](f), f.len), 0, 8*2) | |
| # open at runtime | |
| # font = ttf.openFont("fnt/PixelMplus12-Regular.ttf", 8*2) | |
| if font == nil: | |
| sdl.logCritical(sdl.LogCategoryError, | |
| "Can't load font: %s", | |
| ttf.getError()) | |
| done = true | |
| # Init FPS manager | |
| var | |
| fpsMgr = newFpsManager() | |
| delta = 0.0 # Time passed since last frame in seconds | |
| ticks: uint64 # Ticks counter | |
| freq = sdl.getPerformanceFrequency() # Get counter frequency | |
| fpsMgr.start() | |
| ticks = getPerformanceCounter() | |
| # Main loop | |
| while not done: | |
| # Clear screen with draw color | |
| discard app.renderer.setRenderDrawColor(0x00, 0x00, 0x00, 0xFF) | |
| if app.renderer.renderClear() != 0: | |
| sdl.logWarn(sdl.LogCategoryVideo, | |
| "Can't clear screen: %s", | |
| sdl.getError()) | |
| var fps = font.renderUTF8_Shaded("FPS: " & $fpsMgr.fps, white, black) | |
| if not app.renderer.render(fps, 10, 10): | |
| sdl.logWarn(sdl.LogCategoryVideo, | |
| "Can't render text: %s", | |
| sdl.getError()) | |
| sdl.freeSurface(fps) | |
| var s = font.renderUTF8_Shaded("吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。", white, black) | |
| if not app.renderer.render(s, 10, 10+8*2+5): | |
| sdl.logWarn(sdl.LogCategoryVideo, | |
| "Can't render text: %s", | |
| sdl.getError()) | |
| sdl.freeSurface(s) | |
| # Update renderer | |
| app.renderer.renderPresent() | |
| # Event handling | |
| done = events(pressed) | |
| # Count frame | |
| fpsMgr.count() | |
| # Get frame duration | |
| delta = (sdl.getPerformanceCounter() - ticks).float / freq.float | |
| ticks = sdl.getPerformanceCounter() | |
| free(fpsMgr) | |
| # Shutdown | |
| exit(app) |
Author
doccaico
commented
Nov 20, 2020

Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment