diff --git a/functions.py b/functions.py index 68e7015..5dc562d 100644 --- a/functions.py +++ b/functions.py @@ -3,7 +3,7 @@ import colorsys import random import imageio - +import numpy # functions # converts a coordinate from a coordinate with origin at the middle, to a coordinate with origin at the top left @@ -178,8 +178,7 @@ else: return[p1, p2] - -# classes +# new classes class Colour: r = 0 g = 0 @@ -221,52 +220,51 @@ else: return False +class Point2D: + x: float + y: float -class Face: - def __init__(self, points: list[list[float]], colour: Colour, has_edges, has_faces: bool): - self.hasEdges = has_edges # whether the main face has edges - self.colour = colour - self.points = points - self.hasFaces = has_faces + def __init__(self, x, y): + self.x = x + self.y = y - def get_points_order(self): - order = [] - for i, _ in enumerate(self.points): - order.append(i) - return order + def get(self): + return [self.x, self.y] - points: list[list[float]] = [] # main edges of the face (used for distance and back face culling calculations) - colour: Colour = [] # colour of the face - hasEdges: bool = [] - hasFaces: bool = [] +class Point3D: + x: float + y: float + z: float + def __init__(self, xyz : list[float]): + self.x = xyz[0] + self.y = xyz[1] + self.z = xyz[2] -# contains n faces that are all in the same plane -class TexturedFace: - def __init__(self, face: Face): # init from existing face object (probably an easier way of doing this) - self.hasEdges = face.hasEdges # whether the main face has edges - self.colour = face.colour - self.points = face.points - self.hasFaces = face.hasFaces + def translate(self, t_vec): # but whyy + self.x += t_vec.x + self.y += t_vec.y + self.z += t_vec.z - def get_points_order(self): - order = [] - for i, _ in enumerate(self.points): - order.append(i) - return order + def rotate(self, rot_matrix: numpy.array): + point = numpy.array([self.x, self.y, self.z]) + numpy.multiply(point, rot_matrix) - def set_sub_faces(self, sub_faces: list[Face]): - self.sub_faces = sub_faces + def get_2d_point(self, fp_distance): + # converts a 3d point into a 2d point + distance = 0 + # calculate x pos + try: + x = ((fp_distance * self.x) / (self.y - distance)) + # calculate y pos + y = ((fp_distance * self.z) / (self.y - distance)) + except ZeroDivisionError: + x = 0 + y = 0 + return Point2D(x, y) - def get_sub_faces(self): - return self.sub_faces - - points: list[list[float]] = [] # main edges of the face (used for distance and back face culling calculations) - colour: Colour = [] # colour of the main face (should be unused 99% of the time) - hasEdges: bool = [] - hasFaces: bool = [] # whether the main face renders (should always be false) - sub_faces: list[Face] - + def to_list(self): + return [self.x, self.y, self.z] class Texture: # Y -> X -> Colour @@ -290,221 +288,332 @@ def get_pixel_alpha(self, x, y): return self.pixels[y][x].get_alpha() +class Face: + # The face class stores a face with N points, a colour, information about edges and faces with nothing else + points: list[Point3D] + colour: Colour + has_faces: bool + has_edges: bool -class Cube: - position: list[int] = [] - colours: list[Colour] = [] # list of 6 colours [legacy, will be removed] - textures: list[Texture] = [] # list of 6 textures for each face of the cube - has_edges: bool = [] - has_faces: bool = [] - textured_face_list: list[TexturedFace] = None - # ordered top - north - east - south - west - bottom - cubePoints = [[.5, .5, .5], [.5, .5, -.5], [.5, -.5, .5], [.5, -.5, -.5], - [-.5, .5, .5], [-.5, .5, -.5], [-.5, -.5, .5], [-.5, -.5, -.5]] - cubeSides = [[3, 7, 5, 1], [2, 6, 7, 3], [4, 5, 7, 6], [0, 1, 5, 4], [0, 2, 3, 1], [6, 2, 0, 4]] + def __init__(self, points: list[Point3D], colour: Colour, has_edges: bool, has_faces: bool): + self.hasEdges = has_edges # whether the main face has edges + self.colour = colour + self.points = points + self.hasFaces = has_faces - # generate the points for a subdivided 16*16 face - sub_div_points = [] - y = -.5 - for i in range(17): - x = -.5 - sub_div_points.append([]) - for j in range(17): - sub_div_points[i].append([x, y]) - x += 1 / 16 - y += 1 / 16 + def get_points(self): + # returns the positions of points (not rotated, not relative to the player) + return self.points - # generate the face_list for a subdivided 16*16 face - sub_div_faces = [] - y = 0 - for i in range(16): - x = 0 - for j in range(16): - sub_div_faces.append([[x, y], [1 + x, y], [1 + x, 1 + y], [x, y + 1]]) - x += 1 - y += 1 +class TexturedFace(Face): + texture: Texture + # This class inherits from Face, and instead of a base colour it has a texture + def set_texture(self, texture: Texture): + # sets the texture of the textured Face - def __init__(self, position: list[int], colour, has_edges, has_faces): - self.has_edges = has_edges - self.has_faces = has_faces + def get_sub_faces(self): - self.colours = [[], [], [], [], [], []] - self.textures = [[], [], [], [], [], []] - self.position = position - if type(colour) is list: - if type(colour[0]) is Texture: - for i in range(6): - self.textures[i] = colour[i] - else: - for i in range(6): - self.colours[i] = colour[i] - else: - for i in range(6): - self.colours[i] = colour +# new functions +def generateRotMatrix(Rx: int, Ry: int, Rz: int): + # generates a rotation matrix for the current camera rotations + # should only be run once per frame (hopefully a performance improvement?) - # legacy function, will be removed - def get_geometry_points(self, player_pos): - points_list = translate(translate(self.cubePoints, player_pos), self.position) - face_list = copy.deepcopy(self.cubeSides) - return [points_list, face_list] - def has_texture(self): - if not self.textures[0]: - return False - else: - return True +def drawFace(face: Face, rot_matrix: numpy.array, playerPos: Point3D): + # has face to draw and precalculated camera rotation matrix, along with player position as input + # the face has the global coordinates here + x = 0 + face.points[x].translate(playerPos.to_list()).rotate(rot_matrix) - def get_faces(self, player_pos): - face_list: list[Face] = [] - for x in range(6): - points_list = translate(translate(self.cubePoints, player_pos), self.position) - if not self.colours[0]: - face_list.append(Face([points_list[face] - for face in self.cubeSides[x]], - Colour([0, 255, 0]), self.has_edges, False)) - else: - face_list.append(Face([points_list[face] - for face in self.cubeSides[x]], - self.colours[x], self.has_edges, self.has_faces)) - return face_list +def drawTexturedFace(face: Face, transform_matrix: numpy.array): + # has face and a camera rotation + position matrix as input, draws the textured face onto the screen - def get_textured_faces(self, player_pos): # returns a list of 6 textured face objects - if self.textured_face_list is None: - textured_face_list = [TexturedFace(i) for i in self.get_faces([0, 0, 0])] - # top face (translate up by .5) - new_sub_faces = [] - i = 0 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to -.5 for top face positioning - point.insert(2, -.5) - - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - - # bottom face (5) (translate down by .5, mirror in x) - new_sub_faces = [] - i = 5 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to .5 for bottom face positioning - point.insert(2, .5) - # mirror the face in x - point[0] = -point[0] - - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - - # north (swap y and z) - new_sub_faces = [] - i = 1 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to .5 - point.insert(2, .5) - # swap x and z - temp = point[2] - point[2] = point[1] - point[1] = temp - # mirror the face in x - # point[0] = -point[0] - - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - - # south = swap y and z, mirror in x - new_sub_faces = [] - i = 3 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to -.5 - point.insert(2, -.5) - # swap x and z - temp = point[2] - point[2] = point[1] - point[1] = temp - # mirror the face in x - point[0] = -point[0] - - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - - # east face = swap x and z - new_sub_faces = [] - i = 2 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to .5 - point.insert(2, .5) - # swap y and z - temp = point[2] - point[2] = point[1] - point[1] = temp - # swap x and y - temp = point[1] - point[1] = point[0] - point[0] = temp - # mirror the face in y - point[1] = -point[1] - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - # west face = swap y and z, and reverse sub lists - new_sub_faces = [] - i = 4 - for j, face in enumerate(self.sub_div_faces): - points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] - for point in points: - - # set the z coordinate to .5 - point.insert(2, .5) - # swap y and z - temp = point[2] - point[2] = point[1] - point[1] = temp - # swap x and y - temp = point[1] - point[1] = point[0] - point[0] = temp - # mirror the face in x - point[0] = -point[0] - y = j % 16 - x = j // 16 - if True: # not self.textures[i].get_pixel_alpha(x, y): - new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) - textured_face_list[i].set_sub_faces(new_sub_faces) - # return a face_list with the colours of the texture applied - self.textured_face_list = textured_face_list - textured_face_list = copy.deepcopy(self.textured_face_list) - for textured_face in textured_face_list: - for face in textured_face.sub_faces: - for point in face.points: - for i in range(3): - point[i] += player_pos[i] - return textured_face_list +# old classes +# class Face: +# def __init__(self, points: list[list[float]], colour: Colour, has_edges, has_faces: bool): +# self.hasEdges = has_edges # whether the main face has edges +# self.colour = colour +# self.points = points +# self.hasFaces = has_faces +# +# def get_points_order(self): +# order = [] +# for i, _ in enumerate(self.points): +# order.append(i) +# return order +# +# points: list[list[float]] = [] # main edges of the face (used for distance and back face culling calculations) +# colour: Colour = [] # colour of the face +# hasEdges: bool = [] +# hasFaces: bool = [] +# +# +# # contains n faces that are all in the same plane +# class TexturedFace: +# def __init__(self, face: Face): # init from existing face object (probably an easier way of doing this) +# self.hasEdges = face.hasEdges # whether the main face has edges +# self.colour = face.colour +# self.points = face.points +# self.hasFaces = face.hasFaces +# +# def get_points_order(self): +# order = [] +# for i, _ in enumerate(self.points): +# order.append(i) +# return order +# +# def set_sub_faces(self, sub_faces: list[Face]): +# self.sub_faces = sub_faces +# +# def get_sub_faces(self): +# return self.sub_faces +# +# points: list[list[float]] = [] # main edges of the face (used for distance and back face culling calculations) +# colour: Colour = [] # colour of the main face (should be unused 99% of the time) +# hasEdges: bool = [] +# hasFaces: bool = [] # whether the main face renders (should always be false) +# sub_faces: list[Face] +# +# +# class Texture: +# # Y -> X -> Colour +# pixels: list[list[Colour]] = [] +# +# def __init__(self, path: str): +# self.pixels = [] +# +# image = imageio.imread(path) +# for i, image_y in enumerate(image): +# self.pixels.append([]) +# for image_x in image_y: +# self.pixels[i].append(Colour(image_x)) +# +# def get(self): +# return self.pixels +# +# def get_pixel(self, x, y): +# return self.pixels[y][x] +# +# def get_pixel_alpha(self, x, y): +# return self.pixels[y][x].get_alpha() +# +# +# class Cube: +# position: list[int] = [] +# colours: list[Colour] = [] # list of 6 colours [legacy, will be removed] +# textures: list[Texture] = [] # list of 6 textures for each face of the cube +# has_edges: bool = [] +# has_faces: bool = [] +# textured_face_list: list[TexturedFace] = None +# # ordered top - north - east - south - west - bottom +# cubePoints = [[.5, .5, .5], [.5, .5, -.5], [.5, -.5, .5], [.5, -.5, -.5], +# [-.5, .5, .5], [-.5, .5, -.5], [-.5, -.5, .5], [-.5, -.5, -.5]] +# cubeSides = [[3, 7, 5, 1], [2, 6, 7, 3], [4, 5, 7, 6], [0, 1, 5, 4], [0, 2, 3, 1], [6, 2, 0, 4]] +# +# # generate the points for a subdivided 16*16 face +# sub_div_points = [] +# y = -.5 +# for i in range(17): +# x = -.5 +# sub_div_points.append([]) +# for j in range(17): +# sub_div_points[i].append([x, y]) +# x += 1 / 16 +# y += 1 / 16 +# +# # generate the face_list for a subdivided 16*16 face +# sub_div_faces = [] +# y = 0 +# for i in range(16): +# x = 0 +# for j in range(16): +# sub_div_faces.append([[x, y], [1 + x, y], [1 + x, 1 + y], [x, y + 1]]) +# x += 1 +# y += 1 +# +# def __init__(self, position: list[int], colour, has_edges, has_faces): +# self.has_edges = has_edges +# self.has_faces = has_faces +# +# self.colours = [[], [], [], [], [], []] +# self.textures = [[], [], [], [], [], []] +# self.position = position +# +# if type(colour) is list: +# if type(colour[0]) is Texture: +# for i in range(6): +# self.textures[i] = colour[i] +# else: +# for i in range(6): +# self.colours[i] = colour[i] +# else: +# for i in range(6): +# self.colours[i] = colour +# +# # legacy function, will be removed +# def get_geometry_points(self, player_pos): +# points_list = translate(translate(self.cubePoints, player_pos), self.position) +# face_list = copy.deepcopy(self.cubeSides) +# return [points_list, face_list] +# +# def has_texture(self): +# if not self.textures[0]: +# return False +# else: +# return True +# +# def get_faces(self, player_pos): +# face_list: list[Face] = [] +# for x in range(6): +# points_list = translate(translate(self.cubePoints, player_pos), self.position) +# if not self.colours[0]: +# face_list.append(Face([points_list[face] +# for face in self.cubeSides[x]], +# Colour([0, 255, 0]), self.has_edges, False)) +# else: +# face_list.append(Face([points_list[face] +# for face in self.cubeSides[x]], +# self.colours[x], self.has_edges, self.has_faces)) +# return face_list +# +# def get_textured_faces(self, player_pos): # returns a list of 6 textured face objects +# +# if self.textured_face_list is None: +# textured_face_list = [TexturedFace(i) for i in self.get_faces([0, 0, 0])] +# # top face (translate up by .5) +# new_sub_faces = [] +# i = 0 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to -.5 for top face positioning +# point.insert(2, -.5) +# +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# +# # bottom face (5) (translate down by .5, mirror in x) +# new_sub_faces = [] +# i = 5 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to .5 for bottom face positioning +# point.insert(2, .5) +# # mirror the face in x +# point[0] = -point[0] +# +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# +# # north (swap y and z) +# new_sub_faces = [] +# i = 1 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to .5 +# point.insert(2, .5) +# # swap x and z +# temp = point[2] +# point[2] = point[1] +# point[1] = temp +# # mirror the face in x +# # point[0] = -point[0] +# +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# +# # south = swap y and z, mirror in x +# new_sub_faces = [] +# i = 3 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to -.5 +# point.insert(2, -.5) +# # swap x and z +# temp = point[2] +# point[2] = point[1] +# point[1] = temp +# # mirror the face in x +# point[0] = -point[0] +# +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# +# # east face = swap x and z +# new_sub_faces = [] +# i = 2 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to .5 +# point.insert(2, .5) +# # swap y and z +# temp = point[2] +# point[2] = point[1] +# point[1] = temp +# # swap x and y +# temp = point[1] +# point[1] = point[0] +# point[0] = temp +# # mirror the face in y +# point[1] = -point[1] +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# # west face = swap y and z, and reverse sub lists +# new_sub_faces = [] +# i = 4 +# for j, face in enumerate(self.sub_div_faces): +# points = [copy.deepcopy(self.sub_div_points[point[0]][point[1]]) for point in face] +# for point in points: +# +# # set the z coordinate to .5 +# point.insert(2, .5) +# # swap y and z +# temp = point[2] +# point[2] = point[1] +# point[1] = temp +# # swap x and y +# temp = point[1] +# point[1] = point[0] +# point[0] = temp +# # mirror the face in x +# point[0] = -point[0] +# y = j % 16 +# x = j // 16 +# if True: # not self.textures[i].get_pixel_alpha(x, y): +# new_sub_faces.append(Face(points, self.textures[i].get_pixel(x, y), False, True)) +# textured_face_list[i].set_sub_faces(new_sub_faces) +# # return a face_list with the colours of the texture applied +# self.textured_face_list = textured_face_list +# textured_face_list = copy.deepcopy(self.textured_face_list) +# for textured_face in textured_face_list: +# for face in textured_face.sub_faces: +# for point in face.points: +# for i in range(3): +# point[i] += player_pos[i] +# return textured_face_list diff --git a/main.py b/main.py index ff0fa1c..33f1524 100644 --- a/main.py +++ b/main.py @@ -45,11 +45,12 @@ print(placingColours) currentTexture: int = 0 +# create cubes cubes: list[Cube] = [] for x in [[-12, 3, 4], [2, 2, 2], [2, 0, 0], [0, 2, 0], [0, 0, 0], [6, -8, 4]]: cubes.append(Cube(x, Colour([255, 0, 0]), True, True)) - +# axes points axesPoints = [[1000, 0, 0], [-1000, 0, 0], [0, 1000, 0], [0, -1000, 0], [0, 0, 1000], [0, 0, -1000]] axesEdges = [[0, 1], [2, 3], [4, 5]] axesColours = [(0, .8, .8), (.2, .8, 1), (.8, .8, .8)] @@ -94,8 +95,8 @@ # create surfaces mainSurface = pygame.Surface(size) -grass = [Texture("grass.png") for x in range(6)] -cubes.append(Cube([0, 2, 3], grass, True, True)) +# grass = [Texture("grass.png") for x in range(6)] +# cubes.append(Cube([0, 2, 3], grass, True, True)) for i in range(len(polyColour)): polyColour[i] = tuple(255 * x for x in colorsys.hsv_to_rgb(hue, .5, 1))