Source

pygamekit / engine.pxi

Full commit

import sys, imp

#import traceback

from scene cimport *

cdef extern from "gkLogger.h":
    #cdef cppclass gkLogger:
    void gkLogger_enable "gkLogger::enable"(gkString&, bool verbose)
    void gkLogger_disable "gkLogger::disable"()
    void gkLogger_write "gkLogger::write"(gkString& msg, bool force = 0)
    
    void gkPrintf(char *fmt, ...)
    int GK_CPP_VERBOSE_LOG
    
cdef extern from "gkUserDefs.h":
    cdef cppclass gkUserDefs:
        void load(gkString& fname)
        void parseString(gkString& key, gkString& val)


        OgreRenderSystem        rendersystem       # Ogre render system to use
        gkString                viewportOrientation# portrait, landscaperight, landscapeleft
        int                     sceneManager       # TODO scene manager to use
        gkString                log                # Main log file name
        bool                    verbose            # Enable/Disable Ogre print-out
        gkVector2               winsize            # Window width & height
        gkString                wintitle           # Window title
        gkString                extWinhandle       # External Window Handle
        bool                    fullscreen         # Fullscreen mode
        int                     framingType        # crop/letterbox/extend. Used when window is larger then requested
        gkString                resources          # resources to load
        bool                    blendermat         # convert meshes using blender materials
        bool                    grabInput          # hide & grab the mouse
        bool                    debugFps           # show fps and profiling information
        bool                    debugPhysics       # enable / disable physics debugging
        bool                    debugPhysicsAabb   # show / hide bounding box
        bool                    buildStaticGeometry# Use Static geometry
        bool                    useBulletDbvt      # Use Bullet Dynamic AABB Tree
        bool                    showDebugProps     # Show variable debugging information.
        bool                    debugSounds        # Show 3D sound debug info
        bool                    disableSound       # Disable OpenAL sound.
        bool                    fsaa               # Enable Full scene anti aliasing.
        int                     fsaaSamples        # Anti aliasing samples.
        bool                    enableshadows
        int                     defaultMipMap      # Number of mipmaps to generate per texture (default 5)

        gkString                shadowtechnique
        gkColor                 colourshadow
        gkScalar                fardistanceshadow

        OgreRenderSystem getOgreRenderSystem(gkString& val)
        int getViewportFramingType(gkString& val)
        
cdef extern from "gkEngine.h":
    
    cdef cppclass pyEngineListener "gkEngine::Listener":
        pass
        
    cdef cppclass gkEngine:
                    
        gkEngine(gkUserDefs *defs)
        
        void initialize()
        void finalize()
        void run()

        bool initializeStepLoop()
        bool stepOneFrame()
        void finalizeStepLoop()

        bool isInitialized()
        bool isRunning()

        void initializeWindow()

        bool hasActiveScene()

        gkUserDefs& getUserDefs()
        void requestExit()

        void loadResources(gkString& name)

        void addDebugProperty(gkVariable* prop)
        void removeDebugProperty(gkVariable* prop)

        gkScalar getStepRate()
        gkScalar getTickRate()

        gkScene* getActiveScene()

        void registerActiveScene(gkScene* scene)
        void unregisterActiveScene(gkScene* scene)

        void addListener(pyEngineListener* listener)
        void removeListener(pyEngineListener* listener)

    gkEngine* gkEngine_getSingleton "&gkEngine::getSingleton"()


cdef extern from "Graphics/gkHUDManager.h":
    cdef cppclass gkHUDManager:
        pass

cdef extern from "Graphics/gkHUD.h":
    cdef cppclass gkHUD:
        pass

cdef extern from "Graphics/gkHUDElement.h":
    cdef cppclass gkHUDElement:
        pass

cdef extern from "gkTextFile.h":
    cdef cppclass gkTextFile:
        gkString& getText()

cdef extern from "gkTextManager.h":
    cppclass gkTextManager "gkTextManager::getSingleton":
        gkTextManager()
        gkTextFile* getByName "getByName<gkTextFile>"(gkString&)
        bool exists(gkString&)

#----------------------------------------------------------------------------
# Globals
cdef list tick_callback = []
cdef bool initialized = False
cdef Engine current_engine
    
cdef class Engine:
    cdef gkEngine *eng
    cdef gkClock *timer
    #cdef gkHUDManager* mgr
    
    cdef Scene _act_scene

    def __init__(self, bfile=None, cfgfile=None, initialize=True):
        
        global initialized, current_engine
        
        if initialize:
            if PLATFORM!="ANDROID":
                if cfgfile:
                    prefs.load(gkString(cfgfile))
                    
                self.eng = new gkEngine(prefs)
                self.eng.initialize()
                if not self.eng.isInitialized():
                    print("Failed to initialize enigne.")
                    sys.exit(1)
                #self.mgr = new gkHUDManager()

                if bfile:
                    self.load_blend(bfile)
                    
                self.eng.initializeStepLoop()
            else:
                self.eng = gkEngine_getSingleton()
            
            self.timer = new gkClock()
            self.timer.reset()
            
            initialized = True
            current_engine = self
            
            
    def __del__(self):
        self.eng.requestExit()

    property active_scene:
        def __get__(self):
            cdef gkScene* s = self.eng.getActiveScene()
            if self._act_scene is None or self._act_scene._p != <void*>s:
                self._act_scene = wrap(Scene, s)
            return self._act_scene

    def _step_one_frame(self):
        #try:
        evaluate_all_callbacks()
        #except SystemExit:
            #return False
        #except:
            #traceback.print_exc()
        return self.eng.stepOneFrame()
    
    def load_blend(self, bfile):
        cdef gkScene* scn
        
        b = BlendFile()
        b.load(bfile, IGNORE_CACHE_FILE)
        scn = self.eng.getActiveScene()
        
        
        if scn:
            gkSceneManager().copyObjects(b.bfile.getMainScene(), scn, OBJ_CAMERA | OBJ_LIGHT)
        else:
            scn = b.bfile.getMainScene()
            
            self.eng.registerActiveScene(scn)
            
            scn.createInstance()
            
    def run(self):
        while self._step_one_frame():
            pass

cdef class TickSensor(Sensor):
    
    def __init__(self):
        self.init_sensor(tick_callback)
        
    def __nonzero__(self):
        return True
            
cdef void evaluate_tick_callbacks() except *:
    for s in tick_callback[:]:
        (<TickSensor>s).execute()
    
cdef public void evaluate_all_callbacks() except *:
    
    #TODO: make tick time configurable (now fixed at 60)
    
    #For the moment will not compensate slow graphics with substeps,
    #so use tickSensor.elapsedTime to make your interactions proportional.
    
    #TODO: now I'm blocking to limir overall FPS, to fix collisions
    cdef long long us=current_engine.timer.getMicroseconds()
    if 0<us<16666:
        usleep(16666-us)
    if 1:#current_engine.timer.getMicroseconds()>16666: #60 FPS
        current_engine.timer.reset()
        evaluate_input_callbacks()
        evaluate_collision_callbacks()
        evaluate_timer_callbacks()
        evaluate_tick_callbacks()
        
cpdef public get_engine():
    global current_engine
    if current_engine is None:
        current_engine = Engine()
    return current_engine
    
    
def get_active_scene():
    if current_engine!=None:
        return current_engine.active_scene

class TextBlockImporter(object):
    def find_module(self, module_name, package_path):
        if package_path: return
        module_name += '.py'
        if initialized and gkTextManager().exists(gkString(module_name)):
            return self
            
    def load_module(self, module_name):
        mod = imp.new_module(module_name)
        sys.modules[module_name] = mod
        module_name += '.py'
        code = str(gkTextManager().getByName(gkString(module_name)).getText().c_str())
        exec code in mod.__dict__
        return mod

sys.meta_path.append(TextBlockImporter())
del TextBlockImporter

def has_text_block(name):
    if initialized: return gkTextManager().exists(gkString(name))
    
def get_text_block(name):
    if initialized:
        return str(gkTextManager().getByName(gkString(name)).getText().c_str())
    
def reload_init():
    pass

def destroy_all_links():
    for c in tick_callback, key_callbacks, mouse_move_callbacks, mousebutton_callbacks, timer_callbacks:
        for s in c:
            (<Sensor>s).unlink_all()
        del(c[:])