import random
from bresenham import bresenham
from redeclipse.objects import cube
from redeclipse.vector import FineVector
from redeclipse.vector.orientations import TILE_VOX_OFF, NORTH, SOUTH, EAST, WEST, ABOVE, BELOW
ROOM_SIZE = 8
[docs]def line_points(start, end):
"""
TODO: this is broken af currently.
"""
print("Line from ", start, 'to', end)
if start.x == end.x:
return []
xy = list(bresenham(start.x, start.y, end.x, end.y))
xz = list(bresenham(start.x, start.z, end.x, end.z))
print(xy)
print(xz)
# There are gonna be uuuugly cases aren't there :(
kv = {}
for x in range(start.x, end.x + 1):
kv[x] = {
'y': [],
'z': [],
}
print(kv)
for pxz in xz:
kv[pxz[0]]['z'].append(pxz[1])
for pxy in xy:
kv[pxy[0]]['y'].append(pxy[1])
# resolve
for pt in kv.keys():
ys = kv[pt]['y']
zs = kv[pt]['z']
if len(ys) == len(zs):
for (y, z) in zip(ys, zs):
yield FineVector(pt, y, z)
elif len(ys) % len(zs) == 0:
# eg. 9ys and 3zs
it_size = len(ys) // len(zs)
for i in range(len(zs)):
for j in range(it_size):
yield FineVector(pt, ys[i + j], zs[i])
elif len(zs) % len(ys) == 0:
it_size = len(zs) // len(ys)
for i in range(len(ys)):
for j in range(it_size):
yield FineVector(pt, ys[i], zs[i + j])
else:
# worst case.
for i in range(len(ys)):
for j in range(len(zs)):
yield FineVector(pt, ys[i], zs[j])
[docs]def column_points(size, direction):
"""
Yield points needed to draw a column
:param int size: Length of column
:param str direction: direction the column should go in. One of (±x/y/z)
:returns: An iterable of FineVectors
:rtype: list(redeclipse.vector.FineVector)
"""
# Convert direction to fine.
direction = direction.fine() / 8
for i in range(size):
yield direction * i
[docs]def wall_points(size, direction, limit_j=100, limit_i=100):
"""
Yield points needed to draw a wall. The semantics of direction are a
bit odd.
:param int size: size of the (square) wall
:param str direction: Face the wall is on, e.g. -z is floor, +z is ceiling (size - 1)
:param int limit_i: A clamp applied to the x component
:param int limit_j: A clamp applied to the y component
:returns: An iterable of FineVectors
:rtype: list(redeclipse.vector.FineVector)
"""
if size > 0:
i_lower_bound = 0
i_upper_bound = size
j_lower_bound = 0
j_upper_bound = size
else:
i_lower_bound = size
i_upper_bound = 0
j_lower_bound = size
j_upper_bound = 0
for i in range(i_lower_bound, i_upper_bound):
# Allow partial_j walls
if i > limit_i:
continue
for j in range(j_lower_bound, j_upper_bound):
# Allow partial_j walls
if j > limit_j:
continue
if direction == BELOW:
yield FineVector(i, j, 0)
elif direction == ABOVE:
yield FineVector(i, j, size - 1)
elif direction == SOUTH:
yield FineVector(i, 0, j)
elif direction == NORTH:
yield FineVector(i, size - 1, j)
elif direction == WEST:
yield FineVector(0, i, j)
elif direction == EAST:
yield FineVector(size - 1, i, j)
[docs]def cube_points(x, y, z):
"""
Yield points needed to draw a rectangular prism or cube.
:param int x: size of the rectangular_prism in the x direction
:param int y: size of the rectangular_prism in the y direction
:param int z: size of the rectangular_prism in the z direction
If, e.g., x is less than zero, it will go from (-x to 0) rather than
(0, x)
:returns: An iterable of FineVectors
:rtype: list(redeclipse.vector.FineVector)
"""
if x > 0:
x_lower_bound = 0
x_upper_bound = x
else:
x_lower_bound = x + 1
x_upper_bound = 1
if y > 0:
y_lower_bound = 0
y_upper_bound = y
else:
y_lower_bound = y + 1
y_upper_bound = 1
if z > 0:
z_lower_bound = 0
z_upper_bound = z
else:
z_lower_bound = z + 1
z_upper_bound = 1
for i in range(x_lower_bound, x_upper_bound):
for j in range(y_lower_bound, y_upper_bound):
for k in range(z_lower_bound, z_upper_bound):
yield FineVector(i, j, k)
[docs]def subtract_or_skip(subtract, prob):
"""
determine if we should subtract or skip based on the parameters.
:param boolean subtract: Should subtract the point
:param float prob: If ``random.random()`` > prob, will return that we
should "skip" the point.
:returns: should we subtract (true) or skip the point (false)
:rtype: boolean
"""
if subtract:
return True
else:
if prob < 1:
if random.random() > prob:
return True
return False
[docs]class ConstructionKitMixin(object):
"""
A mixin for constructing things in the VoxelWorld. The code is still
a bit messy...
"""
[docs] def x(self, construction, world, *args, **kwargs):
funcname = 'x_' + construction
if not hasattr(self, funcname):
raise Exception("Unknown function")
func = getattr(self, funcname)
tex = 2
subtract = kwargs.get('subtract', False)
prob = kwargs.get('prob', 1.1)
if 'tex' in kwargs:
tex = kwargs['tex']
del kwargs['tex']
if 'subtract' in kwargs:
del kwargs['subtract']
if 'prob' in kwargs:
del kwargs['prob']
for point in func(*args, **kwargs):
if subtract_or_skip(subtract, prob):
world.del_pointv(point)
continue
world.set_pointv(point, cube.newtexcube(tex=tex))
[docs] def x_cube(self, offset):
yield self.pos + offset.offset_rotate(self.orientation, offset=TILE_VOX_OFF)
[docs] def x_column(self, offset, direction, length):
local_position = self.pos + offset.offset_rotate(self.orientation, offset=TILE_VOX_OFF)
for point in column_points(length, direction.rotate(self.orientation)):
yield point + local_position
[docs] def x_interpolate(self, offset, start, end):
start = start.rotate(self.orientation).vox()
end = end.rotate(self.orientation).vox()
local_position = self.pos + offset.offset_rotate(self.orientation, offset=TILE_VOX_OFF)
for point in line_points(start, end):
yield point + local_position
[docs] def x_dotted_column(self, offset, direction, length, on=2, off=2):
local_position = self.pos + offset.offset_rotate(self.orientation, offset=TILE_VOX_OFF)
onoff = [True] * on + [False] * off
for idx, point in enumerate(column_points(length, direction.rotate(self.orientation))):
if onoff[idx % len(onoff)]:
yield point + local_position
[docs] def x_ceiling(self, offset, size=ROOM_SIZE):
yield from self.x_rectangular_prism(offset + FineVector(0, 0, 7), FineVector(size, size, 1))
[docs] def x_floor(self, offset, size=ROOM_SIZE):
yield from self.x_rectangular_prism(offset, FineVector(size, size, 1))
[docs] def x_low_wall(self, offset, face):
yield from self.x_wall(offset, face, limit_j=3)
[docs] def x_wall(self, offset, face, limit_j=8):
if face == EAST:
yield from self.x_rectangular_prism(offset + FineVector(7, 0, 0), FineVector(1, 8, limit_j))
elif face == WEST:
yield from self.x_rectangular_prism(offset + FineVector(0, 0, 0), FineVector(1, 8, limit_j))
elif face == NORTH:
yield from self.x_rectangular_prism(offset + FineVector(0, 7, 0), FineVector(8, 1, limit_j))
elif face == SOUTH:
yield from self.x_rectangular_prism(offset + FineVector(0, 0, 0), FineVector(8, 1, limit_j))
[docs] def x_ring(self, offset, size):
# world, FineVector(-2, -2, i), 12, tex=accent_tex)
yield from self.x_rectangular_prism(offset, FineVector(1, size - 1, 1))
yield from self.x_rectangular_prism(offset, FineVector(size - 1, 1, 1))
yield from self.x_rectangular_prism(offset + FineVector(0, size - 1, 0), FineVector(size, 1, 1))
yield from self.x_rectangular_prism(offset + FineVector(size - 1, 0, 0), FineVector(1, size, 1))
[docs] def x_rectangular_prism(self, offset, xyz):
xyz = xyz.rotate(self.orientation).vox()
local_position = self.pos + offset.offset_rotate(self.orientation, offset=TILE_VOX_OFF)
for point in cube_points(xyz.x, xyz.y, xyz.z):
yield point + local_position