2020-11-08 10:20:23 +01:00
|
|
|
from Lights.Lights import Light
|
|
|
|
from Objects.Objects import Object
|
|
|
|
from Objects.Renderable import Renderable
|
|
|
|
from Objects.Structure import Structure
|
|
|
|
from MatrixStuff.Transformations import translate
|
|
|
|
from OpenGL.GLU import *
|
|
|
|
from OpenGL.GL import *
|
|
|
|
import math
|
|
|
|
import numpy as np
|
2021-12-20 17:21:46 +01:00
|
|
|
import random
|
|
|
|
import sys
|
2020-11-08 10:20:23 +01:00
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
# Plate Types
|
|
|
|
SEA_PLATE = 0
|
|
|
|
CONTINENTAL_PLATE = 1
|
|
|
|
|
|
|
|
# Rock types
|
|
|
|
EMPTY = 0
|
|
|
|
SEA_PLATE_STONE = 1
|
|
|
|
MAGMATIC_STONE = 2
|
|
|
|
METAMORPH_STONE = 3
|
|
|
|
SEDIMENTAL_STONE = 4
|
|
|
|
SEDIMENT = 5
|
|
|
|
|
2020-11-08 10:20:23 +01:00
|
|
|
class WorldChunk(Structure):
|
|
|
|
def __init__(self, width: int, length: int, height: int, programs: dict):
|
|
|
|
assert width > 0, 'Width must be greater than 0'
|
|
|
|
assert length > 0, 'length must be greater than 0'
|
|
|
|
assert height > 0, 'height must be greater than 0'
|
|
|
|
super(WorldChunk, self).__init__()
|
|
|
|
self.visible = []
|
|
|
|
self.content = []
|
|
|
|
self.entities = []
|
|
|
|
self.lights = []
|
|
|
|
|
|
|
|
self.width = width
|
|
|
|
self.length = length
|
|
|
|
self.height = height
|
|
|
|
self.programs = programs
|
|
|
|
|
|
|
|
for x in range(width):
|
|
|
|
self.content.append([])
|
|
|
|
self.visible.append([])
|
|
|
|
for y in range(length):
|
|
|
|
self.content[x].append([])
|
|
|
|
self.visible[x].append([])
|
|
|
|
for z in range(height):
|
|
|
|
self.content[x][y].append(None)
|
|
|
|
self.visible[x][y].append(4)
|
|
|
|
|
|
|
|
def put_object(self, x: int, y: int, z: int, new_object: Object):
|
|
|
|
assert 0 <= x < self.width, 'Put out of bounds for x coordinate! Must be between 0 and %i' % self.width
|
|
|
|
assert 0 <= y < self.length, 'Put out of bounds for y coordinate! Must be between 0 and %i' % self.length
|
|
|
|
assert 0 <= z < self.height, 'Put out of bounds for z coordinate! Must be between 0 and %i' % self.height
|
|
|
|
no_visibility_changes = (self.content[x][y][z] is None) == (new_object is None)
|
|
|
|
|
|
|
|
self.content[x][y][z] = new_object
|
|
|
|
new_object.translate(translate(x, y, z))
|
|
|
|
|
|
|
|
change = -1 if new_object is not None else 1
|
|
|
|
visible_carry_over = []
|
|
|
|
if not no_visibility_changes:
|
|
|
|
if x + 1 >= self.width:
|
|
|
|
visible_carry_over.append((1, 0, 0, change))
|
|
|
|
else:
|
|
|
|
self.visible[x + 1][y][z] += change
|
|
|
|
if x - 1 < 0:
|
|
|
|
visible_carry_over.append((-1, 0, 0, change))
|
|
|
|
else:
|
|
|
|
self.visible[x - 1][y][z] += change
|
|
|
|
|
|
|
|
if y + 1 >= self.length:
|
|
|
|
visible_carry_over.append((0, 1, 0, change))
|
|
|
|
else:
|
|
|
|
self.visible[x][y + 1][z] += change
|
|
|
|
if y - 1 < 0:
|
|
|
|
visible_carry_over.append((0, -1, 0, change))
|
|
|
|
else:
|
|
|
|
self.visible[x][y - 1][z] += change
|
|
|
|
|
|
|
|
if z + 1 >= self.height:
|
|
|
|
visible_carry_over.append((0, 0, 1, change))
|
|
|
|
else:
|
|
|
|
self.visible[x][y][z + 1] += change
|
|
|
|
if z - 1 < 0:
|
|
|
|
visible_carry_over.append((0, 0, -1, change))
|
|
|
|
else:
|
|
|
|
self.visible[x][y][z - 1] += change
|
|
|
|
|
|
|
|
return visible_carry_over
|
|
|
|
|
|
|
|
def get_object(self, x: int, y: int, z: int):
|
|
|
|
assert 0 <= x < self.width, 'Put out of bounds for x coordinate! Must be between 0 and %i' % self.width
|
|
|
|
assert 0 <= y < self.length, 'Put out of bounds for y coordinate! Must be between 0 and %i' % self.length
|
|
|
|
assert 0 <= z < self.height, 'Put out of bounds for z coordinate! Must be between 0 and %i' % self.height
|
|
|
|
|
|
|
|
return self.content[x][y][z]
|
|
|
|
|
|
|
|
def apply_visible_carry_over(self, x: int, y: int, z: int, change: int):
|
|
|
|
assert 0 <= x < self.width, 'Apply visible out of bounds for x coordinate! Must be between 0 and %i' % self.width
|
|
|
|
assert 0 <= y < self.length, 'Apply visible out of bounds for y coordinate! Must be between 0 and %i' % self.length
|
|
|
|
assert 0 <= z < self.height, 'Apply visible out of bounds for z coordinate! Must be between 0 and %i' % self.height
|
|
|
|
|
|
|
|
self.visible[x][y][z] += change
|
|
|
|
|
|
|
|
def set_visibility(self, x: int, y: int, z: int, visibility: int):
|
|
|
|
assert 0 <= x < self.width, 'Apply visible out of bounds for x coordinate! Must be between 0 and %i' % self.width
|
|
|
|
assert 0 <= y < self.length, 'Apply visible out of bounds for y coordinate! Must be between 0 and %i' % self.length
|
|
|
|
assert 0 <= z < self.height, 'Apply visible out of bounds for z coordinate! Must be between 0 and %i' % self.height
|
|
|
|
|
|
|
|
self.visible[x][y][z] = visibility
|
|
|
|
|
|
|
|
def buildvertexArrays(self):
|
|
|
|
if self.dirty:
|
|
|
|
self.clearVertexArrays()
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY)
|
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
|
|
|
|
glEnableClientState(GL_NORMAL_ARRAY)
|
|
|
|
glEnableClientState(GL_COLOR_ARRAY)
|
|
|
|
self.vais = {}
|
|
|
|
|
|
|
|
objects = {}
|
|
|
|
counts = {}
|
|
|
|
for x in range(self.width):
|
|
|
|
for y in range(self.length):
|
|
|
|
for z in range(self.height):
|
|
|
|
if self.content[x][y][z] is not None: # and self.visible[x][y][z] > 0: TODO: check visibility...
|
|
|
|
if self.programs[type(self.content[x][y][z])] not in objects.keys():
|
|
|
|
objects[self.programs[type(self.content[x][y][z])]] = []
|
|
|
|
counts[self.programs[type(self.content[x][y][z])]] = 0
|
|
|
|
objects[self.programs[type(self.content[x][y][z])]].append(self.content[x][y][z])
|
|
|
|
counts[self.programs[type(self.content[x][y][z])]] += 1
|
|
|
|
|
|
|
|
for key, object_list in objects.items():
|
|
|
|
tvai = GLuint(0)
|
|
|
|
tpbi = GLuint(0)
|
|
|
|
tcbi = GLuint(0)
|
|
|
|
tsbi = GLuint(0)
|
|
|
|
|
|
|
|
glGenVertexArrays(1, tvai)
|
|
|
|
glBindVertexArray(tvai)
|
|
|
|
|
|
|
|
vid = glGetAttribLocation(key, "in_position")
|
|
|
|
glEnableVertexAttribArray(vid)
|
|
|
|
|
|
|
|
tpbi = glGenBuffers(1)
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, tpbi)
|
|
|
|
positions = []
|
|
|
|
for o in object_list:
|
2022-01-15 14:31:19 +01:00
|
|
|
positions.append(o.pos[0] + self.x_offset)
|
|
|
|
positions.append(o.pos[1] + self.y_offset)
|
|
|
|
positions.append(o.pos[2] + self.z_offset)
|
2020-11-08 10:20:23 +01:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW)
|
|
|
|
glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None)
|
|
|
|
self.check_error("Could not create position buffer")
|
|
|
|
|
|
|
|
colors = []
|
|
|
|
for o in object_list:
|
|
|
|
colors.append(o.color[0])
|
|
|
|
colors.append(o.color[1])
|
|
|
|
colors.append(o.color[2])
|
|
|
|
tcbi = glGenBuffers(1)
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, tcbi)
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW)
|
|
|
|
vc = glGetAttribLocation(key, "MyInColor")
|
|
|
|
if vc != -1:
|
|
|
|
glEnableVertexAttribArray(vc)
|
|
|
|
glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None)
|
|
|
|
self.check_error("Could not create color buffer")
|
|
|
|
|
|
|
|
if hasattr(object_list[0], 'size'):
|
|
|
|
sizes = []
|
|
|
|
for o in object_list:
|
|
|
|
sizes.append(o.size[0])
|
|
|
|
sizes.append(o.size[1])
|
|
|
|
sizes.append(o.size[2])
|
|
|
|
tsbi = glGenBuffers(1)
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, tsbi)
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW)
|
|
|
|
vs = glGetAttribLocation(key, "MyInSize")
|
|
|
|
if vs != -1:
|
|
|
|
glEnableVertexAttribArray(vs)
|
|
|
|
glVertexAttribPointer(vs, 3, GL_FLOAT, GL_FALSE, 0, None)
|
|
|
|
self.check_error("Could not create size buffer")
|
|
|
|
|
|
|
|
glBindVertexArray(0)
|
|
|
|
self.vais[key] = (tvai, tpbi, tcbi, tsbi, counts[key])
|
|
|
|
self.dirty = False
|
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
def render(self, proj_matrix, geometry_rot_matrix, alternate_programs=None,
|
|
|
|
preselected_program=None, projection_pos=None, rot_pos=None):
|
|
|
|
super(WorldChunk, self).render(proj_matrix, geometry_rot_matrix, alternate_programs,
|
|
|
|
preselected_program, projection_pos, rot_pos)
|
2020-11-08 10:20:23 +01:00
|
|
|
|
|
|
|
for entity in self.entities:
|
2022-01-15 14:31:19 +01:00
|
|
|
entity.render(proj_matrix, geometry_rot_matrix, alternate_programs,
|
|
|
|
preselected_program, projection_pos, rot_pos)
|
2020-11-08 10:20:23 +01:00
|
|
|
|
|
|
|
def set_color(self, x: int, y: int, z: int, r: float, g: float, b: float):
|
|
|
|
assert 0 <= x < self.width, 'Put out of bounds for x coordinate! Must be between 0 and %i' % self.width
|
|
|
|
assert 0 <= y < self.length, 'Put out of bounds for y coordinate! Must be between 0 and %i' % self.length
|
|
|
|
assert 0 <= z < self.height, 'Put out of bounds for z coordinate! Must be between 0 and %i' % self.height
|
|
|
|
|
|
|
|
if self.content[x][y][z] is not None:
|
|
|
|
self.content[x][y][z].setColor(r, g, b)
|
|
|
|
self.dirty = True
|
|
|
|
|
|
|
|
class World(Renderable):
|
|
|
|
def __init__(self, chunk_size_x: int, chunk_size_y: int, chunk_size_z: int,
|
|
|
|
chunk_n_x: int, chunk_n_y: int, chunk_n_z: int, programs: dict):
|
|
|
|
super(World, self).__init__()
|
|
|
|
self.chunk_size_x = chunk_size_x
|
|
|
|
self.chunk_size_y = chunk_size_y
|
|
|
|
self.chunk_size_z = chunk_size_z
|
|
|
|
self.chunk_n_x = chunk_n_x
|
|
|
|
self.chunk_n_y = chunk_n_y
|
|
|
|
self.chunk_n_z = chunk_n_z
|
|
|
|
self.programs = programs
|
|
|
|
|
2021-12-20 17:21:46 +01:00
|
|
|
self.fault_nodes = []
|
|
|
|
self.fault_lines = []
|
|
|
|
self.plates = None
|
|
|
|
self.directions = None
|
2022-01-15 14:31:19 +01:00
|
|
|
self.num_plates = 0
|
|
|
|
self.stone = None
|
|
|
|
self.faults = None
|
2021-12-20 17:21:46 +01:00
|
|
|
|
2020-11-08 10:20:23 +01:00
|
|
|
self.chunks: [[[WorldChunk]]] = []
|
|
|
|
for x in range(chunk_n_x):
|
|
|
|
self.chunks.append([])
|
|
|
|
for y in range(chunk_n_y):
|
|
|
|
self.chunks[x].append([])
|
|
|
|
for z in range(chunk_n_z):
|
|
|
|
self.chunks[x][y].append(None)
|
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
def generate(self, seed: int=None, sea_plate_height: int = 50, continental_plate_height: int = 200):
|
2021-12-20 17:21:46 +01:00
|
|
|
if seed is None:
|
|
|
|
seed = random.randrange(2**32)
|
|
|
|
seed = 229805811
|
|
|
|
print('Generation seed is %i' % seed)
|
|
|
|
random.seed(seed)
|
|
|
|
np.random.seed(seed)
|
|
|
|
node_n = self.chunk_n_x + self.chunk_n_y
|
|
|
|
total_x = self.chunk_n_x * self.chunk_size_x
|
|
|
|
total_y = self.chunk_n_y * self.chunk_size_y
|
|
|
|
nodes = []
|
|
|
|
for _ in range(node_n):
|
|
|
|
nodes.append([random.randint(0, total_x - 1), random.randint(0, total_y - 1)])
|
|
|
|
|
|
|
|
# connections = np.random.randint(2, 5, len(nodes)) #np.zeros(len(nodes)) + 3
|
|
|
|
connections = (np.abs(np.random.normal(0, 5, len(nodes))) + 2).astype(np.int)
|
|
|
|
|
|
|
|
def calc_min_vector(start, end):
|
|
|
|
dx = end[0] - start[0]
|
|
|
|
wrapped_dx = dx % total_x
|
|
|
|
|
|
|
|
dy = end[1] - start[1]
|
|
|
|
wrapped_dy = dy % total_y
|
|
|
|
|
|
|
|
vector = np.array([dx, dy])
|
|
|
|
if wrapped_dx < abs(dx):
|
|
|
|
vector[0] = wrapped_dx
|
|
|
|
if wrapped_dy < abs(dy):
|
|
|
|
vector[1] = wrapped_dy
|
|
|
|
return vector
|
|
|
|
|
|
|
|
def is_intersecting_any(start, end, edges):
|
|
|
|
vec1 = calc_min_vector(start, end)
|
|
|
|
|
|
|
|
for (start2_index, end2_index) in edges:
|
|
|
|
start2 = nodes[start2_index]
|
|
|
|
end2 = nodes[end2_index]
|
|
|
|
|
|
|
|
vec2 = calc_min_vector(start2, end2)
|
|
|
|
|
|
|
|
norm1 = vec1 / np.sqrt(np.sum(np.square(vec1)))
|
|
|
|
norm2 = vec2 / np.sqrt(np.sum(np.square(vec2)))
|
|
|
|
|
|
|
|
# parrallel
|
|
|
|
parallel_threshold = 0.0001
|
|
|
|
if np.sqrt(np.sum(np.square(norm1 - norm2))) < parallel_threshold or np.sqrt(np.sum(np.square(norm1 + norm2))) < parallel_threshold:
|
|
|
|
t = (start[0] - start2[0]) / vec2[0]
|
|
|
|
t2 = (end[0] - start2[0]) / vec2[0]
|
|
|
|
s = (start2[0] - start[0]) / vec1[0]
|
|
|
|
s2 = (end2[0] - start[0]) / vec1[0]
|
|
|
|
if (start2[1] + t * vec2[1]) - start[1] < parallel_threshold:
|
|
|
|
if (0 <= t <= 1.0 and 0 <= t2 <= 1.0) or (0 <= s <= 1.0 and 0 <= s2 <= 1.0):
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if start != start2 and end != end2 and end != start2 and start != end2:
|
|
|
|
t = (vec1[0] * start[1] + vec1[1] * start2[0] - vec1[1] * start[0] - start2[1] * vec1[0]) / (vec2[1] * vec1[0] - vec2[0] * vec1[1])
|
|
|
|
if 0 <= t <= 1.0:
|
|
|
|
intersection = np.array(start2) + vec2 * t
|
|
|
|
s = (intersection[0] - start[0]) / vec1[0]
|
|
|
|
if 0 <= s <= 1.0:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for index, node in enumerate(nodes):
|
|
|
|
distances = []
|
|
|
|
for other_index, other_node in enumerate(nodes):
|
|
|
|
if node != other_node and (index, other_index) not in self.fault_lines and\
|
|
|
|
(other_index, index) not in self.fault_lines:
|
|
|
|
if (not is_intersecting_any(node, other_node, self.fault_lines)) and (not is_intersecting_any(other_node, node, self.fault_lines)):
|
|
|
|
distances.append((other_index, np.sqrt(np.sum(np.square(calc_min_vector(node, other_node))))))
|
|
|
|
|
|
|
|
distances.sort(key=lambda element: element[1])
|
|
|
|
while connections[index] > 0 and len(distances) > 0:
|
|
|
|
self.fault_lines.append((index, distances[0][0]))
|
|
|
|
connections[distances[0][0]] -= 1
|
|
|
|
connections[index] -= 1
|
|
|
|
distances.pop(0)
|
|
|
|
|
|
|
|
self.fault_nodes = nodes
|
|
|
|
|
|
|
|
plates = np.zeros((total_x, total_y))
|
|
|
|
faults = np.zeros((total_x, total_y)) - 1
|
|
|
|
plate_bordering_fault = {}
|
|
|
|
# draw fault lines
|
|
|
|
for fault_index, fault_line in enumerate(self.fault_lines):
|
|
|
|
start = self.fault_nodes[fault_line[0]]
|
|
|
|
end = self.fault_nodes[fault_line[1]]
|
|
|
|
vector = calc_min_vector(start, end)
|
|
|
|
vector = vector / np.sqrt(np.sum(np.square(vector)))
|
|
|
|
|
|
|
|
point = np.array(start, dtype=np.float)
|
|
|
|
plate_bordering_fault[fault_index] = []
|
|
|
|
|
|
|
|
while np.sqrt(np.sum(np.square(point - np.array(end)))) > 0.5:
|
|
|
|
plates[int(point[0]), int(point[1])] = -1
|
|
|
|
if faults[int(point[0]), int(point[1])] == -1:
|
|
|
|
faults[int(point[0]), int(point[1])] = fault_index
|
|
|
|
elif faults[int(point[0]), int(point[1])] != fault_index:
|
|
|
|
faults[int(point[0]), int(point[1])] = -2
|
|
|
|
point += 0.5 * vector
|
|
|
|
point[0] %= total_x
|
|
|
|
point[1] %= total_y
|
|
|
|
self.faults = faults
|
|
|
|
|
|
|
|
plate = 1
|
|
|
|
while np.any(plates == 0):
|
|
|
|
start = np.where(plates == 0)
|
|
|
|
start = (start[0][0], start[1][0])
|
|
|
|
plates[start] = plate
|
|
|
|
work_list = [start]
|
|
|
|
|
|
|
|
while len(work_list) > 0:
|
|
|
|
work = work_list.pop()
|
|
|
|
|
|
|
|
up = (work[0], (work[1] + 1) % total_y)
|
|
|
|
down = (work[0], (work[1] - 1) % total_y)
|
|
|
|
left = ((work[0] - 1) % total_x, work[1])
|
|
|
|
right = ((work[0] + 1) % total_x, work[1])
|
|
|
|
|
|
|
|
if plates[up] == -1 and plates[down] == -1 and plates[left] == -1 and plates[right] == -1:
|
|
|
|
plates[work] = -1
|
|
|
|
continue
|
|
|
|
|
|
|
|
if plates[up] <= 0:
|
|
|
|
if plates[up] == 0:
|
|
|
|
work_list.append(up)
|
|
|
|
plates[up] = plate
|
|
|
|
if plates[down] <= 0:
|
|
|
|
if plates[down] == 0:
|
|
|
|
work_list.append(down)
|
|
|
|
plates[down] = plate
|
|
|
|
if plates[left] <= 0:
|
|
|
|
if plates[left] == 0:
|
|
|
|
work_list.append(left)
|
|
|
|
plates[left] = plate
|
|
|
|
if plates[right] <= 0:
|
|
|
|
if plates[right] == 0:
|
|
|
|
work_list.append(right)
|
|
|
|
plates[right] = plate
|
|
|
|
|
|
|
|
if faults[up] > -1:
|
|
|
|
if plate not in plate_bordering_fault[faults[up]]:
|
|
|
|
plate_bordering_fault[faults[up]].append(plate)
|
|
|
|
if faults[down] > -1:
|
|
|
|
if plate not in plate_bordering_fault[faults[down]]:
|
|
|
|
plate_bordering_fault[faults[down]].append(plate)
|
|
|
|
if faults[left] > -1:
|
|
|
|
if plate not in plate_bordering_fault[faults[left]]:
|
|
|
|
plate_bordering_fault[faults[left]].append(plate)
|
|
|
|
if faults[right] > -1:
|
|
|
|
if plate not in plate_bordering_fault[faults[right]]:
|
|
|
|
plate_bordering_fault[faults[right]].append(plate)
|
|
|
|
plate += 1
|
|
|
|
|
|
|
|
plate_num = plate
|
|
|
|
for plate in range(1, plate_num):
|
|
|
|
if np.sum(plates == plate) < 20:
|
|
|
|
plates[plates == plate] = -1
|
|
|
|
for key, item in plate_bordering_fault.items():
|
|
|
|
if plate in item:
|
|
|
|
item.remove(plate)
|
|
|
|
|
|
|
|
directions = np.zeros((total_x, total_y, 3))
|
|
|
|
|
|
|
|
coords = np.zeros((total_x, total_y, 2))
|
|
|
|
for x in range(total_x):
|
|
|
|
for y in range(total_y):
|
|
|
|
coords[x, y, 0] = x
|
|
|
|
coords[x, y, 1] = y
|
|
|
|
|
|
|
|
for fault_index, fault_line in enumerate(self.fault_lines):
|
|
|
|
start = self.fault_nodes[fault_line[0]]
|
|
|
|
end = self.fault_nodes[fault_line[1]]
|
|
|
|
vector = calc_min_vector(start, end)
|
|
|
|
vector = vector / np.sqrt(np.sum(np.square(vector)))
|
|
|
|
|
|
|
|
perpendicular = np.array([vector[1], -vector[0]])
|
|
|
|
|
|
|
|
if len(plate_bordering_fault[fault_index]) == 2:
|
|
|
|
for plate in plate_bordering_fault[fault_index]:
|
|
|
|
vecs = coords - np.array(start)
|
|
|
|
lengths = np.sqrt(np.sum(np.square(vecs), axis=2, keepdims=True))
|
|
|
|
norm_vecs = vecs / lengths
|
|
|
|
scalars = np.sum(norm_vecs * perpendicular, axis=2, keepdims=True)
|
|
|
|
scalars[lengths == 0] = 0
|
|
|
|
|
|
|
|
end_vecs = coords - np.array(end)
|
|
|
|
end_lengths = np.sqrt(np.sum(np.square(end_vecs), axis=2, keepdims=True))
|
|
|
|
end_min_length = np.min(end_lengths[np.logical_and(plates == plate, end_lengths[:, :, 0] > 0)])
|
|
|
|
end_min_length_scalar = scalars[np.logical_and(plates == plate, end_lengths[:, :, 0] == end_min_length)][0, 0]
|
|
|
|
|
|
|
|
min_length = np.min(lengths[np.logical_and(plates == plate, lengths[:, :, 0] > 0)])
|
|
|
|
min_length_scalar = scalars[np.logical_and(plates == plate, lengths[:, :, 0] == min_length)][0, 0]
|
|
|
|
|
|
|
|
mean_scalar = np.mean(scalars[plates == plate])
|
|
|
|
|
|
|
|
if (min_length_scalar / abs(min_length_scalar)) == (end_min_length_scalar / abs(end_min_length_scalar)):
|
|
|
|
scalar = min_length_scalar
|
|
|
|
else:
|
|
|
|
if (min_length_scalar / abs(min_length_scalar)) == (mean_scalar / abs(mean_scalar)):
|
|
|
|
scalar = min_length_scalar
|
|
|
|
else:
|
|
|
|
scalar = end_min_length_scalar
|
|
|
|
|
|
|
|
directions[plates == plate, :2] += perpendicular * (scalar / abs(scalar))
|
|
|
|
pass
|
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
for x in range(total_x):
|
|
|
|
for y in range(total_y):
|
|
|
|
if plates[x, y] == -1:
|
|
|
|
plate = np.max(plates[x - 1: x + 1, y - 1: y + 1])
|
|
|
|
plates[x, y] = plate
|
2021-12-20 17:21:46 +01:00
|
|
|
|
|
|
|
self.plates = plates
|
|
|
|
self.directions = directions
|
2022-01-15 14:31:19 +01:00
|
|
|
self.num_plates = plate_num
|
|
|
|
|
|
|
|
# max height will be three times the continental height
|
|
|
|
# sea level will be at one and a half time continental height
|
|
|
|
# with the continental plates top end ending there
|
|
|
|
# sea plates will be flush at the bottom end
|
|
|
|
max_height = 3 * continental_plate_height
|
|
|
|
sea_level = int(1.5 * continental_plate_height)
|
|
|
|
lower_level = sea_level - continental_plate_height
|
|
|
|
upper_sea_plate_level = lower_level + sea_plate_height
|
|
|
|
|
|
|
|
# stone kinds: 0: lava/air, 1: sea_plate, 2: magmatic_continental, 3: metamorph, 4: sedimental_rock, 5: sediment
|
|
|
|
self.stone = np.zeros((total_x, total_y, max_height), np.int)
|
|
|
|
plate_to_type = {}
|
|
|
|
for plate in range(1, plate_num):
|
|
|
|
if random.randint(1, 2) == 1:
|
|
|
|
self.stone[plates == plate, lower_level:upper_sea_plate_level] = SEA_PLATE_STONE
|
|
|
|
plate_to_type[plate] = SEA_PLATE
|
|
|
|
else:
|
|
|
|
self.stone[plates == plate, lower_level:sea_level] = MAGMATIC_STONE
|
|
|
|
plate_to_type[plate] = CONTINENTAL_PLATE
|
|
|
|
|
|
|
|
pass
|
2021-12-20 17:21:46 +01:00
|
|
|
|
2020-11-08 10:20:23 +01:00
|
|
|
def set_color(self, x: int, y: int, z: int, r: float, g: float, b: float):
|
|
|
|
x = x % (self.chunk_size_x * self.chunk_n_x)
|
|
|
|
y = y % (self.chunk_size_y * self.chunk_n_y)
|
|
|
|
z = z % (self.chunk_size_z * self.chunk_n_z)
|
|
|
|
|
|
|
|
chunk_x = int(x / self.chunk_size_x)
|
|
|
|
chunk_y = int(y / self.chunk_size_y)
|
|
|
|
chunk_z = int(z / self.chunk_size_z)
|
|
|
|
if self.chunks[chunk_x][chunk_y][chunk_z] is not None:
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].set_color(x % self.chunk_size_x,
|
|
|
|
y % self.chunk_size_y,
|
|
|
|
z % self.chunk_size_z,
|
|
|
|
r, g, b)
|
|
|
|
|
|
|
|
def put_object(self, x: int, y: int, z: int, new_object: Object):
|
|
|
|
x = x % (self.chunk_size_x * self.chunk_n_x)
|
|
|
|
y = y % (self.chunk_size_y * self.chunk_n_y)
|
|
|
|
z = z % (self.chunk_size_z * self.chunk_n_z)
|
|
|
|
|
|
|
|
chunk_x = int(x / self.chunk_size_x)
|
|
|
|
chunk_y = int(y / self.chunk_size_y)
|
|
|
|
chunk_z = int(z / self.chunk_size_z)
|
|
|
|
|
|
|
|
if self.chunks[chunk_x][chunk_y][chunk_z] is None:
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z] = WorldChunk(self.chunk_size_x, self.chunk_size_y, self.chunk_size_z, self.programs)
|
2022-01-15 14:31:19 +01:00
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].x_offset = chunk_x * self.chunk_size_x
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].y_offset = chunk_y * self.chunk_size_z
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].z_offset = chunk_z * self.chunk_size_y
|
2020-11-08 10:20:23 +01:00
|
|
|
|
|
|
|
carry_overs = self.chunks[chunk_x][chunk_y][chunk_z].put_object(x % self.chunk_size_x,
|
|
|
|
y % self.chunk_size_y,
|
|
|
|
z % self.chunk_size_z,
|
|
|
|
new_object)
|
|
|
|
for carry_over in carry_overs:
|
|
|
|
if self.chunks[(chunk_x + carry_over[0]) % self.chunk_n_x][(chunk_y + carry_over[1]) % self.chunk_n_y][(chunk_z + carry_over[2]) % self.chunk_n_z] is not None:
|
|
|
|
self.chunks[
|
|
|
|
(chunk_x + carry_over[0]) % self.chunk_n_x][
|
|
|
|
(chunk_y + carry_over[1]) % self.chunk_n_y][
|
|
|
|
(chunk_z + carry_over[2]) % self.chunk_n_z].apply_visible_carry_over(
|
|
|
|
(x + carry_over[0]) % self.chunk_size_x,
|
|
|
|
(y + carry_over[1]) % self.chunk_size_y,
|
|
|
|
(z + carry_over[2]) % self.chunk_size_z,
|
|
|
|
carry_over[3])
|
|
|
|
self.chunks[
|
|
|
|
(chunk_x + carry_over[0]) % self.chunk_n_x][
|
|
|
|
(chunk_y + carry_over[1]) % self.chunk_n_y][
|
|
|
|
(chunk_z + carry_over[2]) % self.chunk_n_z].dirty = True
|
|
|
|
|
|
|
|
visibility = 6
|
|
|
|
neighbour = self.get_object(x - 1, y, z)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
neighbour = self.get_object(x + 1, y, z)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
neighbour = self.get_object(x, y - 1, z)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
neighbour = self.get_object(x, y + 1, z)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
neighbour = self.get_object(x, y, z - 1)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
neighbour = self.get_object(x, y, z + 1)
|
|
|
|
if neighbour is not None:
|
|
|
|
visibility -= 1
|
|
|
|
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].set_visibility(x % self.chunk_size_x,
|
|
|
|
y % self.chunk_size_y,
|
|
|
|
z % self.chunk_size_z,
|
|
|
|
visibility)
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].dirty = True
|
|
|
|
|
|
|
|
def get_object(self, x: int, y: int, z: int):
|
|
|
|
x = x % (self.chunk_size_x * self.chunk_n_x)
|
|
|
|
y = y % (self.chunk_size_y * self.chunk_n_y)
|
|
|
|
z = z % (self.chunk_size_z * self.chunk_n_z)
|
|
|
|
|
|
|
|
chunk_x = int(x / self.chunk_size_x)
|
|
|
|
chunk_y = int(y / self.chunk_size_y)
|
|
|
|
chunk_z = int(z / self.chunk_size_z)
|
|
|
|
|
|
|
|
if self.chunks[chunk_x][chunk_y][chunk_z] is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return self.chunks[chunk_x][chunk_y][chunk_z].get_object(x % self.chunk_size_x,
|
|
|
|
y % self.chunk_size_y,
|
|
|
|
z % self.chunk_size_z)
|
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
def render(self, proj_matrix, geometry_rot_matrix, alternate_programs=None,
|
|
|
|
preselected_program=None, projection_pos=None, rot_pos=None):
|
|
|
|
if preselected_program is not None:
|
|
|
|
for x in range(self.chunk_n_x):
|
|
|
|
for y in range(self.chunk_n_y):
|
|
|
|
for z in range(self.chunk_n_z):
|
|
|
|
if self.chunks[x][y][z] is not None:
|
|
|
|
self.chunks[x][y][z].render(proj_matrix,
|
|
|
|
geometry_rot_matrix, alternate_programs,
|
|
|
|
preselected_program, projection_pos, rot_pos)
|
|
|
|
else:
|
|
|
|
for _, program_id in self.programs.items():
|
|
|
|
if alternate_programs == None:
|
|
|
|
used_program_id = program_id
|
|
|
|
else:
|
|
|
|
assert program_id in alternate_programs.keys()
|
|
|
|
used_program_id = alternate_programs[program_id]
|
|
|
|
glUseProgram(used_program_id)
|
|
|
|
self.check_error("Renderingprogram is not initialized!")
|
|
|
|
projection = glGetUniformLocation(used_program_id, 'projModelViewMatrix')
|
|
|
|
rot = glGetUniformLocation(used_program_id, 'rotMatrix')
|
|
|
|
glUniformMatrix3fv(rot, 1, GL_FALSE, np.array(geometry_rot_matrix))
|
|
|
|
glUniformMatrix4fv(projection, 1, GL_FALSE, np.array(proj_matrix))
|
|
|
|
for x in range(self.chunk_n_x):
|
|
|
|
for y in range(self.chunk_n_y):
|
|
|
|
for z in range(self.chunk_n_z):
|
|
|
|
if self.chunks[x][y][z] is not None:
|
|
|
|
self.chunks[x][y][z].render(proj_matrix,
|
|
|
|
geometry_rot_matrix, alternate_programs,
|
|
|
|
used_program_id, projection, rot)
|
|
|
|
|
|
|
|
def add_light(self, x: float, y: float, z: float, l: Light)-> Light:
|
2020-11-08 10:20:23 +01:00
|
|
|
x = x % (self.chunk_size_x * self.chunk_n_x)
|
|
|
|
y = y % (self.chunk_size_y * self.chunk_n_y)
|
|
|
|
z = z % (self.chunk_size_z * self.chunk_n_z)
|
|
|
|
|
|
|
|
chunk_x = int(x / self.chunk_size_x)
|
|
|
|
chunk_y = int(y / self.chunk_size_y)
|
|
|
|
chunk_z = int(z / self.chunk_size_z)
|
|
|
|
|
|
|
|
if self.chunks[chunk_x][chunk_y][chunk_z] is None:
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z] = WorldChunk(self.chunk_size_x, self.chunk_size_y, self.chunk_size_z, self.programs)
|
2022-01-15 14:31:19 +01:00
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].x_offset = chunk_x * self.chunk_size_x
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].y_offset = chunk_y * self.chunk_size_z
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].z_offset = chunk_z * self.chunk_size_y
|
2020-11-08 10:20:23 +01:00
|
|
|
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].lights.append(l)
|
|
|
|
l.pos = [x, y, z]
|
|
|
|
|
2022-01-15 14:31:19 +01:00
|
|
|
return l
|
|
|
|
|
2020-11-08 10:20:23 +01:00
|
|
|
def remove_light(self, l: Light):
|
|
|
|
chunk_x = int(l.pos[0] / self.chunk_size_x)
|
|
|
|
chunk_y = int(l.pos[1] / self.chunk_size_y)
|
|
|
|
chunk_z = int(l.pos[2] / self.chunk_size_z)
|
|
|
|
|
|
|
|
if self.chunks[chunk_x][chunk_y][chunk_z] is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
if l in self.chunks[chunk_x][chunk_y][chunk_z].lights:
|
|
|
|
self.chunks[chunk_x][chunk_y][chunk_z].lights.remove(l)
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def move_light(self, l: Light, target_x: float, target_y: float, target_z: float):
|
|
|
|
self.remove_light(l)
|
|
|
|
self.add_light(target_x, target_y, target_z, l)
|
|
|
|
|
|
|
|
def get_lights_to_render(self, pos, distance):
|
|
|
|
distance_x = math.ceil(float(distance) / self.chunk_size_x)
|
|
|
|
distance_y = math.ceil(float(distance) / self.chunk_size_y)
|
|
|
|
distance_z = math.ceil(float(distance) / self.chunk_size_z)
|
|
|
|
|
|
|
|
pos_x = int(pos[0] / self.chunk_size_x)
|
|
|
|
pos_y = int(pos[1] / self.chunk_size_y)
|
|
|
|
pos_z = int(pos[2] / self.chunk_size_z)
|
|
|
|
|
|
|
|
lights = []
|
|
|
|
for x in range(distance_x):
|
|
|
|
for y in range(distance_y):
|
|
|
|
for z in range(distance_z):
|
|
|
|
chunk = self.chunks[(pos_x + x) % self.chunk_n_x][(pos_y + y) % self.chunk_n_y][(pos_z + z) % self.chunk_n_z]
|
|
|
|
if chunk is not None:
|
|
|
|
lights += chunk.lights
|
|
|
|
|
|
|
|
return lights
|