Esempio n. 1
0
class Renderer:
    def __init__(self, project='SOURCE', ground=None, walls=(), sky=None, reducing=1):
        self.walls = walls
        self.ground = ground
        self.sky = sky
        self.reducing = reducing
        self.project = project
        self.cp = CameraProperties(project=self.project)

        self.change_y_coordinate()

        self.ground_plane = (0, 0, 1, 0)
        self.walls_planes = [self.define_wall_plane(wall) for wall in self.walls]
        self.get_ground_image()
        self.get_walls_images()

    def change_y_coordinate(self):
        change_y_in_lines = lambda lines: map(lambda line:
                                              map(lambda point: [point[0], self.cp.image.size[1] - point[1] - 1],
                                                  line),
                                              lines)
        self.ground = change_y_in_lines(self.ground)
        self.walls = map(lambda wall: change_y_in_lines(wall), self.walls)

    def get_ground_image(self):
        self.ground_image = Image3D.load(self.project, key='ground')
        if not self.ground_image:
            self.ground_image = self.cp.image2plane_v2(reducing=self.reducing,
                                                       plane=self.ground_plane,
                                                       lines=self.ground,
                                                       key='ground',
                                                       max_size=PROJECTION_SIZE)

    def define_wall_plane(self, wall):
        points = []
        for line in wall:
            points.append(line[0])
        distances = np.zeros((len(points), len(self.ground)))
        for p, point in enumerate(points):
            for l, line in enumerate(self.ground):
                distances[p, l] = dist(point, line[0])
        # print distances
        min_indexes = np.argsort(distances, axis=1)
        min_values = [[distances[i][min_indexes[i, 0]], (i, min_indexes[i, 0])] for i in range(distances.shape[0])]
        min_values.sort(key=lambda m: m[0])
        min_dist_points = [min_values[i][1] for i in (0, 1)]
        points_on_plane = [self.ground[min_dist_points[i][1]][0] for i in (0, 1)]
        # print points_on_plane
        x0, y0, z0 = map(float, self.cp.img2world(point=points_on_plane[0],
                                                  plane=self.ground_plane,
                                                  reducing=self.reducing))
        x1, y1, z1 = map(float, self.cp.img2world(point=points_on_plane[1],
                                                  plane=self.ground_plane,
                                                  reducing=self.reducing))
        x2, y2, z2 = x0, y0, 5.0
        # A = np.linalg.det(np.matrix([[y1 - y0, z1 - z0], [y2 - z0, z2 - z0]]))
        # B = -np.linalg.det(np.matrix([[x1 - x0, z1 - z0], [x2 - x0, z2 - z0]]))
        # C = 0
        # D = -x0 * A - y0 * B
        p1 = np.array([x0, y0, z0])
        p2 = np.array([x1, y1, z1])
        p3 = np.array([x2, y2, z2])
        v1 = p3 - p1
        v2 = p2 - p1
        cp = np.cross(v1, v2)
        a, b, c = cp
        d = -np.dot(cp, p3)
        # print a, b, c, d
        return a, b, c, d

    def get_walls_images(self):
        self.walls_images = []
        for num, wall in enumerate(self.walls):
            img = Image3D.load(self.project, key='wall' + str(num))
            if not img:
                img = self.cp.image2plane_v2(reducing=self.reducing,
                                             plane=self.walls_planes[num],
                                             key='wall' + str(num),
                                             lines=wall,
                                             max_size=PROJECTION_SIZE)
            self.walls_images.append(img)

    @staticmethod
    def __load_texture(image):
        width, height = image.size
        try:
            image = image.tobytes('raw', 'RGB', 0, -1)
            texture = glGenTextures(1)

            glBindTexture(GL_TEXTURE_2D, texture)
            glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
            gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, image)
            return texture
        except SystemError:
            image = image.tobytes('raw', 'RGBA', 0, -1)
            texture = glGenTextures(1)

            glBindTexture(GL_TEXTURE_2D, texture)
            glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
            gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image)
            return texture

    def __draw_ground(self):
        if not self.ground:
            return

        glBindTexture(GL_TEXTURE_2D, self.ground_texture)
        glColor3f(1, 1, 1)
        glBegin(GL_POLYGON)
        glNormal3f(0, 0, 1)

        for line in self.ground:
            _x, _y = line[0]
            wp = self.cp.img2world(point=(_x, _y),
                                   plane=self.ground_plane,
                                   reducing=self.reducing)
            tex_coord = self.ground_image.texture_coordinates(wp)
            glTexCoord2f(tex_coord[0], -tex_coord[1])
            print 'GROUND', wp, tex_coord
            glVertex3fv(wp)
        glEnd()

    def __draw_walls(self):
        for i, wall in enumerate(self.walls):
            glBindTexture(GL_TEXTURE_2D, self.walls_textures[i])
            glBegin(GL_POLYGON)
            # glColor3f(1, 1, 1)
            for line in wall:
                _x, _y = line[0]
                wp = self.cp.img2world(point=(_x, _y),
                                       plane=self.walls_planes[i],
                                       reducing=self.reducing)
                tex_coord = self.walls_images[i].texture_coordinates(wp)
                glTexCoord2f(tex_coord[0], -tex_coord[1])
                print 'WALL', wp, tex_coord
                glVertex3fv(wp)
            glEnd()

    def __draw_cube(self, (x, y, z), size=2):
Esempio n. 2
0
class Renderer:
    def __init__(self, walls=(), ground=None, sky=None, filename='SOURCE-2.jpg', reducing=1):
        self.walls = walls
        self.ground = ground
        print ground
        self.sky = sky

        self.vertexes = VertexData()
        self.triangles = []
        self.count = 0

        self.filename = filename
        self.project = CameraProperties.make_project_name(filename)
        self.cp = CameraProperties(project=self.project)
        self.reducing = reducing
        # self.world_image = self.cp.image2plane(reducing=self.reducing)
        self.world_image = self.get_world_coordinates_image(self.project)

    def get_world_coordinates_image(self, project=''):
        world_image = ExtendedImage.load(project)
        if not world_image:
            world_image = self.cp.image2plane(reducing=self.reducing)
        return world_image

    def set_vertexes(self, increase=2):
        # self.set_ground_by_points_in_grid(increase=1)
        self.set_ground_by_lines(increase=increase)
        # self.set_ground_by_vertexes()
        for wall in self.walls:
            self.set_wall(wall=wall)
        self.set_sky()

    def set_ground_by_lines(self, increase=4.0):
        if not self.ground:
            return
        tangents = [line[0][1] / line[0][0] for line in self.ground]
        idx_min_tg = tangents.index(min(tangents))
        points_count = len(self.ground)
        p1, p2 = self.ground[(idx_min_tg - 1) % points_count][0], \
                 self.ground[(idx_min_tg + 1) % points_count][0]
        next_idx = (idx_min_tg - 1) % points_count if p1[0] > p2[0] \
            else (idx_min_tg + 1) % points_count
        oriented_points = [self.ground[idx_min_tg][0], self.ground[next_idx][0]]
        now_idx, prev_idx = next_idx, idx_min_tg
        idx = self.find_next_point(now_idx=now_idx, prev_idx=prev_idx)
        while now_idx != idx_min_tg:
            print idx
            oriented_points.append(self.ground[idx][0])
            now_idx, prev_idx = idx, now_idx
            idx = self.find_next_point(now_idx=now_idx, prev_idx=prev_idx, count=points_count)
        print oriented_points

        orientations = [self.line_orientation(oriented_points[i], oriented_points[(i + 1) % points_count])
                        for i in range(points_count)]
        param = lambda indx: get_parameters((oriented_points[indx], oriented_points[(indx + 1) % points_count]))
        lines_func = [lambda x, y: y <= get_value(param(i), x) if orientations[i] > 0 else y >= get_value(param(i), x)
                      for i in range(points_count)]

        increase = float(increase)
        min_x, min_y, max_x, max_y = 10000, 10000, 0, 0
        for line in lines:
            x, y = line[0]
            min_x = min(min_x, x)
            min_y = min(min_y, y)
            max_x = max(max_x, x)
            max_y = max(max_y, y)
        square = 0

        x, x_m, y_m = 0, max_x - min_x, max_y - min_y
        while x < x_m:
            y = 0
            while y < y_m:
                if all(func(x, y) for func in lines_func):
                    square += 1
                    from random import random
                    self.vertexes += Vertex(pos=(int(x / increase), int(y / increase), 0),
                                            nor=(0, 0, 1), col=(random(), random(), random()))
                y += 1 / increase
            x += 1 / increase
        # for x in [0: 1/increase: max_x - min_x]:
        #     for y in range((max_y - min_y) * int(increase)):
        #         if all(func(x, y) for func in lines_func):
        #             square += 1
        #             from random import random
        #             self.vertexes += Vertex(pos=(int(x / increase), int(y / increase), 0),
        #                                     nor=(0, 0, 1), col=(random(), random(), random()))
        print square
        if not self.triangles:
            self.set_triangles()

    def set_ground_by_points_in_grid(self, normal=(0, 0, 1), increase=2.0):
        if not self.ground:
            return
        increase = float(increase)
        points_on_plane = get_points_on_plane(self.ground, increase=increase)
        print points_on_plane
        pop = points_on_plane
        square = 0
        for i in range(pop.shape[0]):
            for j in range(pop.shape[1]):
                if pop[i][j]:
                    square += 1
                    from random import random
                    self.vertexes += Vertex(pos=(int(i / increase), int(j / increase), 0),
                                            nor=normal, col=(random(), random(), random()))
        print square
        if not self.triangles:
            self.set_triangles()

    def __draw_ground_by_vertexes(self):
        if not self.ground:
            return
        glColor3f(1, 1, 1)
        glBindTexture(GL_TEXTURE_2D, self.world_texture)
        glBegin(GL_POLYGON)
        glNormal3f(0, 0, -1)
        for line in self.ground:
            point_x, point_y = line[0]
            # glTexCoord2f(point_x / self.image_width, point_y / self.image_height)
            wp = self.cp.img2world(point=(point_x, point_y), reducing=self.reducing)
            glTexCoord2fv(self.world_image.image_coordinates(wp))
            glVertex3f(float(wp[0]), float(wp[1]), 0)
        glEnd()

    @staticmethod
    def find_next_point(now_idx=1, prev_idx=0, count=5):
        return (now_idx + 1 if prev_idx == (now_idx - 1) % count else now_idx - 1) % count

    @staticmethod
    def line_orientation(p1, p2):
        return 1 if p1[0] > p2[0] else -1

    def set_wall(self, wall=None, normal=(1, 0, 0)):
        pass

    def set_sky(self, normal=(0, -1, 0)):
        pass

    def set_triangles(self):
        points = []
        for ver in self.vertexes:
            points.append(ver.pos[0:2])
        triangles = delaunay(points)
        for tri in triangles:
            self.triangles.extend(self.vertexes[tri[i]].pos for i in xrange(3))

    def __draw_cube(self, pos=(), size=1):
        if not pos:
            pos = self.cen
        x1, y1, z1 = pos
        x2, y2, z2 = map(lambda p: p + size, [x1, y1, z1])
        glBindTexture(GL_TEXTURE_2D, self.texture)
        glBegin(GL_POLYGON)  # front face
        glNormal3f(0.0, 0.0, 1.0)
        glTexCoord2f(0, 0)
        glVertex3f(x1, y1, z2)
        glTexCoord2f(1, 0)
        glVertex3f(x2, y1, z2)
        glTexCoord2f(1, 1)
        glVertex3f(x2, y2, z2)
        glTexCoord2f(0, 1)
        glVertex3f(x1, y2, z2)
        glEnd()

        glBegin(GL_POLYGON)  # back face
        glNormal3f(0.0, 0.0, -1.0)
        glTexCoord2f(1, 0)
        glVertex3f(x2, y1, z1)
        glTexCoord2f(0, 0)
        glVertex3f(x1, y1, z1)
        glTexCoord2f(0, 1)
        glVertex3f(x1, y2, z1)
        glTexCoord2f(1, 1)
        glVertex3f(x2, y2, z1)
        glEnd()

        glBegin(GL_POLYGON)  # left face
        glNormal3f(-1.0, 0.0, 0.0)
        glTexCoord2f(0, 0)
        glVertex3f(x1, y1, z1)
        glTexCoord2f(0, 1)
        glVertex3f(x1, y1, z2)
        glTexCoord2f(1, 1)
        glVertex3f(x1, y2, z2)
        glTexCoord2f(1, 0)
        glVertex3f(x1, y2, z1)
        glEnd()

        glBegin(GL_POLYGON)  # right face
        glNormal3f(1.0, 0.0, 0.0)
        glTexCoord2f(0, 1)
        glVertex3f(x2, y1, z2)
        glTexCoord2f(0, 0)
        glVertex3f(x2, y1, z1)
        glTexCoord2f(1, 0)
        glVertex3f(x2, y2, z1)
        glTexCoord2f(1, 1)
        glVertex3f(x2, y2, z2)
        glEnd()

        glBegin(GL_POLYGON)  # top face
        glNormal3f(0.0, 1.0, 0.0)
        glTexCoord2f(0, 1)
        glVertex3f(x1, y2, z2)
        glTexCoord2f(1, 1)
        glVertex3f(x2, y2, z2)
        glTexCoord2f(1, 0)
        glVertex3f(x2, y2, z1)
        glTexCoord2f(0, 0)
        glVertex3f(x1, y2, z1)
        glEnd()

        glBegin(GL_POLYGON)  # bottom face
        glNormal3f(0.0, -1.0, 0.0)
        glTexCoord2f(1, 1)
        glVertex3f(x2, y1, z2)
        glTexCoord2f(1, 0)
        glVertex3f(x1, y1, z2)
        glTexCoord2f(0, 0)
        glVertex3f(x1, y1, z1)
        glTexCoord2f(0, 1)
        glVertex3f(x2, y1, z1)
        glEnd()

    @staticmethod
    def __draw_coordinates():
        glLineWidth(2)
        glColor3f(1, 0, 0)
        glBegin(GL_LINES)
        glVertex3f(0, 0, 0)
        glVertex3f(10, 0, 0)
        glEnd()

        glLineWidth(2)
        glColor3f(0, 1, 0)
        glBegin(GL_LINES)
        glVertex3f(0, 0, 0)
        glVertex3f(0, 10, 0)
        glEnd()

        glLineWidth(2)
        glColor3f(0, 0, 1)
        glBegin(GL_LINES)

        glVertex3f(0, 0, 0)
        glVertex3f(0, 0, 10)
        glEnd()

    def __load_world_texture(self):
        image = self.world_image.image
        self.world_image_width = image.size[0]
        self.world_image_height = image.size[1]
        image = image.tobytes('raw', 'RGBA', 0, -1)
        texture = glGenTextures(1)

        glBindTexture(GL_TEXTURE_2D, texture)  # 2d texture (x and y size)
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, self.world_image_width, self.world_image_height,
                          GL_RGBA, GL_UNSIGNED_BYTE, image)
        self.world_texture = texture

    def __load_texture(self, filename='SOURCE.jpg', image=None):
        if not image:
            image = Image.open(filename)
        self.image_width = image.size[0]
        self.image_height = image.size[1]
        image = image.tobytes('raw', 'RGBA', 0, -1)
        texture = glGenTextures(1)

        glBindTexture(GL_TEXTURE_2D, texture)  # 2d texture (x and y size)
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, self.image_width, self.image_height, GL_RGBA, GL_UNSIGNED_BYTE, image)
        self.texture = texture

    def __init(self):
        glClearColor(0, 0, 0, 0)
        glClearDepth(1.0)
        glDepthFunc(GL_LEQUAL)
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_TEXTURE_2D)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
        # self.eye, self.cen, self.up = [0, 0, 5], [3, 3, 0], [0, 1, 1]
        self.eye, self.cen, self.up = self.cp.get_eye_center_up_right(reducing=self.reducing) / self.world_image.reducing
        self.mouse_x, self.mouse_y, self.push = 0, 0, False
        # self.__load_texture(filename=self.filename)
        self.__load_world_texture()
        gluPerspective(60, 1.5, 0.1, 100000)

    def __reshape(self, width, height):
        glViewport(0, 0, width, height)
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(60.0, float(width) / float(height), 1.0, 1000.0)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(self.eye[0], self.eye[1], self.eye[2],
                  self.cen[0], self.cen[1], self.cen[2],
                  self.up[0], self.up[1], self.up[2])
        print self.eye, self.cen

    def __display(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(self.eye[0], self.eye[1], self.eye[2],
                  self.cen[0], self.cen[1], self.cen[2],
                  self.up[0], self.up[1], self.up[2])
        # glLoadIdentity()
        # glTranslatef(1, 0, 3)
        # glRotatef(0, 1, -1, 0)
        # d = 3 / sqrt(3)
        # glTranslatef(d - 1.5, d - 1.5, d - 1.5)
        # glTranslatef(1.5, 1.5, 1.5)  # move cube from the center
        # glRotatef(0, 1.0, 1.0, 0.0)
        # glTranslatef(-1.5, -1.5, -1.5)  # move cube into the center
        # self.__draw_objects()
        self.__draw_ground_by_vertexes()
        self.__draw_coordinates()
        # self.__draw_cube()
        glutSwapBuffers()

    def __e_pressed(self, speed):
        temp = map(lambda a, b: (a - b) * speed / 3.0, self.cen, self.eye)
        self.eye = map(lambda a, t: a + t, self.eye, temp)
        self.cen = map(lambda a, t: a + t, self.cen, temp)

    def __q_pressed(self, speed):
        temp = map(lambda a, b: (a - b) * speed / 3.0, self.cen, self.eye)
        self.eye = map(lambda a, t: a - t, self.eye, temp)
        self.cen = map(lambda a, t: a - t, self.cen, temp)

    def __w_pressed(self, speed):
        self.eye[2] += 3 * speed
        self.cen[2] += 3 * speed

    def __s_pressed(self, speed):
        self.eye[2] -= 3 * speed
        self.cen[2] -= 3 * speed

    def __a_pressed(self, speed):
        cross_vector = normalize(np.cross(np.array(map(lambda a, b: a - b, self.eye, self.cen)),
                                          np.array(self.up)))
        self.eye = map(lambda a, b: a + b * speed, self.eye, cross_vector)
        self.cen = map(lambda a, b: a + b * speed, self.cen, cross_vector)

    def __d_pressed(self, speed):
        cross_vector = normalize(np.cross(np.array(map(lambda a, b: a - b, self.eye, self.cen)),
                                          np.array(self.up)))
        self.eye = map(lambda a, b: a - b * speed, self.eye, cross_vector)
        self.cen = map(lambda a, b: a - b * speed, self.cen, cross_vector)

    def __keyboard(self, key, mx, my):
        speed = 0.8
        print self.cen, self.eye
        {
            'e': self.__e_pressed,
            'q': self.__q_pressed,
            'w': self.__w_pressed,
            'a': self.__a_pressed,
            's': self.__s_pressed,
            'd': self.__d_pressed,
        }[key](speed)

    def __mouse(self, button, mode, pos_x, pos_y):
        if button == GLUT_LEFT_BUTTON:
            self.mouse_x = pos_x
            self.mouse_y = pos_y
            self.push = True if mode == GLUT_DOWN else False

    def __mouse_move(self, pos_x, pos_y):
        if self.push:
            _x, _y = pos_x - self.mouse_x, pos_y - self.mouse_y
            temp = map(lambda a, b: a - b, self.cen, self.eye)
            if _x:
                fx = _x * pi / 180.0 / 20.0
                self.cen[2] = self.eye[2] + sin(fx) * temp[0] + cos(fx) * temp[2]
                self.cen[0] = self.eye[0] + cos(fx) * temp[0] - sin(fx) * temp[2]
            print _x, _y
            if _y:
                self.cen[1] -= _y / 20.0
        self.mouse_x = pos_x
        self.mouse_y = pos_y

    def render(self):
        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(500, 500)
        glutCreateWindow('First Try')
        glutDisplayFunc(self.__display)
        glutReshapeFunc(self.__reshape)
        glutKeyboardFunc(self.__keyboard)
        glutMouseFunc(self.__mouse)
        glutMotionFunc(self.__mouse_move)
        glutIdleFunc(glutPostRedisplay)
        self.__init()
        glutMainLoop()