diff --git a/.gitignore b/.gitignore index a46abc5..e8e9cf1 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ library.zip /env /env2 /env3 + +# Our special launcher +!/punyverse/launcher.c diff --git a/README.md b/README.md index c4b9a45..dc709da 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Python simulator of a puny universe. (How many words can I stick into one?) To install, run `pip install punyverse`. +If you are on Windows, run `punyverse_make_launcher`. This should create special launchers that runs `punyverse` on +your dedicated graphics card, should it exist. + Then, run `punyverse` to launch the simulator, or `punyversew` to launch without the console. ### A Note on Textures diff --git a/punyverse/launcher.c b/punyverse/launcher.c new file mode 100644 index 0000000..5766fc5 --- /dev/null +++ b/punyverse/launcher.c @@ -0,0 +1,28 @@ +#include +#include +#include + +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 0x00000001; + +#ifdef GUI +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +#else +int main() +#endif +{ +#if PY_MAJOR_VERSION >= 3 + int argc; + LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); +#else + int argc = __argc; + char **argv = __argv; +#endif + + Py_SetProgramName(argv[0]); + Py_Initialize(); + PySys_SetArgvEx(argc, argv, 0); + PyRun_SimpleString("from punyverse.main import main; main()"); + Py_Finalize(); + return 0; +} diff --git a/punyverse/launcher.py b/punyverse/launcher.py new file mode 100644 index 0000000..e261f79 --- /dev/null +++ b/punyverse/launcher.py @@ -0,0 +1,31 @@ +import os +import shutil +import sys + + +def main(): + if os.name != 'nt': + print('Not on Windows. Nothing to do.') + return + + source_dir = os.path.dirname(__file__) + dest_dir = os.path.join(sys.prefix, 'Scripts') + + launcher_exe = os.path.join(source_dir, 'launcher.exe') + launcherw_exe = os.path.join(source_dir, 'launcherw.exe') + punyverse_exe = os.path.join(dest_dir, 'punyverse.exe') + punyversew_exe = os.path.join(dest_dir, 'punyversew.exe') + assert os.path.isfile(launcher_exe) + assert os.path.isfile(launcherw_exe) + assert os.path.isfile(punyverse_exe) + assert os.path.isfile(punyversew_exe) + + def copy(src, dst): + print('Copying %s to %s...' % (src, dst)) + shutil.copy(src, dst) + copy(launcher_exe, punyverse_exe) + copy(launcherw_exe, punyversew_exe) + + +if __name__ == '__main__': + main() diff --git a/punyverse/main.py b/punyverse/main.py index 00187fa..34cf4d3 100644 --- a/punyverse/main.py +++ b/punyverse/main.py @@ -4,7 +4,7 @@ import pyglet INITIAL_WIN_HEIGHT = 540 INITIAL_WIN_WIDTH = 700 -DEBUG = True +DEBUG = False def main(): diff --git a/setup.py b/setup.py index 9841244..78e91cd 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,8 @@ import os import sys from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext +from setuptools.extension import Library has_pyx = os.path.exists(os.path.join(os.path.dirname(__file__), 'punyverse', '_glgeom.pyx')) @@ -30,6 +32,77 @@ else: with open(os.path.join(os.path.dirname(__file__), 'README.md')) as f: long_description = f.read() + +if os.name == 'nt': + class SimpleExecutable(Library, object): + executable_names = set() + + def __init__(self, name, *args, **kwargs): + super(SimpleExecutable, self).__init__(name, *args, **kwargs) + self.executable_names.add(name) + if '.' in name: + self.executable_names.add(name.split('.')[-1]) + + + def link_shared_object( + self, objects, output_libname, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, + target_lang=None): + self.link( + self.EXECUTABLE, objects, output_libname, + output_dir, libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, extra_preargs, extra_postargs, + build_temp, target_lang + ) + + def make_manifest_get_embed_info(old_func): + def manifest_get_embed_info(self, target_desc, ld_args): + temp_manifest, mfid = old_func(target_desc, ld_args) + if not os.path.exists(temp_manifest): + return None + return temp_manifest, mfid + return manifest_get_embed_info.__get__(old_func.__self__) + + + class build_ext_exe(build_ext, object): + def get_ext_filename(self, fullname): + ext = self.ext_map[fullname] + if isinstance(ext, SimpleExecutable): + return fullname.replace('.', os.sep) + '.exe' + return super(build_ext_exe, self).get_ext_filename(fullname) + + def get_export_symbols(self, ext): + if isinstance(ext, SimpleExecutable): + return ext.export_symbols + return super(build_ext_exe, self).get_export_symbols(ext) + + def build_extension(self, ext): + if isinstance(ext, SimpleExecutable): + old = self.shlib_compiler.link_shared_object + self.shlib_compiler.link_shared_object = link_shared_object.__get__(self.shlib_compiler) + patched = False + if hasattr(self.shlib_compiler, 'manifest_get_embed_info'): + self.shlib_compiler.manifest_get_embed_info = \ + make_manifest_get_embed_info(self.shlib_compiler.manifest_get_embed_info) + patched = True + super(build_ext_exe, self).build_extension(ext) + self.shlib_compiler.link_shared_object = old + if patched: + del self.shlib_compiler.manifest_get_embed_info + else: + super(build_ext_exe, self).build_extension(ext) + + extra_libs = [ + SimpleExecutable('punyverse.launcher', sources=['punyverse/launcher.c'], libraries=['shell32']), + SimpleExecutable('punyverse.launcherw', sources=['punyverse/launcher.c'], + libraries=['shell32'], define_macros=[('GUI', 1)]), + ] + build_ext = build_ext_exe +else: + extra_libs = [] + + setup( name='punyverse', version='0.5', @@ -52,11 +125,13 @@ setup( ext_modules=cythonize([ Extension('punyverse._glgeom', sources=[pyx_path('punyverse/_glgeom.pyx')], libraries=gl_libs), Extension('punyverse._model', sources=[pyx_path('punyverse/_model.pyx')], libraries=gl_libs), - ]), + ]) + extra_libs, + cmdclass={'build_ext': build_ext}, entry_points={ 'console_scripts': [ 'punyverse = punyverse.main:main', + 'punyverse_make_launcher = punyverse.launcher:main', 'punyverse_small_images = punyverse.small_images:main', ], 'gui_scripts': [