Introduce Shard object
Only works locally at the moment and not optimized.
This commit is contained in:
parent
809a577f6d
commit
74ac31d239
31
axuy/misc.py
31
axuy/misc.py
|
@ -16,7 +16,8 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Axuy. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from itertools import chain, combinations_with_replacement, permutations
|
||||
from itertools import (chain, combinations_with_replacement,
|
||||
permutations, product)
|
||||
from random import choices, shuffle
|
||||
|
||||
import numpy
|
||||
|
@ -73,8 +74,34 @@ def neighbors(x, y, z):
|
|||
for i, j, k in NEIGHBORS: yield x + i*12, y + j*12, z + k*9
|
||||
|
||||
|
||||
def sign(x):
|
||||
def normalized(*vector):
|
||||
"""Return normalized vector as a NumPy array of float32."""
|
||||
v = numpy.float32(vector)
|
||||
if not any(v): return v
|
||||
return v / sum(v**2)
|
||||
|
||||
|
||||
def sign(x) -> int:
|
||||
"""Return the sign of number x."""
|
||||
if x > 0: return 1
|
||||
if x: return -1
|
||||
return 0
|
||||
|
||||
|
||||
def twelve(x) -> int:
|
||||
"""Shorthand for int(x % 12)."""
|
||||
return int(x % 12)
|
||||
|
||||
|
||||
def nine(x) -> int:
|
||||
"""Shorthand for int(x % 9)."""
|
||||
return int(x % 9)
|
||||
|
||||
|
||||
def placeable(space, x, y, z, r):
|
||||
"""Return whether a sphere of radius r
|
||||
can be placed at (x, y, z) in given space."""
|
||||
return not any(space[i][j][k] for i, j, k in product(
|
||||
{twelve(x-r), twelve(x), twelve(x+r)},
|
||||
{twelve(y-r), twelve(y), twelve(y+r)},
|
||||
{nine(z-r), nine(z), nine(z+r)}))
|
||||
|
|
27
axuy/peer.py
27
axuy/peer.py
|
@ -24,8 +24,7 @@ from socket import socket, SOCK_DGRAM, SOL_SOCKET, SO_REUSEADDR
|
|||
from threading import Thread
|
||||
|
||||
from .misc import mapgen, mapidgen
|
||||
from .pico import Picobot
|
||||
from .view import View
|
||||
from .view import Pico, View
|
||||
|
||||
|
||||
class Peer:
|
||||
|
@ -47,8 +46,8 @@ class Peer:
|
|||
self.peers.extend(data['peers'])
|
||||
|
||||
self.space = mapgen(mapid)
|
||||
self.pico = Picobot(self.space, (0, 0, 0))
|
||||
self.view = View(self.pico, args.width, args.height, self.space)
|
||||
self.pico = Pico(self.space, (0, 0, 0))
|
||||
self.view = View(self.pico, self.space, args.width, args.height)
|
||||
|
||||
address = args.host, args.port
|
||||
data_server = Thread(target=self.serve,
|
||||
|
@ -69,15 +68,14 @@ class Peer:
|
|||
|
||||
def serve(self, address, mapid):
|
||||
"""Initiate peers."""
|
||||
self.server = socket() # TCP server
|
||||
self.server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||
self.server.bind(address)
|
||||
self.server.listen(7)
|
||||
while self.view.is_running:
|
||||
conn, addr = self.server.accept()
|
||||
conn.send(dumps({'mapid': mapid, 'peers': self.peers}))
|
||||
conn.close()
|
||||
self.server.close()
|
||||
with socket() as server: # TCP server
|
||||
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||
server.bind(address)
|
||||
server.listen(7)
|
||||
while self.view.is_running:
|
||||
conn, addr = server.accept()
|
||||
conn.send(dumps({'mapid': mapid, 'peers': self.peers}))
|
||||
conn.close()
|
||||
|
||||
def push(self):
|
||||
"""Send own state to peers."""
|
||||
|
@ -93,13 +91,12 @@ class Peer:
|
|||
try:
|
||||
self.view.picos[addr].update(pos, rot)
|
||||
except KeyError:
|
||||
self.view.picos[addr] = Picobot(self.space, pos, rot)
|
||||
self.view.picos[addr] = Pico(self.space, pos, rot)
|
||||
self.peers.append(addr)
|
||||
|
||||
def __enter__(self): return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.server.close()
|
||||
self.sock.close()
|
||||
self.view.close()
|
||||
|
||||
|
|
146
axuy/pico.py
146
axuy/pico.py
|
@ -25,23 +25,28 @@ import glfw
|
|||
import numpy as np
|
||||
from pyrr import matrix33
|
||||
|
||||
BASE = np.float32([[1, 0, 0], [0, 1, 0], [0, 0, -1]])
|
||||
RP = 1 / 4 # radius of a Picobot
|
||||
from .misc import normalized, placeable
|
||||
|
||||
SPEED = 2
|
||||
MOUSE_SPEED = 1/8
|
||||
INVX = np.float32([[-1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
||||
INVY = np.float32([[1, 0, 0], [0, -1, 0], [0, 0, -1]])
|
||||
INVZ = np.float32([[1, 0, 0], [0, 1, 0], [0, 0, -1]])
|
||||
|
||||
PICO_SPEED = 2 # in unit/s
|
||||
SHARD_SPEED = PICO_SPEED * 243**0.25 # in unit/s
|
||||
SHARD_LIFE = 11 / SHARD_SPEED # in seconds
|
||||
|
||||
|
||||
class Picobot:
|
||||
"""Game character.
|
||||
"""Game character, which is represented as a regular tetrahedron
|
||||
whose circumscribed sphere's radius is 1/4 unit.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
space : np.ndarray of shape (12, 12, 9) of bools
|
||||
3D array of occupied space.
|
||||
pos : iterable of length 3 of floats
|
||||
position : iterable of length 3 of floats, optional
|
||||
Position.
|
||||
rotation : np.ndarray of shape (3, 3) of np.float32
|
||||
rotation : np.ndarray of shape (3, 3) of np.float32, optional
|
||||
Rotational matrix.
|
||||
|
||||
Attributes
|
||||
|
@ -50,12 +55,11 @@ class Picobot:
|
|||
3D array of occupied space.
|
||||
x, y, z : floats
|
||||
Position.
|
||||
rotation : np.ndarray of shape (3, 3) of np.float32
|
||||
rot : np.ndarray of shape (3, 3) of np.float32
|
||||
Rotational matrix.
|
||||
fps : float
|
||||
Currently rendered frames per second.
|
||||
"""
|
||||
|
||||
def __init__(self, space, position=None, rotation=None):
|
||||
self.space = space
|
||||
if position is None:
|
||||
|
@ -67,43 +71,13 @@ class Picobot:
|
|||
self.x, self.y, self.z = position
|
||||
|
||||
if rotation is None:
|
||||
self.rotation = BASE
|
||||
self.rot = INVZ
|
||||
self.rotate(random()*pi*2, random()*pi*2)
|
||||
else:
|
||||
self.rotation = rotation
|
||||
self.rot = rotation
|
||||
|
||||
self.fps = 60.0
|
||||
|
||||
def update(self, position, rotation):
|
||||
"""Update state."""
|
||||
self.pos = position
|
||||
self.rotation = rotation
|
||||
|
||||
def empty(self, x, y, z) -> bool:
|
||||
"""Return whether a Picobot can be placed at (x, y, z)."""
|
||||
if self.space[int((x-RP) % 12)][int(y % 12)][int(z % 9)]: return False
|
||||
if self.space[int((x+RP) % 12)][int(y % 12)][int(z % 9)]: return False
|
||||
if self.space[int(x % 12)][int((y-RP) % 12)][int(z % 9)]: return False
|
||||
if self.space[int(x % 12)][int((y+RP) % 12)][int(z % 9)]: return False
|
||||
if self.space[int(x % 12)][int(y % 12)][int((z-RP) % 9)]: return False
|
||||
if self.space[int(x % 12)][int(y % 12)][int((z+RP) % 9)]: return False
|
||||
return True
|
||||
|
||||
def rotate(self, yaw, pitch):
|
||||
"""Rotate yaw radians around y-axis
|
||||
and pitch radians around x-axis.
|
||||
"""
|
||||
self.rotation = (matrix33.create_from_x_rotation(pitch)
|
||||
@ matrix33.create_from_y_rotation(yaw) @ self.rotation)
|
||||
|
||||
def move(self, right=0, upward=0, forward=0):
|
||||
"""Try to move in the given direction."""
|
||||
dr = [right, upward, forward] @ self.rotation / self.fps * SPEED
|
||||
x, y, z = [self.x, self.y, self.z] + dr
|
||||
if self.empty(x, self.y, self.z): self.x = x % 12
|
||||
if self.empty(self.x, y, self.z): self.y = y % 12
|
||||
if self.empty(self.x, self.y, z): self.z = z % 9
|
||||
|
||||
@property
|
||||
def pos(self):
|
||||
"""Position in a NumPy array."""
|
||||
|
@ -116,12 +90,90 @@ class Picobot:
|
|||
@property
|
||||
def state(self):
|
||||
"""Position and rotation."""
|
||||
return self.pos, self.rotation
|
||||
return self.pos, self.rot
|
||||
|
||||
def look(self, window, xpos, ypos):
|
||||
"""Look according to cursor position.
|
||||
def sync(self, position, rotation) -> None:
|
||||
"""Synchronize state received from other peers."""
|
||||
self.pos = position
|
||||
self.rot = rotation
|
||||
|
||||
Present as a callback for GLFW CursorPos event.
|
||||
def placeable(self, x, y, z) -> bool:
|
||||
"""Return whether it can be placed at (x, y, z)."""
|
||||
return placeable(self.space, x, y, z, 1/4)
|
||||
|
||||
def rotate(self, yaw, pitch):
|
||||
"""Rotate yaw radians around y-axis
|
||||
and pitch radians around x-axis.
|
||||
"""
|
||||
center = np.float32(glfw.get_window_size(window)) / 2
|
||||
self.rotate(*((center - [xpos, ypos]) / self.fps * MOUSE_SPEED))
|
||||
self.rot = (matrix33.create_from_x_rotation(pitch)
|
||||
@ matrix33.create_from_y_rotation(yaw) @ self.rot)
|
||||
|
||||
def move(self, right=0, upward=0, forward=0):
|
||||
"""Try to move in the given direction."""
|
||||
direction = normalized(right, upward, forward) @ self.rot
|
||||
x, y, z = self.pos + direction/self.fps*PICO_SPEED
|
||||
if self.placeable(x, self.y, self.z): self.x = x % 12
|
||||
if self.placeable(self.x, y, self.z): self.y = y % 12
|
||||
if self.placeable(self.x, self.y, z): self.z = z % 9
|
||||
|
||||
|
||||
class Shard:
|
||||
"""Fragment broken or shot out of a Picobot, which is a regular
|
||||
octahedron whose circumscribed sphere's radius is 1/12 unit.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
space : np.ndarray of shape (12, 12, 9) of bools
|
||||
3D array of occupied space.
|
||||
position : iterable of length 3 of floats
|
||||
Position.
|
||||
rotation : np.ndarray of shape (3, 3) of np.float32
|
||||
Rotational matrix.
|
||||
fps : float, optional
|
||||
Currently rendered frames per second.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
space : np.ndarray of shape (12, 12, 9) of bools
|
||||
3D array of occupied space.
|
||||
x, y, z : floats
|
||||
Position.
|
||||
rot : np.ndarray of shape (3, 3) of np.float32
|
||||
Rotational matrix.
|
||||
power : float
|
||||
Relative destructive power to the original.
|
||||
fps : float
|
||||
Currently rendered frames per second.
|
||||
"""
|
||||
def __init__(self, space, position, rotation, fps=60.0):
|
||||
self.space = space
|
||||
self.x, self.y, self.z = position
|
||||
self.rot = rotation
|
||||
self.fps = fps
|
||||
|
||||
@property
|
||||
def pos(self):
|
||||
"""Position in a NumPy array."""
|
||||
return np.float32([self.x, self.y, self.z])
|
||||
|
||||
@pos.setter
|
||||
def pos(self, position):
|
||||
self.x, self.y, self.z = position
|
||||
|
||||
@property
|
||||
def forward(self):
|
||||
"""Direction in a NumPy array."""
|
||||
return self.rot[-1]
|
||||
|
||||
def placeable(self, x, y, z) -> bool:
|
||||
"""Return whether it can be placed at (x, y, z)."""
|
||||
return placeable(self.space, x, y, z, r=1/12)
|
||||
|
||||
def update(self):
|
||||
"""Update states."""
|
||||
x, y, z = self.pos + self.forward/self.fps*SHARD_SPEED
|
||||
if not self.placeable(x, self.y, self.z): self.rot = self.rot @ INVX
|
||||
if not self.placeable(self.x, y, self.z): self.rot = self.rot @ INVY
|
||||
if not self.placeable(self.x, self.y, z): self.rot = self.rot @ INVZ
|
||||
self.pos += self.forward / self.fps * SHARD_SPEED
|
||||
return self
|
||||
|
|
135
axuy/view.py
135
axuy/view.py
|
@ -20,17 +20,20 @@ __doc__ = 'Axuy module for map class'
|
|||
|
||||
from itertools import product
|
||||
from math import sqrt
|
||||
from multiprocessing import Pool
|
||||
|
||||
import glfw
|
||||
import moderngl
|
||||
import numpy as np
|
||||
from pyrr import Matrix44
|
||||
|
||||
from .pico import INVZ, Picobot, Shard
|
||||
from .misc import abspath, color, neighbors, sign
|
||||
|
||||
FOV_MIN = 30
|
||||
FOV_MAX = 120
|
||||
FOV_INIT = (FOV_MIN+FOV_MAX) / 2
|
||||
MOUSE_SPEED = 1/8
|
||||
|
||||
OXY = np.float32([[0, 0, 0], [1, 0, 0], [1, 1, 0],
|
||||
[1, 1, 0], [0, 1, 0], [0, 0, 0]])
|
||||
|
@ -54,30 +57,59 @@ with open(abspath('shaders/pico.vert')) as f: PICO_VERTEX = f.read()
|
|||
with open(abspath('shaders/pico.frag')) as f: PICO_FRAGMENT = f.read()
|
||||
|
||||
|
||||
class Pico(Picobot):
|
||||
def look(self, window, xpos, ypos):
|
||||
"""Look according to cursor position.
|
||||
|
||||
Present as a callback for GLFW CursorPos event.
|
||||
"""
|
||||
center = np.float32(glfw.get_window_size(window)) / 2
|
||||
self.rotate(*((center - [xpos, ypos]) / self.fps * MOUSE_SPEED))
|
||||
|
||||
|
||||
class View:
|
||||
"""World map and camera placement.
|
||||
(Documentation below is not completed.)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mapid : iterable of length 48 of ints
|
||||
order of nodes to sort map.npy.
|
||||
context : moderngl.Context
|
||||
OpenGL context from which ModernGL objects are created.
|
||||
camera : Pico
|
||||
Protagonist whose view is the camera.
|
||||
space : np.ndarray of shape (12, 12, 9) of bools
|
||||
3D array of occupied space.
|
||||
width, height : ints
|
||||
Window size.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
space : np.ndarray of shape (12, 12, 9) of bools
|
||||
3D array of occupied space.
|
||||
camera : Pico
|
||||
Protagonist whose view is the camera.
|
||||
picos : dict of (str, Pico)
|
||||
Enemies characters.
|
||||
shards : list of Shards
|
||||
Picobot fragments, which are capable of causing damage.
|
||||
window : GLFW window
|
||||
fov : int
|
||||
horizontal field of view in degrees
|
||||
context : moderngl.Context
|
||||
OpenGL context from which ModernGL objects are created.
|
||||
maprog : moderngl.Program
|
||||
Processed executable code in GLSL.
|
||||
Processed executable code in GLSL for map rendering.
|
||||
mapva : moderngl.VertexArray
|
||||
Vertex data of the map.
|
||||
camera : Picobot
|
||||
Protagonist whose view is the camera.
|
||||
prog : moderngl.Program
|
||||
Processed executable code in GLSL
|
||||
for rendering picobots and their shards.
|
||||
pva : moderngl.VertexArray
|
||||
Vertex data of picobots.
|
||||
sva : moderngl.VertexArray
|
||||
Vertex data of shards.
|
||||
last_time : float
|
||||
timestamp in seconds of the previous frame
|
||||
"""
|
||||
|
||||
def __init__(self, pico, width, height, space):
|
||||
def __init__(self, camera, space, width, height):
|
||||
# Create GLFW window
|
||||
if not glfw.init(): raise RuntimeError('Failed to initialize GLFW!')
|
||||
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
|
||||
|
@ -87,11 +119,13 @@ class View:
|
|||
self.window = glfw.create_window(width, height, 'Axuy', None, None)
|
||||
if not self.window:
|
||||
glfw.terminate()
|
||||
raise RuntimeError('Failed to create glfw window!')
|
||||
raise RuntimeError('Failed to create GLFW window!')
|
||||
|
||||
self.camera = pico
|
||||
self.picos = {'self': pico}
|
||||
self.last_time = glfw.get_time() # to keep track of FPS
|
||||
self.camera = camera
|
||||
self.picos = {'self': camera}
|
||||
self.shards = []
|
||||
self.last_time = glfw.get_time()
|
||||
self.pool = Pool()
|
||||
|
||||
# Window's rendering and event-handling configuration
|
||||
glfw.make_context_current(self.window)
|
||||
|
@ -101,6 +135,7 @@ class View:
|
|||
glfw.set_cursor_pos_callback(self.window, self.camera.look)
|
||||
self.fov = FOV_INIT
|
||||
glfw.set_scroll_callback(self.window, self.zoom)
|
||||
glfw.set_mouse_button_callback(self.window, self.shoot)
|
||||
|
||||
# Create OpenGL context
|
||||
self.context = context = moderngl.create_context()
|
||||
|
@ -128,8 +163,9 @@ class View:
|
|||
pvb = [(context.buffer(TETRAVERTICES.tobytes()), '3f', 'in_vert')]
|
||||
pib = context.buffer(TETRAINDECIES.tobytes())
|
||||
self.pva = context.vertex_array(self.prog, pvb, pib)
|
||||
|
||||
self.should_close = None
|
||||
svb = [(context.buffer(OCTOVERTICES.tobytes()), '3f', 'in_vert')]
|
||||
sib = context.buffer(OCTOINDECIES.tobytes())
|
||||
self.sva = context.vertex_array(self.prog, svb, sib)
|
||||
|
||||
def zoom(self, window, xoffset, yoffset):
|
||||
"""Adjust FOV according to vertical scroll."""
|
||||
|
@ -137,6 +173,16 @@ class View:
|
|||
if self.fov < FOV_MIN: self.fov = FOV_MIN
|
||||
if self.fov > FOV_MAX: self.fov = FOV_MAX
|
||||
|
||||
def shoot(self, window, button, action, mods):
|
||||
"""Shoot on click.
|
||||
|
||||
Present as a callback for GLFW MouseButton event.
|
||||
"""
|
||||
protagonist = self.camera
|
||||
if button == glfw.MOUSE_BUTTON_LEFT and action == glfw.PRESS:
|
||||
self.shards.append(Shard(self.space, protagonist.pos,
|
||||
protagonist.rot, protagonist.fps))
|
||||
|
||||
@property
|
||||
def pos(self):
|
||||
"""Camera position in a NumPy array."""
|
||||
|
@ -145,32 +191,47 @@ class View:
|
|||
@property
|
||||
def right(self):
|
||||
"""Camera right direction."""
|
||||
return self.camera.rotation[0]
|
||||
return self.camera.rot[0]
|
||||
|
||||
@property
|
||||
def upward(self):
|
||||
"""Camera upward direction."""
|
||||
return self.camera.rotation[1]
|
||||
return self.camera.rot[1]
|
||||
|
||||
@property
|
||||
def forward(self):
|
||||
"""Camera forward direction."""
|
||||
return self.camera.rotation[2]
|
||||
return self.camera.rot[2]
|
||||
|
||||
@property
|
||||
def is_running(self):
|
||||
def is_running(self) -> bool:
|
||||
"""GLFW window status."""
|
||||
return not glfw.window_should_close(self.window)
|
||||
|
||||
def is_pressed(self, *keys):
|
||||
@property
|
||||
def visibility(self) -> np.float32:
|
||||
"""Camera visibility."""
|
||||
return np.float32(sqrt(1800 / self.fov))
|
||||
|
||||
def update_fps(self, fps):
|
||||
"""Update camera's and shards' FPS
|
||||
for their movement calculations.
|
||||
"""
|
||||
self.camera.fps = fps
|
||||
for shard in self.shards: shard.fps = fps
|
||||
print(len(self.shards), fps)
|
||||
|
||||
def is_pressed(self, *keys) -> bool:
|
||||
"""Return whether given keys are pressed."""
|
||||
return any(glfw.get_key(self.window, k) == glfw.PRESS for k in keys)
|
||||
|
||||
def render(self, obj, va):
|
||||
"""Render the obj and its images in bounded 3D space."""
|
||||
rotation = Matrix44.from_matrix33(obj.rotation)
|
||||
vsqr = self.visibility ** 2
|
||||
rotation = Matrix44.from_matrix33(obj.rot)
|
||||
i, j, k = map(sign, self.pos - obj.pos)
|
||||
for position in product(*zip(obj.pos, obj.pos + [i*12, j*12, k*9])):
|
||||
if sum((self.pos-position) ** 2) > vsqr: continue
|
||||
model = rotation @ Matrix44.from_translation(position)
|
||||
self.prog['model'].write(model.astype(np.float32).tobytes())
|
||||
self.prog['color'].write(color('Background').tobytes())
|
||||
|
@ -179,19 +240,20 @@ class View:
|
|||
va.render(moderngl.TRIANGLES)
|
||||
|
||||
def render_pico(self, pico):
|
||||
"""Render the pico and its images in bounded 3D space."""
|
||||
rotation = Matrix44.from_matrix33(pico.rotation)
|
||||
i, j, k = map(sign, self.pos - pico.pos)
|
||||
for position in product(*zip(pico.pos, pico.pos + [i*12, j*12, k*9])):
|
||||
model = rotation @ Matrix44.from_translation(position)
|
||||
self.prog['model'].write(model.astype(np.float32).tobytes())
|
||||
self.prog['color'].write(color('Background').tobytes())
|
||||
self.pva.render(moderngl.LINES)
|
||||
self.prog['color'].write(color('Plum').tobytes())
|
||||
self.pva.render(moderngl.TRIANGLES)
|
||||
"""Render pico and its images in bounded 3D space."""
|
||||
self.render(pico, self.pva)
|
||||
|
||||
def render_shard(self, shard):
|
||||
"""Render shard and its images in bounded 3D space."""
|
||||
self.render(shard, self.sva)
|
||||
|
||||
def update(self):
|
||||
"""Handle input, update GLSL programs and render the map."""
|
||||
# Update instantaneous FPS
|
||||
next_time = glfw.get_time()
|
||||
self.update_fps(1 / (next_time-self.last_time))
|
||||
self.last_time = next_time
|
||||
|
||||
# Character movements
|
||||
right, upward, forward = 0, 0, 0
|
||||
if self.is_pressed(glfw.KEY_UP): forward += 1
|
||||
|
@ -205,22 +267,26 @@ class View:
|
|||
self.context.viewport = 0, 0, width, height
|
||||
self.context.clear(*color('Background'))
|
||||
|
||||
visibility = sqrt(1800 / self.fov)
|
||||
visibility = self.visibility
|
||||
projection = Matrix44.perspective_projection(self.fov, width/height,
|
||||
3E-3, visibility)
|
||||
view = Matrix44.look_at(self.pos, self.pos + self.forward, self.upward)
|
||||
vp = (view @ projection).astype(np.float32).tobytes()
|
||||
|
||||
self.maprog['visibility'].write(np.float32(visibility).tobytes())
|
||||
self.maprog['visibility'].write(visibility.tobytes())
|
||||
self.maprog['camera'].write(self.pos.tobytes())
|
||||
self.maprog['mvp'].write(vp)
|
||||
self.mapva.render(moderngl.TRIANGLES)
|
||||
|
||||
self.prog['visibility'].write(np.float32(visibility).tobytes())
|
||||
self.prog['visibility'].write(visibility.tobytes())
|
||||
self.prog['camera'].write(self.pos.tobytes())
|
||||
self.prog['vp'].write(vp)
|
||||
for pico in self.picos.copy().values():
|
||||
if pico is not self.camera: self.render_pico(pico)
|
||||
self.shards = self.pool.map(Shard.update, self.shards)
|
||||
for shard in self.shards:
|
||||
#shard.update()
|
||||
self.render_shard(shard)
|
||||
glfw.swap_buffers(self.window)
|
||||
|
||||
# Resetting cursor position and event queues
|
||||
|
@ -230,3 +296,4 @@ class View:
|
|||
def close(self):
|
||||
"""Close window."""
|
||||
glfw.terminate()
|
||||
self.pool.terminate()
|
||||
|
|
Loading…
Reference in New Issue