Example #1
0
def test_missing_resource(clean_assets):
    a = Asset('ppb/dont.touch.this')
    engine = GameEngine(
        AssetTestScene, basic_systems=[AssetLoadingSystem, Failer],
        fail=lambda e: False, message=None, run_time=1,
    )
    with engine:
        engine.start()

        with pytest.raises(FileNotFoundError):
            assert a.load()
Example #2
0
def test_missing_package(clean_assets):
    a = Asset('does/not/exist')
    engine = GameEngine(
        AssetTestScene, basic_systems=[AssetLoadingSystem, Failer],
        fail=lambda e: False, message=None, run_time=1,
    )
    with engine:
        engine.start()

        with pytest.raises(FileNotFoundError):
            assert a.load()
Example #3
0
    def __init__(self, name, *, size, index=None):
        """
        :param name: the filename to load
        :param size: the size in points
        :param index: the index of the font in a multi-font file (rare)
        """
        # We do it this way so that the raw data can be cached between multiple
        # invocations, even though we have to reparse it every time.
        self._data = Asset(name)
        self.size = size
        self.index = index

        self._start(self._data)
Example #4
0
def test_instance_condense():
    class SubAsset(Asset):
        pass

    a1 = Asset('ppb/engine.py')
    a2 = Asset('ppb/engine.py')

    a3 = Asset('ppb/scenes.py')

    s1 = SubAsset('ppb/engine.py')

    assert a1 is a2
    assert a1 is not a3
    assert a1 is not s1
Example #5
0
def test_loading(clean_assets):
    a = Asset('ppb/engine.py')
    engine = GameEngine(
        AssetTestScene, basic_systems=[AssetLoadingSystem, Failer],
        fail=lambda e: False, message=None, run_time=1,
    )
    with engine:
        engine.start()
        ats = engine.current_scene

        engine.main_loop()

        assert a.load()
        print(vars(ats))
        assert ats.ale.asset is a
        assert ats.ale.total_loaded == 1
        assert ats.ale.total_queued == 0
Example #6
0
class Font(ChainingMixin, FreeingMixin, AbstractAsset):
    """
    A TrueType/OpenType Font
    """
    def __init__(self, name, *, size, index=None):
        """
        :param name: the filename to load
        :param size: the size in points
        :param index: the index of the font in a multi-font file (rare)
        """
        # We do it this way so that the raw data can be cached between multiple
        # invocations, even though we have to reparse it every time.
        self._data = Asset(name)
        self.size = size
        self.index = index

        self._start(self._data)

    def _background(self):
        self._file = rw_from_object(io.BytesIO(self._data.load()))
        # We have to keep the file around because freetype doesn't load
        # everything at once, resulting in segfaults.
        with _freetype_lock:
            # Doing this so that we "refcount" the FT_Library internal to SDL_ttf
            # (TTF_CloseFont is often called after system cleanup)
            ttf_call(TTF_Init, _check_error=lambda rv: rv == -1)
            if self.index is None:
                return ttf_call(
                    TTF_OpenFontRW, self._file, False, self.size,
                    _check_error=lambda rv: not rv
                )
            else:
                return ttf_call(
                    TTF_OpenFontIndexRW, self._file, False, self.size, self.index,
                    _check_error=lambda rv: not rv
                )

    def free(self, data, _TTF_CloseFont=TTF_CloseFont, _lock=_freetype_lock,
             _TTF_Quit=TTF_Quit):
        # ^^^ is a way to keep required functions during interpreter cleanup
        with _lock:
            _TTF_CloseFont(data)  # Can't fail
            _TTF_Quit()

    def __repr__(self):
        return f"<{type(self).__name__} name={self.name!r} size={self.size!r}{' loaded' if self.is_loaded() else ''} at {id(self):x}>"

    @property
    def name(self):
        return self._data.name

    def resize(self, size):
        """
        Returns a new copy of this font in a different size
        """
        return type(self)(self._data.name, size=size, index=self._index)

    @property
    def _is_fixed_width(self):
        return bool(TTF_FontFaceIsFixedWidth(self.load()))

    @property
    def _family_name(self):
        return TTF_FontFaceFamilyName(self.load())

    @property
    def _style_name(self):
        return TTF_FontFaceStyleName(self.load())