View difference between Paste ID: Ftt5GxvJ and TWRh5qDF
SHOW: | | - or go back to the newest paste.
1
#!/usr/bin/env python
2
#
3
# Copyright (c) 2011-2012 Wiktor Starzyk, Faisal Z. Qureshi
4
#
5
# This file is part of the Virtual Vision Simulator.
6
#
7
# The Virtual Vision Simulator is free software: you can 
8
# redistribute it and/or modify it under the terms 
9
# of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, 
11
# or (at your option) any later version.
12
#
13
# The Virtual Vision Simulator is distributed in the hope 
14
# that it will be useful, but WITHOUT ANY WARRANTY; 
15
# without even the implied warranty of MERCHANTABILITY or 
16
# FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with the Virtual Vision Simulator.  
21
# If not, see <http://www.gnu.org/licenses/>.
22
#
23
24
25
import sys, os
26
import logging
27
28
from math import tan, radians
29
30
from direct.showbase.ShowBase import ShowBase
31
from direct.gui.OnscreenText import OnscreenText as OST
32
from direct.task import Task
33
34
from pandac.PandaModules import AntialiasAttrib, ClockObject, TextNode
35
from pandac.PandaModules import Vec3, VBase4
36
from pandac.PandaModules import Camera, OrthographicLens
37
from pandac.PandaModules import loadPrcFileData
38-
from pandac.PandaModules import WindowProperties 
38+
from pandac.PandaModules import WindowProperties
39
from pandac.PandaModules import FrameBufferProperties
40
from pandac.PandaModules import GraphicsPipe
41
42
from builders.object_builder import ObjectBuilder
43
from builders.pedestrian_builder import PedestrianBuilder
44
from builders.light_builder import LightBuilder
45
from builders.camera_builder import PandaCameraBuilder
46
from file_io.scene_file import *
47
from file_io.pedestrian_file import *
48
49
from simulator.model import Model
50
from simulator.model import DIRECTIONALLIGHT
51-
WIDTH = 1024
51+
52-
HEIGHT = 768
52+
53
WIDTH = 1200
54
HEIGHT = 600
55
56
loadPrcFileData("", "win-size %s %s" % (WIDTH, HEIGHT))
57
loadPrcFileData("", "texture-anisotropic-degree 10")
58
59
LIGHTS_PER_OBJECT = 4
60
61
PTZ_CAMERA = 1
62
WIDE_FOV_CAMERA = 2
63
64
MANUAL_CAMERA = False
65
66
67
def Length(a, b):
68
    ax, ay, az = a
69
    bx, by, bz = b
70
    length = (ax-bx) ** 2 + (ay-by) ** 2
71
    return length
72
73
74
class VirtualWorld(ShowBase): 
75
76
    def __init__(self, scene_file, pedestrian_file, dir, mode):
77
        ShowBase.__init__(self)
78
79
        self.globalClock = ClockObject.getGlobalClock()
80
        self.globalClock.setMode(ClockObject.MSlave)
81
        
82-
        self.loadScene(scene_file)
82+
83
        self.model = Model(dir)
84
        #self.loadScene(scene_file)
85
        self.loadPedestrians(pedestrian_file)
86
        
87
        #self.cam_label = OST("Top Down", pos=(0, 0.95), fg=(1,1,1,1), 
88
        #                     scale=0.05, mayChange=True)
89
        #self.time_label = OST("Time: 0.0", pos=(-1.3, 0.95), fg=(1,1,1,1), 
90
        #                      scale=0.06, mayChange=True, align=TextNode.ALeft)
91
                                       
92
        #self.accept("arrow_right", self.changeCamera, [1])
93
        #self.accept("arrow_left", self.changeCamera, [-1])
94
        self.accept("escape", self.exit)
95
        self.accept("aspectRatioChanged", self.setAspectRatio)
96
        self.accept("window-event", self.windowChanged)
97
        
98
        #base.disableMouse()
99
        lens = OrthographicLens()
100
        lens.setFilmSize(1550, 1000)
101
        
102
        self.default_camera = render.attachNewNode(Camera("top down"))
103
        self.default_camera.node().setLens(lens)
104
        self.default_camera.setPosHpr(Vec3( -75, 0, 2200), Vec3(0, -90, 0))
105-
        self.display_regions.append(base.win.makeDisplayRegion(0, 0.33, 0.5, 1))
105+
106-
        self.display_regions.append(base.win.makeDisplayRegion(0.33, 0.66, 0.5, 1))
106+
        #self.new_window = base.openWindow()
107-
        self.display_regions.append(base.win.makeDisplayRegion(0.66, 1, 0.5, 1))
107+
108-
        self.display_regions.append(base.win.makeDisplayRegion(0, 0.33, 0, 0.5))
108+
        new_window_fbp = FrameBufferProperties.getDefault()
109-
        self.display_regions.append(base.win.makeDisplayRegion(0.33, 0.66, 0, 0.5))
109+
        new_window_properties = WindowProperties.getDefault()
110-
        self.display_regions.append(base.win.makeDisplayRegion(0.66, 1, 0, 0.5))
110+
        new_window = base.graphicsEngine.makeOutput(base.pipe, 'Top Down View Window', 0, new_window_fbp, new_window_properties, GraphicsPipe.BFRequireWindow)
111
        
112-
	    self.assign_display_region_to_camera(self.display_regions[i], i)
112+
113
	self.display_regions.append(new_window.makeDisplayRegion())
114
        self.display_regions.append(base.win.makeDisplayRegion(0, 0.32, 0.5, 1))
115
        self.display_regions.append(base.win.makeDisplayRegion(0.34, 0.65, 0.5, 1))
116
        self.display_regions.append(base.win.makeDisplayRegion(0.67, 1, 0.5, 1))
117
        self.display_regions.append(base.win.makeDisplayRegion(0, 0.32, 0, 0.5))
118
        self.display_regions.append(base.win.makeDisplayRegion(0.34, 0.65, 0, 0.5))
119
        self.display_regions.append(base.win.makeDisplayRegion(0.67, 1, 0, 0.5))
120
	self.display_regions[0].setCamera(self.default_camera)
121
        
122
        #self.setCamera(0)
123
124
        self.controller = Controller(self, mode)
125
        self.taskMgr.add(self.updateCameraModules, "Update Camera Modules", 80)
126
        
127
        self.globalClock.setFrameTime(0.0)
128-
    def assign_display_region_to_camera(self, display_region, camera_number):
128+
129
        self.height = HEIGHT
130-
        display_region.setClearColor(VBase4(0, 0, 0, 1))
130+
131-
        display_region.setClearColorActive(True)
131+
132-
        display_region.setClearDepthActive(True)
132+
133-
        if camera_number == 0:
133+
134-
            display_region.setCamera(self.default_camera)
134+
135
        """props_new_window = WindowProperties()
136
        props_new_window.setTitle('Top Down View')
137-
            index = camera_number - 1
137+
        self.new_window.requestProperties(props_new_window)"""
138
139
140
    def assign_display_region_to_camera(self):
141-
                display_region.setCamera(camera_np)
141+
142
        base.win.setClearColorActive(True)
143
	base.win.setClearColor(VBase4(0, 0, 0, 1))
144
        
145
        for i in range(0, len(self.display_regions)):
146
	    display_region = self.display_regions[i]
147
	    display_region.setClearColor(VBase4(0, 0, 0, 1))
148
	    display_region.setClearColorActive(True)
149
	    display_region.setClearDepthActive(True)
150
	    if i == 0:
151
		display_region.setCamera(self.default_camera)
152
	    else:
153
		camera_list = self.model.getCameraList()
154
		index = i - 1
155
		if index < len(camera_list):
156
		    camera = camera_list[index]
157
		    camera_np = camera.getCameraNode()
158
		    display_region.setCamera(camera_np)
159
        
160
        
161
    def getModel(self):
162
        """
163
        Returns the model that stores all of the cameras, pedestrians and 
164
        static objects in the scene.
165
        """
166
        return self.model
167
168
169
    def getController(self):
170
        """
171
        Returns a controller that is used to control the world time.
172
        """
173
        return self.controller
174
175
176
    def getTime(self):
177
        """
178
        Returns the current time in the world.
179
        """
180
        return self.globalClock.getFrameTime()
181
182
183
    def loadScene(self, scene_file):
184
        """
185
        Loads the static objects that make up the scene. Also loads the lights
186
        that illuminate the scene and for performance implications, sets what 
187
        lights affect what objects.
188
        """
189
        if not os.path.exists(scene_file):
190
            logging.error("The path '%s' does not exist" % scene_file)
191
            sys.exit()
192
        light_builder = LightBuilder(self)
193
        object_builder = ObjectBuilder(self, self.directory)
194
        parser = SceneFileParser(self.model, object_builder, light_builder)
195
        parser.parse(scene_file)
196
        
197
        self.setUpLights()
198
199
200
    def setUpLights(self):
201
        # Set what lights illuminate what objects
202
        light_list = self.model.getLightList()
203
        static_objects = self.model.getObjectList()
204
        for object in static_objects:
205
            if object.hasLighting():
206
                model_root = object.getModel().getChildren()[0]
207
                children = model_root.getChildren()
208
                for child in children:
209
                    light_map = {}
210
                    for index, light in enumerate(light_list):
211
                        distance = Length(child.getPos(render), light.getPos())
212
                        half_fov = light.node().getLens().getFov()[0] / 2.0
213
                        height = light.getPos()[2]
214
                        radius = height * tan(radians(half_fov))
215
                        if distance > radius ** 2 + 2500 + 10:
216
                            continue
217
                        if distance not in light_map:
218
                            light_map[distance] = [index]
219
                        else:
220
                            light_map[distance].append(index)
221
222
                    sorted_lights = sorted(light_map.keys())
223
                    light_count = 0
224
                    for key in sorted_lights:
225
                        for i in light_map[key]:
226
                            child.setLight(light_list[i])
227
                            light_count += 1
228
                            if light_count > LIGHTS_PER_OBJECT:
229
                                break
230
                        if light_count > LIGHTS_PER_OBJECT:
231
                            break
232
                    child.flattenStrong()
233
        
234
        # Apply a directional light to the static models        
235
        light_list = self.model.getLightList(DIRECTIONALLIGHT)
236
        if light_list:
237
            for object in static_objects:
238
                if object.hasLighting():
239
                    model_root = object.getModel().getChildren()[0]
240
                    model_root.setLight(light_list[0])
241
242
        render.setShaderAuto()
243
        render.setAntialias(AntialiasAttrib.MLine)
244
245
246
    def loadPedestrians(self, pedestrian_file):
247
        """Loads the pedestrians into the scene."""
248
        if not os.path.exists(pedestrian_file):
249
            logging.error("The path '%s' does not exist" % pedestrian_file)
250
            sys.exit()
251
        pedestrian_builder = PedestrianBuilder(self, "../media/characters/")
252
        parser = PedestrianFileParser(self.model, pedestrian_builder)
253
        parser.parse("../media/characters/pedestrians.xml")
254
        parser.parse(pedestrian_file)
255
256
257
    def addCamera(self, config):
258
        """
259
        This method is used to add a new panda camera to the world. The panda
260
        camera is returned so that it can be linked with a camera module.
261
        """
262
        type = config.type
263
        cam_builder = PandaCameraBuilder(self)
264
        if type == WIDE_FOV_CAMERA:
265
            pass
266
        else:
267
            camera = cam_builder.buildPandaPTZCamera(config)
268
            self.model.addCamera(camera)
269
        return camera
270
271
272
    def setAspectRatio(self):
273
        """
274
        This method is called when the aspect ratio of the window changes.
275
        It updates the aspect ratios of all the cameras.
276
        """
277
        width = base.win.getXSize()
278
        height = base.win.getYSize()
279
        ratio = self.camLens.getAspectRatio()
280
        camera_list = self.model.getCameraList()
281
        for camera in camera_list:
282
            camera.setAspectRatio(ratio)
283
            camera.setImageSize(width, height)
284
285
        self.default_camera.node().getLens().setAspectRatio(ratio)
286
        r =  width / float(height)
287
        #self.time_label.setPos(-r, 0.95)
288
289
290
    def changeCamera(self, num):
291
        """
292
        This method is used to toggle the camera that is viewed in the main 
293
        window. Typically num is either 1 or -1 denoting whether to toggle up
294
        or down the camera list.
295
        """
296
        number = self.cur_camera + 1 + num
297
        num_cameras = len(self.model.getCameraList())
298
        if number > num_cameras:
299
            number = 0
300
        elif number < 0:
301
            number = num_cameras
302
        self.setCamera(number)
303
304
305
    def setCamera(self, num):
306
        """
307
        This method sets which cameras view is shown in the panda3d window.
308
        """
309
        if MANUAL_CAMERA:
310
            self.cur_camera = num -1
311
            return
312
        
313
        self.display_region.setClearColor(VBase4(0, 0, 0, 1))
314
        self.display_region.setClearColorActive(True)
315
        self.display_region.setClearDepthActive(True)
316
        if num == 0:
317
            self.cur_camera = -1
318
            self.display_region.setCamera(self.default_camera)
319
            self.cam_label.setText("Top Down")
320
        else:
321
            camera_list = self.model.getCameraList()
322
            index = num - 1
323
            if index < len(camera_list):
324
                self.cur_camera = index
325
                camera = camera_list[index]
326
                camera_np = camera.getCameraNode()
327
                self.display_region.setCamera(camera_np)
328
                name = camera.getName()
329
                status_label = camera.getStatusLabel()
330
                label = "%s: %s" %(name, status_label)
331
                self.cam_label.setText(label)
332
333
334
    def step(self, increment):
335
        """
336
        This method updates the world by one time step.
337
        """
338
        if increment:
339
            new_time = self.globalClock.getFrameTime() + increment
340
        else:
341
            new_time = self.globalClock.getRealTime()
342
            
343
	print self.globalClock.getRealTime()
344
            
345
        self.globalClock.setFrameTime(new_time)
346
        #self.time_label.setText("Time: %.2f" % new_time)
347
        
348
        self.updateActors()
349
        self.updateCameras()
350
351
352
    def updateActors(self):
353
        """
354
        This method updates the pedestrians in the scene by calling their update
355
        functions.
356
        """
357
        pedestrians = self.model.getPedestrianList()
358
        time = self.getTime()
359
        for pedestrian in pedestrians:
360
            if pedestrian.isActive(time):
361
                pedestrian.update(time)
362
363
364
    def updateCameras(self):
365
        """
366
        This method updates the panda cameras which are used to provide the
367
        higher level camera modules with rendered images of the scene. There
368
        is one panda camera for each camera module.
369
        """
370
        time = self.getTime()
371
        camera_list = self.model.getCameraList()
372
        for camera in camera_list:
373
            camera.update(time)
374
        
375
        """if self.cur_camera != -1:
376
            cur_camera = camera_list[self.cur_camera]
377
            if cur_camera.statusChanged():
378
                name = cur_camera.getName()
379
                status_label = cur_camera.getStatusLabel()
380
                label = "%s: %s" %(name, status_label)
381
                self.cam_label.setText(label)"""
382
383
384
    def updateCameraModules(self, task):
385
        """
386
        This method updates the camera modules by calling their update function.
387
        This allows the camera modules to process messages and complete any
388
        tasks that were assigned to them.
389
        """
390
        time = self.getTime()
391
        for camera in self.model.getCameraModules():
392
            camera.update(time)
393
        return Task.cont
394
395
396
    def windowChanged(self, window):
397
        """
398
        This function is called when the window is modified. It updates the
399
        image size used by the cameras when getting the rendered image from the 
400
        texture.
401
        """
402
        wp = window.getProperties()
403
        width = wp.getXSize()
404
        height = wp.getYSize()
405
        if width != self.width or height != self.height:
406
            self.width = width
407
            self.height = height
408
            camera_list = self.model.getCameraList()
409
            for camera in camera_list:
410
                camera.setImageSize(width, height)
411
        self.windowEvent(window)
412
413
414
    def exit(self):
415
        sys.exit()