vis.py 16.5 KB
Newer Older
Ahmad Reza's avatar
Ahmad Reza committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import datetime, math, os, time
from pyglet.gl import *
from pyglet.window import mouse
import pyglet.window.key as key

# screenshot manager parameters
screenshot_directory = 'screenshots/'
screenshot_file_type = '.png'

# control parameters
zoom_enabled = True
zoom_min = 4
zoom_max = 128
zoom_init = 16
zoom_speed = 1 / 50

translation_enabled = True
translation_init = (0, 0)

# presentation parameters
window_width = 800
window_height = 600
window_resizable = True  # set to False to force resolution even if window does not fit on screen
show_grid = True
rotate_thirty_degree = False  # the grid is not drawn correctly if the view is rotated!

# rendering parameters
Ahmad Reza's avatar
Ahmad Reza committed
28
29
target_frame_rate = 10
busy_waiting_time = 1
Ahmad Reza's avatar
Ahmad Reza committed
30
31
32
print_frame_stats = False

# simulation parameters
33
rounds_per_second = 10
Ahmad Reza's avatar
Ahmad Reza committed
34
35
36
37

# tile_alpha = 0.6
particle_alpha = 1

38
marker_alpha = 1
Ahmad Reza's avatar
Ahmad Reza committed
39
40


41
def coords_to_sim(coords):
Ahmad Reza's avatar
Ahmad Reza committed
42
43
44
    return coords[0], coords[1] * math.sqrt(3/4)


45
def sim_to_coords(x, y):
Ahmad Reza's avatar
Ahmad Reza committed
46
47
48
    return x, round(y / math.sqrt(3/4), 0)


49
def window_to_sim(x, y, view):
Ahmad Reza's avatar
Ahmad Reza committed
50
51
52
53
54
55
56
57
58
    x_coord = view.left + (view.right - view.left) * (x / view.width)  # correct
    y_coord = view.bottom + (view.top - view.bottom) * (y / view.height)  # not correct
    return x_coord, y_coord


class ScreenshotManager:
    dt = datetime.datetime.now()
    #prefix = dt.isoformat(sep = '_', timespec = 'seconds').replace(':', '') + '_'
    prefix = dt.isoformat(sep='_').replace(':', '') + '_'
Ahmad Reza's avatar
Ahmad Reza committed
59

Ahmad Reza's avatar
Ahmad Reza committed
60
61
62
63
64
65
66
67
68
69
70
71
72
    def takeScreenshot():
        if not os.path.exists(screenshot_directory):
            os.makedirs(screenshot_directory)

        index = math.floor(time.monotonic() * 10**3)
        file_name = screenshot_directory + ScreenshotManager.prefix + str(index) + screenshot_file_type
        pyglet.image.get_buffer_manager().get_color_buffer().save(file_name)


class View:
    def __init__(self):
        self.focusPos = translation_init
        self.zoom = zoom_init
Ahmad Reza's avatar
Ahmad Reza committed
73
        halfZoomRec = 0.5 / self.zoom
Ahmad Reza's avatar
Ahmad Reza committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

    def setDimensions(self, width, height):
        self.width = width
        self.height = height
        self.update()

    def drag(self, dx, dy):
        if not translation_enabled:
            return

        self.focusPos = (self.focusPos[0] - dx / self.zoom, self.focusPos[1] - dy / self.zoom)
        self.update()

    def scroll(self, x, y, scroll_x, scroll_y):
        if not zoom_enabled:
            return

        oldPos = (self.left + x / self.zoom, self.bottom + y / self.zoom)
        self.zoom = self.zoom * math.exp(-scroll_y * zoom_speed)
        self.zoom = max(self.zoom, zoom_min)
        self.zoom = min(self.zoom, zoom_max)
        self.update()
        newPos = (self.left + x / self.zoom, self.bottom + y / self.zoom)
        self.focusPos = (self.focusPos[0] + oldPos[0] - newPos[0], self.focusPos[1] + oldPos[1] - newPos[1])
        self.update()

    def update(self):
        halfZoomRec = 0.5 / self.zoom
        self.left = self.focusPos[0] - halfZoomRec * self.width;
        self.right = self.focusPos[0] + halfZoomRec * self.width;
        self.bottom = self.focusPos[1] - halfZoomRec * self.height;
        self.top = self.focusPos[1] + halfZoomRec * self.height;

class VisWindow(pyglet.window.Window):
Ahmad Reza's avatar
Ahmad Reza committed
108
109
    def __init__(self, window_size_x, window_size_y, world):
        #super().__init__(world.get_sim_x_size(), world.get_sim_y_size(), resizable=window_resizable, vsync=False, caption="Simulator")
Ahmad Reza's avatar
Ahmad Reza committed
110
111
112
113
114
        super().__init__(window_size_x, window_size_y , resizable=window_resizable, vsync=False, caption="Simulator")
        self.window_active = True
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClearDepth(1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
Ahmad Reza's avatar
Ahmad Reza committed
115
        self.world = world
Ahmad Reza's avatar
Ahmad Reza committed
116
117
        self.init_tile_vertex_list()
        self.init_particle_vertex_list()
118
        self.init_marker_vertex_list()
Ahmad Reza's avatar
Ahmad Reza committed
119
        self.view = View()
Ahmad Reza's avatar
Ahmad Reza committed
120
121
        self.view.setDimensions(window_size_x, window_size_y)
        self.elapsed_frame_time = 0
Ahmad Reza's avatar
Ahmad Reza committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
        self.particleTexture = pyglet.image.load('lib/images/particle.png').get_mipmapped_texture()
        self.gridTexture = pyglet.image.load('lib/images/grid.png').get_mipmapped_texture()

        glDisable(GL_DEPTH_TEST)
        glDisable(GL_CULL_FACE)

        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        glEnable(self.gridTexture.target)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        if rotate_thirty_degree:
            glRotatef(30, 0, 0, 1)

        glMatrixMode(GL_PROJECTION)

        self.simulation_running = False
        self.video_mode = False
Ahmad Reza's avatar
Ahmad Reza committed
143
144
        self.draw()

Ahmad Reza's avatar
Ahmad Reza committed
145
146
147
148
149
150
151
152
153
154
155
156
157

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        if buttons & mouse.LEFT:
            self.view.drag(dx, dy)

    def exit_callback(self):
        self.close()
    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        self.view.scroll(x, y, scroll_x, scroll_y)

    def on_mouse_press(self, x, y, button, modifiers):
        if modifiers & key.MOD_CTRL:
            # get correct coordinates
158
159
            sim_coords = window_to_sim(x, y, self.view)
            coords_coords = sim_to_coords(sim_coords[0], sim_coords[1])
Ahmad Reza's avatar
Ahmad Reza committed
160
161
162
163
164
            rounded_coords=0
            if coords_coords[1]%2!=0:
                rounded_coords = round(coords_coords[0],0) + 0.5
            else:
                rounded_coords =round(coords_coords[0], 0)
Ahmad Reza's avatar
Ahmad Reza committed
165
            if (rounded_coords,coords_coords[1]) not in self.world.tile_map_coords:
Ahmad Reza's avatar
Ahmad Reza committed
166
                # add tile and vertices
Ahmad Reza's avatar
Ahmad Reza committed
167
168
169
170
171
172
                if self.world.add_tile_vis(rounded_coords, coords_coords[1]):
                    self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
                    #self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
                    self.tile_vertex_list.indices[4 * (len(self.world.tiles) - 1) : 4 * (len(self.world.tiles) - 1) + 4] = range(4 * (len(self.world.tiles) - 1), 4 * (len(self.world.tiles) - 1) + 4)
                   # self.tile_vertex_list.indices = list(range(0, 8 * len(self.world.tiles)))
                   # self.update_tile(len(self.world.tiles) - 1, tile)
Ahmad Reza's avatar
Ahmad Reza committed
173
174
175
                    self.update_tiles(True)
            else:
                # delete tile
Ahmad Reza's avatar
Ahmad Reza committed
176
177
                self.world.remove_tile_on((rounded_coords,coords_coords[1]))
                self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
Ahmad Reza's avatar
Ahmad Reza committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
                self.update_tiles(True)

    def on_resize(self, width, height):
        glViewport(0, 0, width, height)
        self.view.setDimensions(width, height)
        return pyglet.event.EVENT_HANDLED

    def on_close(self):
        self.window_active = False
        return pyglet.event.EVENT_HANDLED

    def on_key_press(self, symbol, modifiers):
        if symbol == key.Q and modifiers & key.MOD_COMMAND:  # cmd+q: quit application
            self.window_active = False
        elif symbol == key.SPACE:  # space: pause / unpause simulation
            self.pause()
        elif symbol == key.S and modifiers & key.MOD_COMMAND:  # cmd+s: save screenshot
            ScreenshotManager.takeScreenshot()
        elif symbol == key.V and modifiers & key.MOD_COMMAND:  # cmd+v: toggle video mode
            if not self.video_mode:
                self.video_mode = True
                self.simulation_running = True
                self.elapsed_frame_time = 0  # make videos completely reproducible
            else:
                self.video_mode = False
                self.simulation_running = False
        return pyglet.event.EVENT_HANDLED

    def draw(self):
        self.update_tiles()
        self.update_particles()
209
        self.update_markers()
Ahmad Reza's avatar
Ahmad Reza committed
210
211
212
213
214
215
216
217
218
219
220
221
        glLoadIdentity()
        glOrtho(self.view.left, self.view.right, self.view.bottom, self.view.top, 1, -1)


        if show_grid:
            self.drawGrid()
        else:
            glClearColor(1, 1, 1, 1)
            glClear(GL_COLOR_BUFFER_BIT)

        glBindTexture(self.particleTexture.target, self.particleTexture.id)

Ahmad Reza's avatar
Ahmad Reza committed
222
        if len(self.world.tiles) != 0:
Ahmad Reza's avatar
Ahmad Reza committed
223
224
            self.tile_vertex_list.draw(GL_QUADS)
        self.particle_vertex_list.draw(GL_QUADS)
225
        self.marker_vertex_list.draw(GL_QUADS)
Ahmad Reza's avatar
Ahmad Reza committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259

        self.flip()

        if self.video_mode:
            ScreenshotManager.takeScreenshot()

    def drawGrid(self):
        texLeft = math.fmod(self.view.left, 1)
        texRight = texLeft + self.view.right - self.view.left

        texHeight = 2 * math.sqrt(3/4)
        texBottom = math.fmod(self.view.bottom, texHeight)
        texTop = texBottom + self.view.top - self.view.bottom
        texBottom = texBottom / texHeight
        texTop = texTop / texHeight

        glColor4f(1, 1, 1, 1)
        glBindTexture(self.gridTexture.target, self.gridTexture.id)

        glBegin(GL_QUADS)
        glTexCoord2f(texLeft, texBottom)
        glVertex2f(self.view.left, self.view.bottom)
        glTexCoord2f(texRight, texBottom)
        glVertex2f(self.view.right, self.view.bottom)
        glTexCoord2f(texRight, texTop)
        glVertex2f(self.view.right, self.view.top)
        glTexCoord2f(texLeft, texTop)
        glVertex2f(self.view.left, self.view.top)
        glEnd()

    def pause(self):
        self.simulation_running = not self.simulation_running

    def init_tile_vertex_list(self):
Ahmad Reza's avatar
Ahmad Reza committed
260
261
262
        self.tile_vertex_list = pyglet.graphics.vertex_list_indexed(4 * len(self.world.tiles),
                                                                    list(range(0, 4 * len(self.world.tiles))),
                                                                    #list(range(0,8 * len(self.world.tiles))),
Ahmad Reza's avatar
Ahmad Reza committed
263
264
265
266
267
268
269
                                                                    'v2f', 't2f', 'c4f')
        self.update_tiles(True)

    def update_tiles(self, update_all=False):
        foreground = []
        background = []

Ahmad Reza's avatar
Ahmad Reza committed
270
271
272
        if (len(self.world.tiles) != 0):
            if self.world.get_tile_deleted():
                self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
Ahmad Reza's avatar
Ahmad Reza committed
273
                update_all=True
Ahmad Reza's avatar
Ahmad Reza committed
274
275
                self.world.set_tile_deleted()
            for i, tile in enumerate(self.world.tiles):
Ahmad Reza's avatar
Ahmad Reza committed
276
                if tile.created:
Ahmad Reza's avatar
Ahmad Reza committed
277
                    self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
Ahmad Reza's avatar
Ahmad Reza committed
278
                    self.tile_vertex_list.indices[
Ahmad Reza's avatar
Ahmad Reza committed
279
280
                    4 * (len(self.world.tiles) - 1): 4 * (len(self.world.tiles) - 1) + 4] = range(
                        4 * (len(self.world.tiles) - 1), 4 * (len(self.world.tiles) - 1) + 4)
Ahmad Reza's avatar
Ahmad Reza committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
                    tile.created =  False
                if update_all or tile.modified:
                    self.update_tile(i, tile)
                    tile.modified = False

                indices = list(range(4 * i, 4 * i + 4))
                if tile.get_tile_status():
                    foreground += indices
                else:
                    background += indices

            self.tile_vertex_list.indices = background + foreground
        else:
            pass#self.tile_vertex_list.indices = list(range(0,4))

    def update_tile(self, i, tile):
        weird = 256 / 220
298
        pos = coords_to_sim(tile.coords)
Ahmad Reza's avatar
Ahmad Reza committed
299
300
301
302
303
304
305
306
307
308
309
        x = pos[0]
        y = pos[1]

        self.tile_vertex_list.vertices[8 * i: 8 * i + 8] = [x - weird, y - weird, x + weird, y - weird, x + weird,
                                                            y + weird, x - weird, y + weird]

        if tile.get_tile_status():
            texLeft = 0 / 8
            texRight = 1 / 8
            texBottom = 5 / 8
            texTop = 6 / 8
310
            #tile_alpha = 1
Ahmad Reza's avatar
Ahmad Reza committed
311
312
        else:
            texLeft = 7 / 8
313
            texRight = 1 # 8/8
Ahmad Reza's avatar
Ahmad Reza committed
314
315
            texBottom = 4 / 8
            texTop = 5 / 8
316
            #tile_alpha = 0.5
Ahmad Reza's avatar
Ahmad Reza committed
317
318
319
320
321
322
323
324

        self.tile_vertex_list.tex_coords[8 * i: 8 * i + 8] = [texLeft, texBottom, texRight, texBottom, texRight, texTop,
                                                              texLeft, texTop]

        self.tile_vertex_list.colors[16 * i: 16 * i + 16] = (tile.color + [tile.get_alpha()]) * 4

    def init_particle_vertex_list(self):
        self.particle_vertex_list = self.particle_vertex_list = pyglet.graphics.vertex_list \
Ahmad Reza's avatar
Ahmad Reza committed
325
            (4 * len(self.world.particles), 'v2f', 't2f', 'c4f')
Ahmad Reza's avatar
Ahmad Reza committed
326
327
328
        self.update_particles(True)

    def update_particles(self, update_all = False):
Ahmad Reza's avatar
Ahmad Reza committed
329
330
331
332
        if (len(self.world.particles) != 0):
            if self.world.get_particle_deleted():
                self.particle_vertex_list.resize(4 * len(self.world.particles))
                self.world.set_particle_deleted()
Ahmad Reza's avatar
Ahmad Reza committed
333
                update_all = True
Ahmad Reza's avatar
Ahmad Reza committed
334
            for i, particle in enumerate(self.world.particles):
Ahmad Reza's avatar
Ahmad Reza committed
335
                if particle.created:
Ahmad Reza's avatar
Ahmad Reza committed
336
337
                    self.particle_vertex_list.resize(4 * len(self.world.particles))
                    # self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
Ahmad Reza's avatar
Ahmad Reza committed
338
339
340
341
342
343
344
345
346
                    particle.created=False
                if update_all or particle.modified:
                    self.update_particle(i, particle)
                    particle.modified = False
        else:
            pass

    def update_particle(self, i, particle):
        weird = 256 / 220
347
        pos = coords_to_sim(particle.coords)
Ahmad Reza's avatar
Ahmad Reza committed
348
349
350
351
352
353
354
355
356
357
358
359
        x = pos[0]
        y = pos[1]

        self.particle_vertex_list.vertices[8 * i: 8 * i + 8] = [x - weird, y - weird, x + weird, y - weird, x + weird,
                                                                y + weird, x - weird, y + weird]
        """UV works in such away that there are 8 Columns and 8 rows and if you want to take one you have to add the direction
        and reduce one from the inverse direction"""
        if particle.get_carried_status():
            texLeft = 0 / 8
            texRight = 1 / 8
            texBottom = 7 / 8
            texTop = 6 / 8
360
            #particle.set_alpha(0.5)
Ahmad Reza's avatar
Ahmad Reza committed
361
362
363
364
365
        else:
            texLeft = 0 / 8
            texRight = 1 / 8
            texBottom = 0 / 8
            texTop = 1 / 8
366
            #particle.set_alpha(1)
Ahmad Reza's avatar
Ahmad Reza committed
367
368
369
370
371
        self.particle_vertex_list.tex_coords[8 * i: 8 * i + 8] = [texLeft, texBottom, texRight, texBottom,
                                                                  texRight, texTop, texLeft, texTop]

        self.particle_vertex_list.colors[16 * i: 16 * i + 16] = (particle.color + [particle.get_alpha()]) * 4

372
373
    def init_marker_vertex_list(self):
        self.marker_vertex_list = self.marker_vertex_list = pyglet.graphics.vertex_list \
Ahmad Reza's avatar
Ahmad Reza committed
374
            (4 * len(self.world.markers), 'v2f', 't2f', 'c4f')
375
        self.update_markers(True)
Ahmad Reza's avatar
Ahmad Reza committed
376

377
    def update_markers(self, update_all=True):
Ahmad Reza's avatar
Ahmad Reza committed
378
379
380
381
        if (len(self.world.markers) != 0):
            if self.world.get_marker_deleted():
                self.marker_vertex_list.resize(4 * len(self.world.markers))
                self.world.set_marker_deleted()
Ahmad Reza's avatar
Ahmad Reza committed
382
                update_all = True
Ahmad Reza's avatar
Ahmad Reza committed
383
            for i, marker in enumerate(self.world.markers):
384
                if marker.created:
Ahmad Reza's avatar
Ahmad Reza committed
385
386
                    self.marker_vertex_list.resize(4 * len(self.world.markers))
                    # self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
387
388
389
390
                    marker.created = False
                if update_all or marker.modified:
                    self.update_marker(i, marker)
                    marker.modified = False
Ahmad Reza's avatar
Ahmad Reza committed
391
392
393
        else:
            pass

394
    def update_marker(self, i, marker):
Ahmad Reza's avatar
Ahmad Reza committed
395
        weird = 256 / 220
396
        pos = coords_to_sim(marker.coords)
Ahmad Reza's avatar
Ahmad Reza committed
397
398
399
        x = pos[0]
        y = pos[1]

400
        self.marker_vertex_list.vertices[8 * i: 8 * i + 8] = [x - weird, y - weird, x + weird, y - weird, x + weird,
Ahmad Reza's avatar
Ahmad Reza committed
401
402
                                                                y + weird, x - weird, y + weird]
        texLeft = 7/8
403
        texRight = 1 #8/8
Ahmad Reza's avatar
Ahmad Reza committed
404
405
406
        texBottom = 0/8
        texTop = 1/8

407
        self.marker_vertex_list.tex_coords[8 * i: 8 * i + 8] = [texLeft, texBottom, texRight, texBottom,
Ahmad Reza's avatar
Ahmad Reza committed
408
409
                                                                  texRight, texTop, texLeft, texTop]

410
        self.marker_vertex_list.colors[16 * i: 16 * i + 16] = (marker.color + [marker.get_alpha()]) * 4
Ahmad Reza's avatar
Ahmad Reza committed
411

412
    def draw_world(self, round_start_timestamp):
Ahmad Reza's avatar
Ahmad Reza committed
413
        while not self.simulation_running:
Ahmad Reza's avatar
Ahmad Reza committed
414
            self.dispatch_events()
415
            self.draw()
Ahmad Reza's avatar
Ahmad Reza committed
416
417
            if self.simulation_running or self.window_active is False:
                return
418

Ahmad Reza's avatar
Ahmad Reza committed
419
        self.draw()
420
421
422
423
424
425
426
427
428
429
430

        # waiting until enough time passed to do the next simulation round.
        time_elapsed = time.perf_counter() - round_start_timestamp
        while time_elapsed < 1 / rounds_per_second:
            # waiting for 1/100 of the round_time
            waiting_time = (1 / rounds_per_second) / 100
            time.sleep(waiting_time)
            self.dispatch_events()
            self.draw()
            time_elapsed = time.perf_counter() - round_start_timestamp

Ahmad Reza's avatar
Ahmad Reza committed
431
        return