source: framspy/gui/widgets/glFrame.py @ 1198

Last change on this file since 1198 was 1198, checked in by Maciej Komosinski, 14 months ago

Added simple Python GUI for Framsticks library/server

File size: 8.0 KB
Line 
1from xmlrpc.client import Boolean
2from gui.visual.entity import Entity
3import OpenGL.GL as gl
4from pyopengltk import OpenGLFrame
5from gui.visual.camera import Camera
6from gui.visual.player import Player
7from gui.visual.masterRenderer import MasterRenderer
8from gui.visual.loader import Loader
9from gui.visual.objLoader import OBJLoader
10from gui.visual.player import Player
11from gui.visual.mouse import Mouse
12from gui.framsutils.creature import Creature
13from typing import List, Callable
14import threading
15import time as timetime
16from gui.utils import Swap
17from typing import Dict
18from gui.visual.modelData import ModelData
19
20class AppOgl(OpenGLFrame):
21    class GLContext(object):
22        pass
23
24    def __init__(self, *args, **kw):
25        super().__init__(*args, **kw)
26        self.REFRESH_RATE = 0.1
27        self.player = Player(10, 10, 0, 0, 0, 0)
28        self.camera = Camera(self.player)
29        self.entities = []
30        self.frams_readCreatures: Callable[[None], List[Creature]] = None
31        self.frams_readCreatures_color: Boolean = False
32        self.onDraw: Callable[[], None] = lambda: None
33        self.commThread = threading.Thread(target=self.commThread, daemon=True)
34        self.commThreadLock = threading.Lock()
35        self.read_creature_semaphore = threading.Semaphore()
36        self.creatures: List[Creature] = []
37        self.swap_buffer = Swap(init=[])
38        self.swap_buffer.update([])
39        self.swap_buffer.update([])
40        self.commThread.start()
41
42    #show tri-colored axis instead of balls
43    SHOW_AXIS = False
44
45    NEURON_SCALE = 1.5
46    OBJ_PATH = "gui/res/obj/"
47    TEX_PATH = "gui/res/img/"
48
49    NEURONS = ["|", "@", "G", "Gpart", "T", "S"]
50
51    def neuronname_in_filename(self, neuronname):
52        if neuronname == "|":
53            return "bend"
54        elif neuronname == "@":
55            return "rot"
56        return neuronname
57
58    def initgl(self):
59        gl.glClearColor(0, 0, 0.4, 0)
60       
61        self.loader = Loader()
62
63        if self.SHOW_AXIS:
64            self.bodyPartModel = OBJLoader.loadOBJ(self.OBJ_PATH+"axis.obj", self.TEX_PATH+"axis.png", self.loader)
65        else:
66            self.bodyPartModel = OBJLoader.loadOBJ(self.OBJ_PATH+"part.obj", self.TEX_PATH+"green2.png", self.loader)
67        self.jointModel = OBJLoader.loadOBJ(self.OBJ_PATH+"stick5red3.obj", self.TEX_PATH+"green2.png", self.loader)
68        self.neurons: Dict[str, ModelData] = dict()
69        for n in self.NEURONS:
70            self.neurons[n] = OBJLoader.loadOBJ(self.OBJ_PATH+"neuro-"+self.neuronname_in_filename(n)+".obj", self.TEX_PATH+"amber.jpg", self.loader)
71
72        self.renderer = MasterRenderer(self.loader)
73
74        gl.glEnable(gl.GL_DEPTH_TEST)
75        gl.glClearDepth(1.0)
76        gl.glEnable(gl.GL_TEXTURE_2D)
77
78        self.initalized = True
79        self._resize(self.width, self.height)
80
81    def init_context(self):
82        self.context = self.GLContext()
83
84    def redraw(self):
85        #call onDraw callback  only for frams library
86        self.onDraw()
87        self.entities.clear()
88        self.creatures: List[Creature] = self.swap_buffer.get()
89        #for every creature, prepare entities for every parts, joints and neurons
90        for creature in self.creatures:
91            parts = creature.mechParts
92            joints = creature.joints
93            neurons = creature.neurons
94
95            '''
96            TODO: solid shapes should be handled here
97            obj models should be loaded in initgl method and used depending on the shape type (probably need to add new lists to Creature class).
98            Position should already be loaded in the part object, as well as rotation matrix, you need to add scale in FramsSocket and FramsLib.
99            You can add scale in each axis in the Entity constructor or as independent properties of the Entity class.
100            scaleX, scaleY, scaleZ have higher priority than scale only if all three (x, y, z) are set.
101            '''
102            for i, part in enumerate(parts):
103                rotMatrix = creature.partRotationMatrix(i)
104                partEntity = Entity(part[0], part[1], part[2], self.bodyPartModel, scale=0.7, rotMatrix=rotMatrix)
105                if i < len(creature.colorsPart):
106                    partEntity.color = creature.colorsPart[i]
107                self.entities.append(partEntity)
108
109            for i in range(len(joints)):
110                translation = creature.jointTranslation(i)
111                rotMatrix = creature.jointRotation(i)
112                jointEntity = Entity(translation[0], translation[1], translation[2], self.jointModel, rotMatrix=rotMatrix)
113                jointEntity.scaleX = creature.jointLength(i)
114                jointEntity.scaleY = 1
115                jointEntity.scaleZ = 1
116                if i < len(creature.colorsJoint):
117                    partEntity.color = creature.colorsJoint[i]
118                self.entities.append(jointEntity)
119
120            for i, neuron in enumerate(neurons):
121                if creature.styleNeuron[i] in self.neurons:
122                    style = creature.styleNeuron[i]
123                    if neuron[0] >= 0:
124                        translation = creature.partTranslation(neuron[0])
125                        rotMatrix = creature.partRotationMatrix(neuron[0])
126                        rotMatrix = rotMatrix * creature.neuronRelativeOrient[i]
127                        neuronEntity = Entity(translation[0], translation[1], translation[2], self.neurons[style], scale=self.NEURON_SCALE, rotMatrix=rotMatrix)
128                    else:
129                        translation = creature.jointTranslation(neuron[1])
130                        if style == 'G':
131                            rotMatrix = creature.jointRotation(neuron[1])
132                        else:
133                            rotMatrix = creature.partRotationMatrix(joints[neuron[1]][0])
134                        rotMatrix = rotMatrix * creature.neuronRelativeOrient[i]
135                        neuronEntity = Entity(translation[0], translation[1], translation[2], self.neurons[style], scale=self.NEURON_SCALE, rotMatrix=rotMatrix)
136                    self.entities.append(neuronEntity)
137
138        self.camera.move()
139        self.renderer._isTexturesOn = not self.frams_readCreatures_color
140        self.renderer.renderScene(self.player, self.entities, self.camera)
141
142    #reload all creatures from frams with self.REFRESH_RATE interval
143    def commThread(self):
144        while True:
145            if self.frams_readCreatures:
146                with self.read_creature_semaphore:
147                    c = self.frams_readCreatures(self.frams_readCreatures_color)
148                self.swap_buffer.update(c)
149            timetime.sleep(self.REFRESH_RATE)
150
151    def onResize(self, event):
152        width, height = event.width, event.height
153        self._resize(width, height)
154
155    def _resize(self, width, height):
156        self.width = width
157        self.height = height
158        try:
159            self.initalized
160            gl.glViewport(0, 0, width, height)
161            self.renderer.resize(width, height)
162        except AttributeError:
163            pass
164
165    def onMouseMotion(self, event):
166        Mouse.setXY(event.x, event.y)
167
168    def onScroll(self, event):
169        if event.delta > 0:
170            Mouse.incrementDWheel(1)
171        else:
172            Mouse.incrementDWheel(-1)
173
174    def onMouseClick(self, event):
175        if event.num == 1:
176            Mouse.setButton(Mouse.MOUSE_LEFT)
177        elif event.num == 3:
178            Mouse.setButton(Mouse.MOUSE_RIGHT)
179
180    def onMouseRelease(self, event):
181        Mouse.setButton(Mouse.MOUSE_NONE)
182
183    def onMouseEnter(self, event):
184        Mouse.setXY(event.x, event.y)
185
186    def reloadWorld(self, worldType: int, simType: int, worldSize: float, worldMap: str, worldBoundaries: int, worldWaterLevel: float) -> None:
187        self.renderer.reloadWorld(self.loader, worldType, simType, worldSize, worldMap, worldBoundaries, worldWaterLevel)
188        self.camera.setPosition(worldSize / 2.0, worldSize / 2.0)
189        self.camera.setZoomScale(worldSize / 20)
190        self.camera.setZoom(worldSize)
Note: See TracBrowser for help on using the repository browser.