Source code for Elements.pyGLV.GUI.Viewer

"""
Viewer classes, part of the Elements.pyGLV
    
Elements.pyGLV (Computer Graphics for Deep Learning and Scientific Visualization)
@Copyright 2021-2022 Dr. George Papagiannakis
    
The classes below are all related to the GUI and Display part of the package

Basic design principles are based on the Decorator Design pattern:
	• https://refactoring.guru/design-patterns/decorator
	• https://github.com/faif/python-patterns/blob/master/patterns/structural/decorator.py
"""

from __future__         import annotations
from abc                import ABC, abstractmethod
from typing             import List, Dict, Any
from collections.abc    import Iterable, Iterator
from sys import platform

import sdl2
import sdl2.ext
from sdl2.keycode import SDLK_ESCAPE
from sdl2.video import SDL_WINDOWPOS_CENTERED, SDL_WINDOW_ALLOW_HIGHDPI
import OpenGL.GL as gl
from OpenGL.GL import shaders
import imgui
from imgui.integrations.sdl2 import SDL2Renderer

import Elements.pyECSS.System  
import Elements.pyECSS.utilities as util
import Elements.pyECSS.Event
from Elements.pyECSS.System import System 
from Elements.pyECSS.Component import BasicTransform
import numpy as np


[docs]class RenderWindow(ABC): """ The Abstract base class of the Viewer GUI/Display sub-system of pyglGA based on the Decorator Pattern, this class is "wrapped" by decorators in order to provide extra cpapabilities e.g. SDL2 window, context and ImGUI widgets """
[docs] def __init__(self): self._eventManager = None self._scene = None
#define properties for EventManager, Scene objects @property #name def eventManager(self): """ Get RenderWindow's eventManager """ return self._eventManager @eventManager.setter def eventManager(self, value): self._eventManager = value @property #name def scene(self): """ Get RenderWindow's Scene reference """ return self._scene @scene.setter def scene(self, value): self._scene = value @abstractmethod def init(self): raise NotImplementedError abstractmethod def init_post(self): raise NotImplementedError @abstractmethod def display(self): raise NotImplementedError @abstractmethod def display_post(self): raise NotImplementedError @abstractmethod def shutdown(self): raise NotImplementedError @abstractmethod def event_input_process(self, running = True): raise NotImplementedError @abstractmethod def accept(self, system: Elements.pyECSS.System, event = None): """ Accepts a class object to operate on the RenderWindow, based on the Visitor pattern. :param system: [a System object] :type system: [System] """ raise NotImplementedError @classmethod def getClassName(cls): return cls.__name__
[docs]class SDL2Window(RenderWindow): """ The concrete subclass of RenderWindow for the SDL2 GUI API :param RenderWindow: [description] :type RenderWindow: [type] """
[docs] def __init__(self, windowWidth = None, windowHeight = None, windowTitle = None, scene = None, eventManager = None, openGLversion = 4): """Constructor SDL2Window for basic SDL2 parameters :param windowWidth: [description], defaults to None :type windowWidth: [type], optional :param windowHeight: [description], defaults to None :type windowHeight: [type], optional :param windowTitle: [description], defaults to None :type windowTitle: [type], optional """ super().__init__() self._gWindow = None self._gContext = None self._gVersionLabel = "None" self.openGLversion = openGLversion if windowWidth is None: self._windowWidth = 1024 else: self._windowWidth = windowWidth if windowHeight is None: self._windowHeight = 768 else: self._windowHeight = windowHeight if windowTitle is None: self._windowTitle = "SDL2Window" else: self._windowTitle = windowTitle if eventManager is not None and scene is None: # in case we are testing without a Scene and just an EventManager self.eventManager = eventManager if scene is not None: # set the reference of parent RenderWindow to Scene # get the reference to EventManager from Scene.ECSSManager self._scene = scene self.eventManager = scene.world.eventManager #OpenGL state variables self._wireframeMode = False self._colorEditor = 0.0, 0.0, 0.0 self._myCamera = np.identity(4)
@property def gWindow(self): return self._gWindow @property def gContext(self): return self._gContext def init(self): """ Initialise an SDL2 RenderWindow, not directly but via the SDL2Decorator """ print(f'{self.getClassName()}: init()') #SDL_Init for the window initialization sdl_not_initialised = sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO | sdl2.SDL_INIT_TIMER) if sdl_not_initialised !=0: print("SDL2 could not be initialised! SDL Error: ", sdl2.SDL_GetError()) exit(1) #setting OpenGL attributes for the GL state sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_FLAGS, sdl2.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG ) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_PROFILE_MASK, sdl2.SDL_GL_CONTEXT_PROFILE_CORE ) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DOUBLEBUFFER, 1) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_ACCELERATED_VISUAL, 1) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_DEPTH_SIZE, 24) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_STENCIL_SIZE, 8) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLEBUFFERS, 1) if self.openGLversion==3: print("="*24) print("Using OpenGL version 3.2") print("="*24) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, 3) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, 2) else: print("="*24) print("Using OpenGL version 4.1") print("="*24) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, 4) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, 1) # Linux doesn't like SDL_GL_MULTISAMPLESAMPLES if platform == "linux" or platform == "linux2": pass else: sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLESAMPLES, 16) sdl2.SDL_SetHint(sdl2.SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, b"1") sdl2.SDL_SetHint(sdl2.SDL_HINT_VIDEO_HIGHDPI_DISABLED, b"1") #creating the SDL2 window self._gWindow = sdl2.SDL_CreateWindow(self._windowTitle.encode(), sdl2.SDL_WINDOWPOS_CENTERED, sdl2.SDL_WINDOWPOS_CENTERED, self._windowWidth, self._windowHeight, # sdl2.SDL_WINDOW_ALLOW_HIGHDPI) sdl2.SDL_WINDOW_OPENGL, sdl2.SDL_WINDOW_RESIZABLE) if self._gWindow is None: print("Window could not be created! SDL Error: ", sdl2.SDL_GetError()) exit(1) #create the OpenGL context for rendering into the SDL2Window that was constructed just before self._gContext = sdl2.SDL_GL_CreateContext(self._gWindow) if self._gContext is None: print("OpenGL Context could not be created! SDL Error: ", sdl2.SDL_GetError()) exit(1) sdl2.SDL_GL_MakeCurrent(self._gWindow, self._gContext) if sdl2.SDL_GL_SetSwapInterval(1) < 0: print("Warning: Unable to set VSync! SDL Error: " + sdl2.SDL_GetError()) # exit(1) #obtain the GL versioning system info self._gVersionLabel = f'OpenGL {gl.glGetString(gl.GL_VERSION).decode()} GLSL {gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION).decode()} Renderer {gl.glGetString(gl.GL_RENDERER).decode()}' print(self._gVersionLabel) def init_post(self): """ Post init method for SDL2 this should be ctypiically alled AFTER all other GL contexts have been created """ pass def display(self): """ Main display window method to be called standalone or from within a concrete Decorator """ #GPTODO make background clear color as parameter at class level gl.glClearColor(*self._colorEditor, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gl.glDisable(gl.GL_CULL_FACE) gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthFunc(gl.GL_LESS) # gl.glDepthFunc(gl.GL_LEQUAL); # gl.glDepthMask(gl.GL_FALSE); #gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL) #setup some extra GL state flags if self._wireframeMode: gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE) #print(f"SDL2Window:display() set wireframemode: {self._wireframeMode}") else: gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL) #print(f"SDL2Window:display() set wireframemode: {self._wireframeMode}") #print(f'{self.getClassName()}: display()') def display_post(self): """ To be called at the end of each drawn frame to swap double buffers """ sdl2.SDL_GL_SwapWindow(self._gWindow) #print(f'{self.getClassName()}: display_post()') def shutdown(self): """ Shutdown and cleanup SDL2 operations """ print(f'{self.getClassName()}: shutdown()') if (self._gContext and self._gWindow is not None): sdl2.SDL_GL_DeleteContext(self._gContext) sdl2.SDL_DestroyWindow(self._gWindow) sdl2.SDL_Quit() def event_input_process(self, running = True): """ process SDL2 basic events and input """ events = sdl2.ext.get_events() for event in events: if event.type == sdl2.SDL_KEYDOWN: if event.key.keysym.sym == sdl2.SDLK_ESCAPE: running = False if event.type == sdl2.SDL_QUIT: running = False return running def accept(self, system: Elements.pyECSS.System, event = None): system.apply2SDLWindow(self, event)
[docs]class RenderDecorator(RenderWindow): """ Main Decorator class that wraps a RenderWindow so that all other Decorator classes can dynamically be adding layered functionality on top of the wrapee (RenderWindow) e.g. ImGUI widgets etc. :param RenderWindow: [description] :type RenderWindow: [type] """
[docs] def __init__(self, wrapee: RenderWindow): super().__init__() self._wrapeeWindow = wrapee
@property def wrapeeWindow(self): return self._wrapeeWindow def init(self): """ [summary] """ self._wrapeeWindow.init() print(f'RenderDecorator: init()') def display(self): """ Main decorator display method """ self._wrapeeWindow.display() def shutdown(self): """ [summary] """ self._wrapeeWindow.shutdown() print(f'RenderDecorator: shutdown()') def event_input_process(self, running = True): """ extra decorator method to handle input events :param running: [description], defaults to True :type running: bool, optional """ self._wrapeeWindow.event_input_process(running) def display_post(self): """ Post diplay method after all other display calls have been issued """ self._wrapeeWindow.display_post() def init_post(self): """ Post init method this should be ctypiically alled AFTER all other GL contexts have been created, e.g. ImGUI context """ self._wrapeeWindow.init_post() def accept(self, system: Elements.pyECSS.System, event = None): pass
[docs]class ImGUIDecorator(RenderDecorator): """ ImGUI decorator :param RenderDecorator: [description] :type RenderDecorator: [type] """
[docs] def __init__(self, wrapee: RenderWindow, imguiContext = None): super().__init__(wrapee) if imguiContext is None: self._imguiContext = imgui.create_context() else: self._imguiContext = imguiContext self._imguiRenderer = None #setup a simple Event: change to wireframe mode via the GUI self._updateWireframe = None self._updateCamera = None # MANOS # extra UI elements self._wireframeMode = False self._changed = False self._checkbox = False self._colorEditor = wrapee._colorEditor self._eye = (2.5, 2.5, 2.5) self._target = (0.0, 0.0, 0.0) self._up = (0.0, 1.0, 0.0)
def init(self): """ Calls Decoratee init() and also sets up events """ self.wrapeeWindow.init() if self._imguiContext is None: print("Window could not be created! ImGUI Error: ") exit(1) else: print("Yay! ImGUI context created successfully") # GPTODO here is the issue: SDL2Decorator takes an SDLWindow as wrappee wheras # ImGUIDEcorator takes and SDL2Decorator and decorates it! if isinstance(self.wrapeeWindow, SDL2Window): self._imguiRenderer = SDL2Renderer(self.wrapeeWindow._gWindow) # # Setting up events that this class is publishing (if the EventManager is present in the decorated wrappee) # self._updateWireframe = Elements.pyECSS.Event.Event(name="OnUpdateWireframe", id=201, value=None) if self._wrapeeWindow.eventManager is not None: self._wrapeeWindow.eventManager._events[self._updateWireframe.name] = self._updateWireframe self._wrapeeWindow.eventManager._publishers[self._updateWireframe.name] = self # MANOS - START self._updateCamera = Elements.pyECSS.Event.Event(name="OnUpdateCamera", id=300, value=None) if self._wrapeeWindow.eventManager is not None: self._wrapeeWindow.eventManager._events[self._updateCamera.name] = self._updateCamera self._wrapeeWindow.eventManager._publishers[self._updateCamera.name] = self # MANOS - END print(f'{self.getClassName()}: init()') def display(self): """ ImGUI decorator display: calls wrapee (RenderWindow::display) as well as extra ImGUI widgets """ self.wrapeeWindow.display() gl.glClearColor(*self._colorEditor, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) #render the ImGUI widgets self.extra() #draw scenegraph tree widget self.scenegraphVisualiser() #print(f'{self.getClassName()}: display()') def event_input_process(self, running = True): """ process SDL2 basic events and input """ events = sdl2.ext.get_events() for event in events: if event.type == sdl2.SDL_KEYDOWN: if event.key.keysym.sym == sdl2.SDLK_ESCAPE: running = False if event.type == sdl2.SDL_QUIT: running = False #imgui event self._imguiRenderer.process_event(event) #imgui input self._imguiRenderer.process_inputs() return running def display_post(self): # this is important to draw the ImGUI in full mode and not wireframe! gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL) # render imgui (after 3D scene and just before the SDL double buffer swap window) imgui.render() self._imguiRenderer.render(imgui.get_draw_data()) # call the SDL window window swapping in the end of the scene as final render action self.wrapeeWindow.display_post() def extra(self): """sample ImGUI widgets to be rendered on a RenderWindow """ imgui.set_next_window_size(300.0, 200.0) #start new ImGUI frame context imgui.new_frame() #demo ImGUI window with all widgets # imgui.show_test_window() #new custom imgui window imgui.begin("Elements ImGUI window", True) #labels inside the window imgui.text("PyImgui + PySDL2 integration successful!") imgui.text(self._wrapeeWindow._gVersionLabel) # populate window with extra UI elements imgui.separator() imgui.new_line() # # wireframe Event updates the GL state self._changed, self._checkbox = imgui.checkbox("Wireframe", self._wireframeMode) if self._changed: if self._checkbox is True: self._wireframeMode = True self._updateWireframe.value = self._wireframeMode if self._wrapeeWindow.eventManager is not None: self.wrapeeWindow.eventManager.notify(self, self._updateWireframe) print(f"wireframe: {self._wireframeMode}") if self._checkbox is False: self._wireframeMode = False self._updateWireframe.value = self._wireframeMode if self._wrapeeWindow.eventManager is not None: self.wrapeeWindow.eventManager.notify(self, self._updateWireframe) print(f"wireframe: {self._wireframeMode}") # # simple slider for color self._changed, self._colorEditor = imgui.color_edit3("Color edit", *self._colorEditor) if self._changed: print(f"_colorEditor: {self._colorEditor}") imgui.separator() # # MANOS - START # simple slider for eye - IMPORTANT PART HERE self._changed, self._eye = imgui.drag_float3( "Eye", *self._eye, change_speed = 0.01, min_value=-10, max_value=10,format="%.3f") if self._changed: self._updateCamera.value = util.lookat(util.vec(self._eye), util.vec(self._target), util.vec(self._up)) print ("NEW CAMERA VALUE", self._updateCamera.value) if self._wrapeeWindow.eventManager is not None: self.wrapeeWindow.eventManager.notify(self, self._updateCamera) print(f"_eye: {self._eye}") imgui.separator() # # simple slider for target self._changed, self._target = imgui.drag_float3( "Target", *self._target, change_speed = 0.01, min_value=-10, max_value=10,format="%.3f") if self._changed: self._updateCamera.value = util.lookat(util.vec(self._eye), util.vec(self._target), util.vec(self._up)) print ("NEW CAMERA VALUE", self._updateCamera.value) if self._wrapeeWindow.eventManager is not None: self.wrapeeWindow.eventManager.notify(self, self._updateCamera) print(f"_target: {self._target}") imgui.separator() # simple slider for up self._changed, self._up = imgui.drag_float3( "Up", *self._up, change_speed = 0.01 ,min_value=-5, max_value=5,format="%.3f") if self._changed: self._updateCamera.value = util.lookat(util.vec(self._eye), util.vec(self._target), util.vec(self._up)) print ("NEW CAMERA VALUE", self._updateCamera.value) if self._wrapeeWindow.eventManager is not None: self.wrapeeWindow.eventManager.notify(self, self._updateCamera) print(f"_up: {self._up}") imgui.separator() # MANOS - END # simple FPS counter strFrameRate = str(("Application average: ", imgui.get_io().framerate, " FPS")) imgui.text(strFrameRate) #end imgui frame context imgui.end() #print(f'{self.getClassName()}: extra()') def scenegraphVisualiser(self): """display the ECSS in an ImGUI tree node structure Typically this is a custom widget to be extended in an ImGUIDecorator subclass """ pass def accept(self, system: Elements.pyECSS.System, event = None): system.apply2ImGUIDecorator(self, event)
[docs]class ImGUIecssDecorator(ImGUIDecorator): """custom ImGUI decorator for this example :param ImGUIDecorator: [description] :type ImGUIDecorator: [type] """
[docs] def __init__(self, wrapee: RenderWindow, imguiContext = None): super().__init__(wrapee, imguiContext) self.selected = None; # Selected should be a component # TRS Variables self.translation = {}; self.translation["x"] = 0; self.translation["y"] = 0; self.translation["z"] = 0; self.rotation = {}; self.rotation["x"] = 0; self.rotation["y"] = 0; self.rotation["z"] = 0; self.scale = {}; self.scale["x"] = 0; self.scale["y"] = 0; self.scale["z"] = 0; self.color = [255, 50, 50];
def scenegraphVisualiser(self): """display the ECSS in an ImGUI tree node structure Typically this is a custom widget to be extended in an ImGUIDecorator subclass """ sceneRoot = self.wrapeeWindow.scene.world.root.name if sceneRoot is None: sceneRoot = "ECSS Root Entity" twoColumn = False if twoColumn: # 2 Column Version imgui.begin("ECSS graph") imgui.columns(2,"Properties") if imgui.tree_node(sceneRoot, imgui.TREE_NODE_OPEN_ON_ARROW): self.drawNode(self.wrapeeWindow.scene.world.root) imgui.tree_pop() imgui.next_column() imgui.text("Properties") imgui.separator() else: imgui.begin("ECSS graph") imgui.columns(1,"Properties") # below is a recursive call to build-up the whole scenegraph as ImGUI tree # if imgui.tree_node(sceneRoot, imgui.TREE_NODE_OPEN_ON_ARROW): # self.drawNode(self.wrapeeWindow.scene.world.root) # imgui.tree_pop() # imgui.next_column() imgui.text("Properties") imgui.separator() # smallerTRSgui = True #TRS sample # if(isinstance(self.selected, BasicTransform)): if imgui.tree_node("Translation", imgui.TREE_NODE_OPEN_ON_ARROW): # changed, value = imgui.slider_float("X", self.translation["x"], -3, 3, "%.01f", 1); # self.translation["x"] = value; # changed, value = imgui.slider_float("Y", self.translation["y"], -3, 3, "%.01f", 1); # self.translation["y"] = value; # changed, value = imgui.slider_float("Z", self.translation["z"], -3, 3, "%.01f", 1); # self.translation["z"] = value; changed, value = imgui.drag_float3("X,Y,Z",self.translation["x"],self.translation["y"],self.translation["z"], 0.01, -30, 30, "%.001f", 1); self.translation["x"],self.translation["y"],self.translation["z"] = value[0],value[1], value[2] imgui.tree_pop(); if imgui.tree_node("Rotation", imgui.TREE_NODE_OPEN_ON_ARROW): # changed, value = imgui.slider_float("X", self.rotation["x"], -90, 90, "%.1f", 1); # self.rotation["x"] = value; # changed, value = imgui.slider_float("Y", self.rotation["y"], -90, 90, "%.1f", 1); # self.rotation["y"] = value; # changed, value = imgui.slider_float("Z", self.rotation["z"], -90, 90, "%.1f", 1); # self.rotation["z"] = value; changed, value = imgui.drag_float3("X,Y,Z",self.rotation["x"],self.rotation["y"],self.rotation["z"], 1, -180, 180, "%.1f", 1); self.rotation["x"],self.rotation["y"],self.rotation["z"] = value[0],value[1], value[2] imgui.tree_pop(); if imgui.tree_node("Scale", imgui.TREE_NODE_OPEN_ON_ARROW): # changed, value = imgui.slider_float("X", self.scale["x"], 0, 3, "%.01f", 1); # self.scale["x"] = value; # changed, value = imgui.slider_float("Y", self.scale["y"], 0, 3, "%.01f", 1); # self.scale["y"] = value; # changed, value = imgui.slider_float("Z", self.scale["z"], 0, 3, "%.01f", 1); # self.scale["z"] = value; changed, value = imgui.drag_float3("X,Y,Z",self.scale["x"],self.scale["y"],self.scale["z"], 0.01, 0, 4, "%.01f", 1); self.scale["x"],self.scale["y"],self.scale["z"] = value[0],value[1], value[2] imgui.tree_pop(); if twoColumn: pass else: imgui.separator() if imgui.tree_node(sceneRoot, imgui.TREE_NODE_OPEN_ON_ARROW): self.drawNode(self.wrapeeWindow.scene.world.root) imgui.tree_pop() imgui.end() def drawNode(self, component): #create a local iterator of Entity's children if component._children is not None: debugIterator = iter(component._children) #call print() on all children (Concrete Components or Entities) while there are more children to traverse done_traversing = False while not done_traversing: try: comp = next(debugIterator) imgui.indent(10) except StopIteration: done_traversing = True else: # using ## creates unique labels, without showing anything after ## # see: https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-have-multiple-widgets-with-the-same-label if imgui.tree_node(comp.name + "##" + str(comp.id), imgui.TREE_NODE_OPEN_ON_ARROW): imgui.text(comp.name) _, selected = imgui.selectable(comp.__str__(), True) if selected: if comp != self.selected: # First time selecting it. Set trs values to GUI; self.selected = comp; if isinstance(comp, BasicTransform): [x, y, z] = comp.translation; self.translation["x"] = x; self.translation["y"] = y; self.translation["z"] = z; [x, y, z] = comp.scale; self.scale["x"] = x; self.scale["y"] = y; self.scale["z"] = z; [x, y, z] = comp.rotationEulerAngles; self.rotation["x"] = x; self.rotation["y"] = y; self.rotation["z"] = z; # elif isinstance(comp, GameObjectEntity): # self.color = comp.color.copy(); else: # Set GUI values to trs; if isinstance(comp, BasicTransform): transMat = util.translate(self.translation["x"], self.translation["y"], self.translation["z"]); rotMatX = util.rotate((1, 0, 0), self.rotation["x"]) rotMatY = util.rotate((0, 1, 0), self.rotation["y"]) rotMatZ = util.rotate((0, 0, 1), self.rotation["z"]) scaleMat = util.scale(self.scale["x"], self.scale["y"], self.scale["z"]) comp.trs = util.identity() @ transMat @ rotMatX @ rotMatY @ rotMatZ @ scaleMat; # comp.trs = scaleMat @ rotMatZ @ rotMatY @ rotMatX @ transMat; elif hasattr(comp, "drawSelfGui"): comp.drawSelfGui(imgui); imgui.tree_pop() self.drawNode(comp) # recursive call of this method to traverse hierarchy imgui.unindent(10) # Corrent placement of unindent
[docs]class RenderGLStateSystem(System): """ System that operates on a RenderDecorator (ImGUIDecorator) and affect GL State """
[docs] def __init__(self, name=None, type=None, id=None): super().__init__(name, type, id)
def update(self): """ method to be subclassed for behavioral or logic computation """ pass def apply2ImGUIDecorator(self, imGUIDecorator, event = None): """ method for behavioral or logic computation when visits Components. In this case update GL State from ImGUIDecorator """ pass def apply2SDLWindow(self, sdlWindow, event = None): """method for behavioral or logic computation when visits Components. In this case update GL State from SDLWindow :param sdlWindow: [description] :type sdlWindow: [type] :param event: [description], defaults to None :type event: [type], optional """ if event.name == "OnUpdateWireframe": print(f"RenderGLStateSystem():apply2SDLWindow() actuator system for: {event}") sdlWindow._wireframeMode = event.value # MANOS - START if event.name == "OnUpdateCamera": print(f"OnUpdateCamera: RenderGLStateSystem():apply2SDLWindow() actuator system for: {event}") sdlWindow._myCamera = event.value
# MANOS - END if __name__ == "__main__": # # The client code. gWindow = SDL2Window(openGLversion=3) # uses openGL version 3.2 instead of the default 4.1 gWindow.init() gWindow.init_post() running = True # MAIN RENDERING LOOP while running: gWindow.display() running = gWindow.event_input_process(running) gWindow.display_post() gWindow.shutdown()