def compute_rectangles(self, texture, game_object, camera): flags = sdl2.stdinc.Uint32() access = ctypes.c_int() img_w = ctypes.c_int() img_h = ctypes.c_int() sdl_call(SDL_QueryTexture, texture, ctypes.byref(flags), ctypes.byref(access), ctypes.byref(img_w), ctypes.byref(img_h), _check_error=lambda rv: rv < 0) src_rect = SDL_Rect(x=0, y=0, w=img_w, h=img_h) if hasattr(game_object, 'width'): obj_w = game_object.width obj_h = game_object.height else: obj_w, obj_h = game_object.size win_w, win_h = self.target_resolution(img_w.value, img_h.value, obj_w, obj_h, camera.pixel_ratio) center = camera.translate_point_to_screen(game_object.position) dest_rect = SDL_Rect( x=int(center.x - win_w / 2), y=int(center.y - win_h / 2), w=win_w, h=win_h, ) return src_rect, dest_rect, ctypes.c_double(-game_object.rotation)
def render_background(self, scene): bg = scene.background_color sdl_call( SDL_SetRenderDrawColor, self.renderer, bg[0], bg[1], bg[2], 255, _check_error=lambda rv: rv < 0 ) sdl_call(SDL_RenderClear, self.renderer, _check_error=lambda rv: rv < 0)
def iter_audio_drivers(): num_drivers = sdl_call(sdl2.SDL_GetNumAudioDrivers, ) for i in range(num_drivers): yield sdl_call( sdl2.SDL_GetAudioDriver, i, _check_error=lambda rv: rv is None, ).decode('utf-8')
def _draw_shape(self, renderer, rgb, **_): sdl_call( SDL_SetRenderDrawColor, renderer, *rgb, 255, _check_error=lambda rv: rv < 0 ) sdl_call( SDL_RenderFillRect, renderer, None, _check_error=lambda rv: rv < 0 )
def iter_render_drivers(): num_drivers = sdl_call(sdl2.SDL_GetNumRenderDrivers, _check_error=lambda rv: rv <= 0) for i in range(num_drivers): info = sdl2.SDL_RendererInfo() sdl_call(sdl2.SDL_GetRenderDriverInfo, i, ctypes.byref(info), _check_error=lambda rv: rv < 0) yield info.name.decode('utf-8'), info
def _draw_shape(self, renderer, rgb, **_): half = int(DEFAULT_SPRITE_SIZE / 2) sdl_call( filledCircleRGBA, renderer, half, half, # Center half, # Radius *rgb, 255, _check_error=lambda rv: rv < 0)
def iter_joysticks(): num_sticks = sdl_call( sdl2.SDL_NumJoysticks, _check_error=lambda rv: rv < 0, ) for i in range(num_sticks): name = sdl_call( sdl2.SDL_JoystickNameForIndex, i, _check_error=lambda rv: rv is None, ) yield name.decode('utf-8')
def _background(self): surface = _create_surface(self.color) renderer = sdl_call(SDL_CreateSoftwareRenderer, surface, _check_error=lambda rv: not rv) try: self._draw_shape(renderer, rgb=self.color) finally: sdl_call(SDL_DestroyRenderer, renderer) return surface
def _draw_shape(self, renderer, rgb, **_): sdl_call(filledTrigonRGBA, renderer, 0, DEFAULT_SPRITE_SIZE, int(DEFAULT_SPRITE_SIZE / 2), 0, DEFAULT_SPRITE_SIZE, DEFAULT_SPRITE_SIZE, *rgb, 255, _check_error=lambda rv: rv < 0)
def _draw_shape(self, renderer, rgb, **_): w, h = c_int(), c_int() sdl_call(SDL_GetRendererOutputSize, renderer, byref(w), byref(h)) half_width, half_height = int(w.value / 2), int(h.value / 2) sdl_call( filledEllipseRGBA, renderer, half_width, half_height, # Center half_width, half_height, # Radius *rgb, 255, _check_error=lambda rv: rv < 0 )
def check_audio_driver(name): try: sdl_call(sdl2.SDL_AudioInit, name.encode('utf-8'), _check_error=lambda rv: rv < 0) except Exception: return False else: sdl_call( sdl2.SDL_AudioQuit, name, ) return True
def _draw_shape(self, renderer, rgb, **_): w, h = c_int(), c_int() sdl_call(SDL_GetRendererOutputSize, renderer, byref(w), byref(h)) width, height = w.value, h.value sdl_call( filledTrigonRGBA, renderer, 0, height, int(width / 2), 0, width, height, *rgb, 255, _check_error=lambda rv: rv < 0 )
def background_parse(self, data): file = rw_from_object(io.BytesIO(data)) # ^^^^ is a pure-python emulation, does not need cleanup. surface = img_call(IMG_Load_RW, file, False, _check_error=lambda rv: not rv) sdl_call(SDL_SetSurfaceBlendMode, surface, SDL_BLENDMODE_BLEND, _check_error=lambda rv: rv < 0) return surface
def compute_rectangles(self, texture, game_object, camera): flags = sdl2.stdinc.Uint32() access = ctypes.c_int() img_w = ctypes.c_int() img_h = ctypes.c_int() sdl_call(SDL_QueryTexture, texture, ctypes.byref(flags), ctypes.byref(access), ctypes.byref(img_w), ctypes.byref(img_h), _check_error=lambda rv: rv < 0) src_rect = SDL_Rect(x=0, y=0, w=img_w, h=img_h) if hasattr(game_object, 'width'): obj_w = game_object.width obj_h = game_object.height else: obj_w, obj_h = game_object.size win_w, win_h = self.target_resolution(img_w.value, img_h.value, obj_w, obj_h, camera.pixel_ratio) try: center = camera.translate_point_to_screen(game_object.position) except TypeError as error: raise TypeError( f"""{type(game_object).__name__}.position was set to a tuple: (number, number) Expected a vector: Vector(number, number) """) from error dest_rect = SDL_Rect( x=int(center.x - win_w / 2), y=int(center.y - win_h / 2), w=win_w, h=win_h, ) return src_rect, dest_rect, ctypes.c_double(-game_object.rotation)
def __enter__(self): super().__enter__() img_call(IMG_Init, IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF) ttf_call(TTF_Init, _check_error=lambda rv: rv == -1) self.window = ctypes.POINTER(SDL_Window)() self.renderer = ctypes.POINTER(SDL_Renderer)() sdl_call( SDL_CreateWindowAndRenderer, self.resolution[0], # Width self.resolution[1], # Height 0, # Flags # SDL_WINDOW_ALLOW_HIGHDPI - Allow the renderer to work in HiDPI natively ctypes.byref(self.window), ctypes.byref(self.renderer), _check_error=lambda rv: rv < 0) # NOTE: It looks like SDL_RENDERER_PRESENTVSYNC will cause SDL_RenderPresent() to block? sdl_call(SDL_SetWindowTitle, self.window, self.window_title.encode('utf-8'))
def on_render(self, render_event, signal): camera = render_event.scene.main_camera self.render_background(render_event.scene) for game_object in render_event.scene.sprite_layers(): texture = self.prepare_resource(game_object) if texture is None: continue src_rect, dest_rect, angle = self.compute_rectangles( texture.inner, game_object, camera ) sdl_call( SDL_RenderCopyEx, self.renderer, texture.inner, ctypes.byref(src_rect), ctypes.byref(dest_rect), angle, None, SDL_FLIP_NONE, _check_error=lambda rv: rv < 0 ) sdl_call(SDL_RenderPresent, self.renderer)
def _create_surface(color): """ Creates a surface for assets and sets the color key. """ surface = sdl_call(SDL_CreateRGBSurface, 0, DEFAULT_SPRITE_SIZE, DEFAULT_SPRITE_SIZE, 32, 0, 0, 0, 0, _check_error=lambda rv: not rv) color_key = BLACK if color != BLACK else MAGENTA color = sdl2.ext.Color(*color_key) sdl_call(SDL_SetColorKey, surface, True, sdl2.ext.prepare_color(color, surface.contents), _check_error=lambda rv: rv < 0) sdl2.ext.fill(surface.contents, color) return surface
def _create_surface(color, aspect_ratio: AspectRatio = AspectRatio(1, 1)): """ Creates a surface for assets and sets the color key. """ width = height = DEFAULT_SPRITE_SIZE if aspect_ratio.width > aspect_ratio.height: height *= aspect_ratio.height / aspect_ratio.width height = int(height) elif aspect_ratio.height > aspect_ratio.width: width *= aspect_ratio.width / aspect_ratio.height width = int(width) surface = sdl_call( SDL_CreateRGBSurface, 0, width, height, 32, 0, 0, 0, 0, _check_error=lambda rv: not rv ) color_key = BLACK if color != BLACK else MAGENTA color = sdl2.ext.Color(*color_key) sdl_call( SDL_SetColorKey, surface, True, sdl2.ext.prepare_color(color, surface.contents), _check_error=lambda rv: rv < 0 ) sdl2.ext.fill(surface.contents, color) return surface
def file_missing(self): width = height = 70 # Pixels, arbitrary surface = sdl_call( SDL_CreateRGBSurface, 0, width, height, 32, 0, 0, 0, 0, _check_error=lambda rv: not rv ) rand = random.Random(str(self.name)) r = rand.randint(65, 255) g = rand.randint(65, 255) b = rand.randint(65, 255) color = sdl2.ext.Color(r, g, b) sdl2.ext.fill(surface.contents, color) return surface
def prepare_resource(self, game_object): """ Get the SDL Texture for an object. """ if not self._object_has_dimension(game_object): return None if not hasattr(game_object, '__image__'): return image = game_object.__image__() if image is None: return None surface = image.load() try: texture = self._texture_cache[surface] except KeyError: texture = SmartPointer( sdl_call(SDL_CreateTextureFromSurface, self.renderer, surface, _check_error=lambda rv: not rv), SDL_DestroyTexture) self._texture_cache[surface] = texture opacity = getattr(game_object, 'opacity', 255) opacity_mode = getattr(game_object, 'opacity_mode', flags.BlendModeBlend) opacity_mode = OPACITY_MODES[opacity_mode] tint = getattr(game_object, 'tint', (255, 255, 255)) sdl_call(SDL_SetTextureAlphaMod, texture.inner, opacity, _check_error=lambda rv: rv < 0) sdl_call(SDL_SetTextureBlendMode, texture.inner, opacity_mode, _check_error=lambda rv: rv < 0) sdl_call(SDL_SetTextureColorMod, texture.inner, tint[0], tint[1], tint[2], _check_error=lambda rv: rv < 0) return texture
def iter_video_drivers(): num_drivers = sdl_call(sdl2.SDL_GetNumVideoDrivers, _check_error=lambda rv: rv <= 0) for i in range(num_drivers): yield sdl_call(sdl2.SDL_GetVideoDriver, i).decode('utf-8')
def sdl_revision(): return sdl_call(sdl2.SDL_GetRevision).decode('utf-8')
def sdl_version(): ver = sdl2.SDL_version() sdl_call(sdl2.SDL_GetVersion, ctypes.byref(ver)) return f"{ver.major}.{ver.minor}.{ver.patch}"
def set_cursor(self, scene): show_cursor = int(bool(getattr(scene, "show_cursor", True))) sdl_call(SDL_ShowCursor, show_cursor)
def __exit__(self, *exc): sdl_call(SDL_DestroyRenderer, self.renderer) sdl_call(SDL_DestroyWindow, self.window) ttf_call(TTF_Quit) img_call(IMG_Quit) super().__exit__(*exc)