Skip to content

Instantly share code, notes, and snippets.

@kiwwisk
Created April 13, 2017 06:13
Show Gist options
  • Save kiwwisk/ecf8d370a6690c15ff0cc4c6b201fda1 to your computer and use it in GitHub Desktop.
Save kiwwisk/ecf8d370a6690c15ff0cc4c6b201fda1 to your computer and use it in GitHub Desktop.
Skeleton for SDL2/OpenGL application in Python 3. Game loop has fixed time step, rendering is going at full speed.
#
# Skeleton for SDL2/OpenGL application in Python
# with fixed logic time step, rendering is going still at full speed.
#
# To turn debug logging messages on, run with -v parameter:
# python <script_name.py> -v
#
import argparse
import logging
import ctypes
import time
import sdl2
from OpenGL import GL
WIDTH = 450
HEIGHT = 600
LOGIC_FPS = 1.0 / 25.0 # 25 logic frames per second, fixed step
def logic(delta_time):
"""
Game logic goes here. Delta time is fixed to LOGIC_FPS
"""
pass
def render(delta_time):
"""
Render code goes here.
"""
GL.glClearColor(0.3, 0.3, 0.3, 1)
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
def init_args_and_logging():
parser = argparse.ArgumentParser(
description='OpenGL skeleton app.')
parser.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
args = parser.parse_args()
if args.verbose:
logging.basicConfig(format=format_str, level=logging.DEBUG)
else:
logging.basicConfig(format=format_str, level=logging.INFO)
def throw_runtime_sdl_error():
err = sdl2.SDL_GetError()
logging.error(err)
raise RuntimeError(err)
def create_opengl_context(window):
sdl2.video.SDL_GL_SetAttribute(
sdl2.video.SDL_GL_CONTEXT_MAJOR_VERSION,
3)
sdl2.video.SDL_GL_SetAttribute(
sdl2.video.SDL_GL_CONTEXT_MINOR_VERSION,
3)
sdl2.video.SDL_GL_SetAttribute(
sdl2.video.SDL_GL_CONTEXT_PROFILE_MASK,
sdl2.video.SDL_GL_CONTEXT_PROFILE_CORE)
context = sdl2.SDL_GL_CreateContext(window)
GL.glEnable(GL.GL_BLEND)
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
GL.glEnable(GL.GL_DEPTH_TEST)
GL.glDepthFunc(GL.GL_LESS)
return context
def window_title(frames=None):
if not frames:
return 'OpenGL Torch demo'.encode('utf-8')
return 'OpenGL Torch demo FPS:{}'.format(frames).encode('utf-8')
def main():
init_args_and_logging()
logging.debug('Application starting...')
if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) != 0:
throw_runtime_sdl_error()
logging.debug('SDL Initialized...')
try:
window = None
window = sdl2.SDL_CreateWindow(window_title(),
sdl2.SDL_WINDOWPOS_UNDEFINED,
sdl2.SDL_WINDOWPOS_UNDEFINED,
WIDTH, HEIGHT,
sdl2.SDL_WINDOW_OPENGL)
if not window:
throw_runtime_sdl_error()
logging.debug('SDL Window initialized...')
context = None
context = create_opengl_context(window)
if not context:
throw_runtime_sdl_error()
logging.debug('OpenGL context initialized...')
logging.debug('Entering main loop...')
accumulator = 0.0
window_title_timer = 0.0
frames = 0
current_time = time.monotonic()
running = True
while running:
event = sdl2.SDL_Event()
while sdl2.SDL_PollEvent(ctypes.byref(event)) != 0:
if event.type == sdl2.SDL_QUIT:
logging.debug('SDL_QUIT event received, bailing out.')
running = False
elif (event.type == sdl2.SDL_KEYDOWN and
event.key.keysym.sym == sdl2.SDLK_ESCAPE):
logging.debug('ESC key pressed, bailing out.')
running = False
new_time = time.monotonic()
delta_time = new_time - current_time
accumulator += delta_time
while accumulator >= LOGIC_FPS:
logic(LOGIC_FPS)
accumulator -= LOGIC_FPS
render(delta_time)
sdl2.SDL_GL_SwapWindow(window)
sdl2.SDL_Delay(1)
frames += 1
window_title_timer += delta_time
if window_title_timer >= 1.0:
sdl2.SDL_SetWindowTitle(window, window_title(frames))
frames = 0
window_title_timer -= 1.0
current_time = new_time
finally:
logging.debug('Quitting, doing cleanup...')
if context:
sdl2.SDL_GL_DeleteContext(context)
if window:
sdl2.SDL_DestroyWindow(window)
sdl2.SDL_Quit()
logging.debug('Done. Bye.')
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment