Exemple #1
0
class GenMapViewer(QtWidgets.QOpenGLWidget):
    mouse_clicked = pyqtSignal(QMouseEvent)
    entity_clicked = pyqtSignal(QMouseEvent, str)
    mouse_dragged = pyqtSignal(QMouseEvent)
    mouse_released = pyqtSignal(QMouseEvent)
    mouse_wheel = pyqtSignal(QWheelEvent)
    position_update = pyqtSignal(QMouseEvent, tuple)
    height_update = pyqtSignal(float)
    select_update = pyqtSignal()
    move_points = pyqtSignal(float, float, float)
    connect_update = pyqtSignal(int, int)
    create_waypoint = pyqtSignal(float, float)
    create_waypoint_3d = pyqtSignal(float, float, float)

    rotate_current = pyqtSignal(Vector3)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._zoom_factor = 10
        self.setFocusPolicy(Qt.ClickFocus)

        self.SIZEX = 1024  #768#1024
        self.SIZEY = 1024  #768#1024

        self.canvas_width, self.canvas_height = self.width(), self.height()

        #self.setMinimumSize(QSize(self.SIZEX, self.SIZEY))
        #self.setMaximumSize(QSize(self.SIZEX, self.SIZEY))
        self.setObjectName("bw_map_screen")

        self.origin_x = self.SIZEX // 2
        self.origin_z = self.SIZEY // 2

        self.offset_x = 0
        self.offset_z = 0

        self.left_button_down = False
        self.mid_button_down = False
        self.right_button_down = False
        self.drag_last_pos = None

        self.selected = []

        #self.p = QPainter()
        #self.p2 = QPainter()
        # self.show_terrain_mode = SHOW_TERRAIN_REGULAR

        self.selectionbox_start = None
        self.selectionbox_end = None

        self.visualize_cursor = None

        self.click_mode = 0

        self.level_image = None

        self.collision = None

        self.highlighttriangle = None

        self.setMouseTracking(True)

        self.pikmin_generators = None
        self.waterboxes = []

        self.mousemode = MOUSE_MODE_NONE

        self.overlapping_wp_index = 0
        self.editorconfig = None

        #self.setContextMenuPolicy(Qt.CustomContextMenu)

        self.spawnpoint = None

        self.shift_is_pressed = False
        self.rotation_is_pressed = False
        self.last_drag_update = 0
        self.change_height_is_pressed = False
        self.last_mouse_move = None

        self.timer = QtCore.QTimer()
        self.timer.setInterval(2)
        self.timer.timeout.connect(self.render_loop)
        self.timer.start()
        self._lastrendertime = 0
        self._lasttime = 0

        self._frame_invalid = False

        self.MOVE_UP = 0
        self.MOVE_DOWN = 0
        self.MOVE_LEFT = 0
        self.MOVE_RIGHT = 0
        self.MOVE_FORWARD = 0
        self.MOVE_BACKWARD = 0
        self.SPEEDUP = 0

        self._wasdscrolling_speed = 1
        self._wasdscrolling_speedupfactor = 3

        self.main_model = None
        self.buffered_deltas = []

        # 3D Setup
        self.mode = MODE_TOPDOWN
        self.camera_horiz = pi * (1 / 2)
        self.camera_vertical = -pi * (1 / 4)
        self.camera_height = 1000
        self.last_move = None

        #self.selection_queue = []
        self.selectionqueue = SelectionQueue()

        self.selectionbox_projected_start = None
        self.selectionbox_projected_end = None

        #self.selectionbox_projected_2d = None
        self.selectionbox_projected_origin = None
        self.selectionbox_projected_up = None
        self.selectionbox_projected_right = None
        self.selectionbox_projected_coords = None
        self.last_position_update = 0
        self.move_collision_plane = Plane(Vector3(0.0, 0.0, 0.0),
                                          Vector3(1.0, 0.0, 0.0),
                                          Vector3(0.0, 1.0, 0.0))

        self.paths = Paths()
        self.usercontrol = UserControl(self)

        # Initialize some models
        with open("resources/gizmo.obj", "r") as f:
            self.gizmo = Gizmo.from_obj(f, rotate=True)

        #self.generic_object = GenericObject()
        self.models = ObjectModels()
        self.grid = Grid(10000, 10000)

        self.modelviewmatrix = None
        self.projectionmatrix = None

    @catch_exception_with_dialog
    def initializeGL(self):
        print(self.context(), self.isValid())
        self.makeCurrent()
        print("OpenGL Version: ", glGetString(GL_VERSION))
        self.rotation_visualizer = glGenLists(1)
        glNewList(self.rotation_visualizer, GL_COMPILE)
        glColor4f(0.0, 0.0, 1.0, 1.0)
        glLineWidth(2.0)
        glBegin(GL_LINES)
        glVertex3f(0.0, 0.0, 0.0)
        glVertex3f(0.0, 40.0, 0.0)
        glEnd()
        glEndList()

        self.models.init_gl()

    def resizeGL(self, width, height):
        # Called upon window resizing: reinitialize the viewport.
        # update the window size
        self.canvas_width, self.canvas_height = width, height
        # paint within the whole window
        glEnable(GL_DEPTH_TEST)
        glViewport(0, 0, self.canvas_width, self.canvas_height)

    @catch_exception
    def set_editorconfig(self, config):
        self.editorconfig = config
        self._wasdscrolling_speed = config.getfloat("wasdscrolling_speed")
        self._wasdscrolling_speedupfactor = config.getfloat(
            "wasdscrolling_speedupfactor")

    def change_from_topdown_to_3d(self):
        if self.mode == MODE_3D:
            return
        else:
            self.mode = MODE_3D

            if self.mousemode == MOUSE_MODE_NONE:
                self.setContextMenuPolicy(Qt.DefaultContextMenu)

            # This is necessary so that the position of the 3d camera equals the middle of the topdown view
            self.offset_x *= -1
            self.do_redraw()

    def change_from_3d_to_topdown(self):
        if self.mode == MODE_TOPDOWN:
            return
        else:
            self.mode = MODE_TOPDOWN
            if self.mousemode == MOUSE_MODE_NONE:
                self.setContextMenuPolicy(Qt.CustomContextMenu)

            self.offset_x *= -1
            self.do_redraw()

    @catch_exception
    def render_loop(self):
        now = default_timer()

        diff = now - self._lastrendertime
        timedelta = now - self._lasttime

        if self.mode == MODE_TOPDOWN:
            self.handle_arrowkey_scroll(timedelta)
        else:
            self.handle_arrowkey_scroll_3d(timedelta)

        if diff > 1 / 60.0:
            if self._frame_invalid:
                self.update()
                self._lastrendertime = now
                self._frame_invalid = False
        self._lasttime = now

    def handle_arrowkey_scroll(self, timedelta):
        if self.selectionbox_projected_coords is not None:
            return

        diff_x = diff_y = 0
        #print(self.MOVE_UP, self.MOVE_DOWN, self.MOVE_LEFT, self.MOVE_RIGHT)
        speedup = 1

        if self.shift_is_pressed:
            speedup = self._wasdscrolling_speedupfactor

        if self.MOVE_FORWARD == 1 and self.MOVE_BACKWARD == 1:
            diff_y = 0
        elif self.MOVE_FORWARD == 1:
            diff_y = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_BACKWARD == 1:
            diff_y = -1 * speedup * self._wasdscrolling_speed * timedelta

        if self.MOVE_LEFT == 1 and self.MOVE_RIGHT == 1:
            diff_x = 0
        elif self.MOVE_LEFT == 1:
            diff_x = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_RIGHT == 1:
            diff_x = -1 * speedup * self._wasdscrolling_speed * timedelta

        if diff_x != 0 or diff_y != 0:
            if self.zoom_factor > 1.0:
                self.offset_x += diff_x * (1.0 +
                                           (self.zoom_factor - 1.0) / 2.0)
                self.offset_z += diff_y * (1.0 +
                                           (self.zoom_factor - 1.0) / 2.0)
            else:
                self.offset_x += diff_x
                self.offset_z += diff_y
            # self.update()

            self.do_redraw()

    def handle_arrowkey_scroll_3d(self, timedelta):
        if self.selectionbox_projected_coords is not None:
            return

        diff_x = diff_y = diff_height = 0
        #print(self.MOVE_UP, self.MOVE_DOWN, self.MOVE_LEFT, self.MOVE_RIGHT)
        speedup = 1

        forward_vec = Vector3(cos(self.camera_horiz), sin(self.camera_horiz),
                              0)
        sideways_vec = Vector3(sin(self.camera_horiz), -cos(self.camera_horiz),
                               0)

        if self.shift_is_pressed:
            speedup = self._wasdscrolling_speedupfactor

        if self.MOVE_FORWARD == 1 and self.MOVE_BACKWARD == 1:
            forward_move = forward_vec * 0
        elif self.MOVE_FORWARD == 1:
            forward_move = forward_vec * (
                1 * speedup * self._wasdscrolling_speed * timedelta)
        elif self.MOVE_BACKWARD == 1:
            forward_move = forward_vec * (
                -1 * speedup * self._wasdscrolling_speed * timedelta)
        else:
            forward_move = forward_vec * 0

        if self.MOVE_LEFT == 1 and self.MOVE_RIGHT == 1:
            sideways_move = sideways_vec * 0
        elif self.MOVE_LEFT == 1:
            sideways_move = sideways_vec * (
                -1 * speedup * self._wasdscrolling_speed * timedelta)
        elif self.MOVE_RIGHT == 1:
            sideways_move = sideways_vec * (
                1 * speedup * self._wasdscrolling_speed * timedelta)
        else:
            sideways_move = sideways_vec * 0

        if self.MOVE_UP == 1 and self.MOVE_DOWN == 1:
            diff_height = 0
        elif self.MOVE_UP == 1:
            diff_height = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_DOWN == 1:
            diff_height = -1 * speedup * self._wasdscrolling_speed * timedelta

        if not forward_move.is_zero() or not sideways_move.is_zero(
        ) or diff_height != 0:
            #if self.zoom_factor > 1.0:
            #    self.offset_x += diff_x * (1.0 + (self.zoom_factor - 1.0) / 2.0)
            #    self.offset_z += diff_y * (1.0 + (self.zoom_factor - 1.0) / 2.0)
            #else:
            self.offset_x += (forward_move.x + sideways_move.x)
            self.offset_z += (forward_move.y + sideways_move.y)
            self.camera_height += diff_height
            # self.update()

            self.do_redraw()

    def set_arrowkey_movement(self, up, down, left, right):
        self.MOVE_UP = up
        self.MOVE_DOWN = down
        self.MOVE_LEFT = left
        self.MOVE_RIGHT = right

    def do_redraw(self, force=False):
        self._frame_invalid = True
        if force:
            self._lastrendertime = 0
            self.update()

    def reset(self, keep_collision=False):
        self.overlapping_wp_index = 0
        self.shift_is_pressed = False
        self.SIZEX = 1024
        self.SIZEY = 1024
        self.origin_x = self.SIZEX // 2
        self.origin_z = self.SIZEY // 2
        self.last_drag_update = 0

        self.left_button_down = False
        self.mid_button_down = False
        self.right_button_down = False
        self.drag_last_pos = None

        self.selectionbox_start = None
        self.selectionbox_end = None

        self.selected = []

        if not keep_collision:
            # Potentially: Clear collision object too?
            self.level_image = None
            self.offset_x = 0
            self.offset_z = 0
            self._zoom_factor = 10
            #self.waterboxes = []

        self.pikmin_generators = None

        self.mousemode = MOUSE_MODE_NONE
        self.spawnpoint = None
        self.rotation_is_pressed = False

        self._frame_invalid = False

        self.MOVE_UP = 0
        self.MOVE_DOWN = 0
        self.MOVE_LEFT = 0
        self.MOVE_RIGHT = 0
        self.SPEEDUP = 0

    def set_collision(self, verts, faces):
        self.collision = Collision(verts, faces)

        if self.main_model is None:
            self.main_model = glGenLists(1)

        glNewList(self.main_model, GL_COMPILE)
        #glBegin(GL_TRIANGLES)
        draw_collision(verts, faces)
        #glEnd()
        glEndList()

    def set_mouse_mode(self, mode):
        assert mode in (MOUSE_MODE_NONE, MOUSE_MODE_ADDWP,
                        MOUSE_MODE_CONNECTWP, MOUSE_MODE_MOVEWP)

        self.mousemode = mode

        if self.mousemode == MOUSE_MODE_NONE and self.mode == MODE_TOPDOWN:
            self.setContextMenuPolicy(Qt.CustomContextMenu)
        else:
            self.setContextMenuPolicy(Qt.DefaultContextMenu)

    @property
    def zoom_factor(self):
        return self._zoom_factor / 10.0

    def zoom(self, fac):
        if 0.1 < (self.zoom_factor + fac) <= 25:
            self._zoom_factor += int(fac * 10)
            #self.update()
            self.do_redraw()

    def mouse_coord_to_world_coord(self, mouse_x, mouse_y):
        zf = self.zoom_factor
        width, height = self.canvas_width, self.canvas_height
        camera_width = width * zf
        camera_height = height * zf

        topleft_x = -camera_width / 2 - self.offset_x
        topleft_y = camera_height / 2 + self.offset_z

        relx = mouse_x / width
        rely = mouse_y / height
        res = (topleft_x + relx * camera_width,
               topleft_y - rely * camera_height)

        return res

    def mouse_coord_to_world_coord_transform(self, mouse_x, mouse_y):
        mat4x4 = Matrix4x4.from_opengl_matrix(
            *glGetFloatv(GL_PROJECTION_MATRIX))
        width, height = self.canvas_width, self.canvas_height
        result = mat4x4.multiply_vec4(mouse_x - width / 2,
                                      mouse_y - height / 2, 0, 1)

        return result

    #@catch_exception_with_dialog
    #@catch_exception
    def paintGL(self):
        start = default_timer()
        offset_x = self.offset_x
        offset_z = self.offset_z

        #start = default_timer()
        glClearColor(1.0, 1.0, 1.0, 0.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        width, height = self.canvas_width, self.canvas_height

        if self.mode == MODE_TOPDOWN:
            glMatrixMode(GL_PROJECTION)
            glLoadIdentity()
            zf = self.zoom_factor
            #glOrtho(-6000.0, 6000.0, -6000.0, 6000.0, -3000.0, 2000.0)
            camera_width = width * zf
            camera_height = height * zf

            glOrtho(-camera_width / 2 - offset_x, camera_width / 2 - offset_x,
                    -camera_height / 2 + offset_z,
                    camera_height / 2 + offset_z, -3000.0, 2000.0)

            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()
        else:
            #glEnable(GL_CULL_FACE)
            # set yellow color for subsequent drawing rendering calls

            glMatrixMode(GL_PROJECTION)
            glLoadIdentity()
            gluPerspective(75, width / height, 3.0, 12800.0 * 1.5)

            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()

            look_direction = Vector3(cos(self.camera_horiz),
                                     sin(self.camera_horiz),
                                     sin(self.camera_vertical))
            # look_direction.unify()
            fac = 1.01 - abs(look_direction.z)
            # print(fac, look_direction.z, look_direction)

            gluLookAt(self.offset_x, self.offset_z, self.camera_height,
                      self.offset_x + look_direction.x * fac,
                      self.offset_z + look_direction.y * fac,
                      self.camera_height + look_direction.z, 0, 0, 1)

            self.camera_direction = Vector3(look_direction.x * fac,
                                            look_direction.y * fac,
                                            look_direction.z)

            #print(self.camera_direction)

        self.modelviewmatrix = numpy.transpose(
            numpy.reshape(glGetFloatv(GL_MODELVIEW_MATRIX), (4, 4)))
        self.projectionmatrix = numpy.transpose(
            numpy.reshape(glGetFloatv(GL_PROJECTION_MATRIX), (4, 4)))
        self.mvp_mat = numpy.dot(self.projectionmatrix, self.modelviewmatrix)
        self.modelviewmatrix_inv = numpy.linalg.inv(self.modelviewmatrix)

        campos = Vector3(self.offset_x, self.camera_height, -self.offset_z)
        self.campos = campos

        if self.mode == MODE_TOPDOWN:
            gizmo_scale = 3 * zf
        else:

            gizmo_scale = (self.gizmo.position - campos).norm() / 130.0

        self.gizmo_scale = gizmo_scale

        #print(self.gizmo.position, campos)

        while len(self.selectionqueue) > 0:
            glClearColor(1.0, 1.0, 1.0, 0.0)
            #
            click_x, click_y, clickwidth, clickheight, shiftpressed, do_gizmo = self.selectionqueue.queue_pop(
            )
            click_y = height - click_y
            hit = 0xFF

            #print("received request", do_gizmo)

            if clickwidth == 1 and clickheight == 1:
                self.gizmo.render_collision_check(gizmo_scale,
                                                  is3d=self.mode == MODE_3D)
                pixels = glReadPixels(click_x, click_y, clickwidth,
                                      clickheight, GL_RGB, GL_UNSIGNED_BYTE)
                #print(pixels)
                hit = pixels[2]
                if do_gizmo and hit != 0xFF:
                    self.gizmo.run_callback(hit)
                    self.gizmo.was_hit_at_all = True
                #if hit != 0xFF and do_:

            glClearColor(1.0, 1.0, 1.0, 0.0)

            if self.pikmin_generators is not None and hit == 0xFF and not do_gizmo:
                objects = self.pikmin_generators.generators
                glDisable(GL_TEXTURE_2D)
                for i, pikminobject in enumerate(objects):
                    self.models.render_object_coloredid(pikminobject, i)

                pixels = glReadPixels(click_x, click_y, clickwidth,
                                      clickheight, GL_RGB, GL_UNSIGNED_BYTE)
                #print(pixels, click_x, click_y, clickwidth, clickheight)
                selected = {}
                #for i in range(0, clickwidth*clickheight, 4):
                start = default_timer()
                """for x in range(0, clickwidth, 3):
                    for y in range(0, clickheight, 3):
                        i = (x + y*clickwidth)*3
                        # | (pixels[i*3+0] << 16)
                        if pixels[i + 1] != 0xFF:
                            index = (pixels[i + 1] << 8) | pixels[i + 2]
                            #print(index)
                            pikminobject = objects[index]
                            selected[pikminobject] = True
                """
                for i in range(0, clickwidth * clickheight, 13):
                    # | (pixels[i*3+0] << 16)
                    if pixels[i * 3 + 1] != 0xFF:
                        index = (pixels[i * 3 + 1] << 8) | pixels[i * 3 + 2]
                        #print(index)

                        pikminobject = objects[index]
                        selected[pikminobject] = True
                #print("select time taken", default_timer() - start)
                selected = list(selected.keys())

                #print("result:", selected)
                if not shiftpressed:
                    self.selected = selected
                    self.select_update.emit()

                elif shiftpressed:
                    for obj in selected:
                        if obj not in self.selected:
                            self.selected.append(obj)
                    self.select_update.emit()

                self.gizmo.move_to_average(self.selected)
                if len(selected) == 0:
                    #print("Select did register")
                    self.gizmo.hidden = True
                if self.mode == MODE_3D:  # In case of 3D mode we need to update scale due to changed gizmo position
                    gizmo_scale = (self.gizmo.position - campos).norm() / 130.0
                #print("total time taken", default_timer() - start)
        #print("gizmo status", self.gizmo.was_hit_at_all)
        glClearColor(1.0, 1.0, 1.0, 0.0)

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glEnable(GL_DEPTH_TEST)
        glDisable(GL_TEXTURE_2D)
        glColor4f(1.0, 1.0, 1.0, 1.0)
        if self.main_model is not None:
            glCallList(self.main_model)

        glColor4f(1.0, 1.0, 1.0, 1.0)
        self.grid.render()
        if self.mode == MODE_TOPDOWN:
            glClear(GL_DEPTH_BUFFER_BIT)
        #    glDisable(GL_DEPTH_TEST)

        glEnable(GL_ALPHA_TEST)
        glAlphaFunc(GL_GEQUAL, 0.5)

        if self.pikmin_generators is not None:
            selected = self.selected
            objects = self.pikmin_generators.generators

            for pikminobject in objects:
                self.models.render_object(pikminobject, pikminobject
                                          in selected)

        glDisable(GL_TEXTURE_2D)
        glColor4f(0.0, 1.0, 0.0, 1.0)
        rendered = {}
        for p1i, p2i in self.paths.unique_paths:
            p1 = self.paths.waypoints[p1i]
            p2 = self.paths.waypoints[p2i]

            glBegin(GL_LINES)
            glVertex3f(p1.position.x, -p1.position.z, p1.position.y + 5)
            glVertex3f(p2.position.x, -p2.position.z, p2.position.y + 5)
            glEnd()

            if p1i not in rendered:
                self.models.draw_sphere(p1.position, p1.radius / 2)
                rendered[p1i] = True
            if p2i not in rendered:
                self.models.draw_sphere(p2.position, p2.radius / 2)
                rendered[p2i] = True
        glColor4f(0.0, 1.0, 1.0, 1.0)
        """for points in self.paths.wide_paths:
            glBegin(GL_LINE_LOOP)
            for p in points:
                glVertex3f(p.x, -p.z, p.y + 5)

            glEnd()"""

        self.gizmo.render_scaled(gizmo_scale, is3d=self.mode == MODE_3D)
        glDisable(GL_DEPTH_TEST)
        if self.selectionbox_start is not None and self.selectionbox_end is not None:
            #print("drawing box")
            startx, startz = self.selectionbox_start
            endx, endz = self.selectionbox_end
            glColor4f(1.0, 0.0, 0.0, 1.0)
            glLineWidth(2.0)
            glBegin(GL_LINE_LOOP)
            glVertex3f(startx, startz, 0)
            glVertex3f(startx, endz, 0)
            glVertex3f(endx, endz, 0)
            glVertex3f(endx, startz, 0)

            glEnd()

        if self.selectionbox_projected_origin is not None and self.selectionbox_projected_coords is not None:
            #print("drawing box")
            origin = self.selectionbox_projected_origin
            point2, point3, point4 = self.selectionbox_projected_coords
            glColor4f(1.0, 0.0, 0.0, 1.0)
            glLineWidth(2.0)

            point1 = origin

            glBegin(GL_LINE_LOOP)
            glVertex3f(point1.x, point1.y, point1.z)
            glVertex3f(point2.x, point2.y, point2.z)
            glVertex3f(point3.x, point3.y, point3.z)
            glVertex3f(point4.x, point4.y, point4.z)
            glEnd()

        glEnable(GL_DEPTH_TEST)
        glFinish()
        now = default_timer() - start
        #print("Frame time:", now, 1/now, "fps")

    @catch_exception
    def mousePressEvent(self, event):
        self.usercontrol.handle_press(event)

    @catch_exception
    def mouseMoveEvent(self, event):
        self.usercontrol.handle_move(event)

    @catch_exception
    def mouseReleaseEvent(self, event):
        self.usercontrol.handle_release(event)

    def wheelEvent(self, event):
        wheel_delta = event.angleDelta().y()

        if self.editorconfig is not None:
            invert = self.editorconfig.getboolean("invertzoom")
            if invert:
                wheel_delta = -1 * wheel_delta

        if wheel_delta < 0:
            self.zoom_out()

        elif wheel_delta > 0:
            self.zoom_in()

    def zoom_in(self):
        current = self.zoom_factor

        fac = calc_zoom_out_factor(current)

        self.zoom(fac)

    def zoom_out(self):
        current = self.zoom_factor
        fac = calc_zoom_in_factor(current)

        self.zoom(fac)

    def create_ray_from_mouseclick(self, mousex, mousey, yisup=False):
        self.camera_direction.normalize()
        height = self.canvas_height
        width = self.canvas_width

        view = self.camera_direction.copy()

        h = view.cross(Vector3(0, 0, 1))
        v = h.cross(view)

        h.normalize()
        v.normalize()

        rad = 75 * pi / 180.0
        vLength = tan(rad / 2) * 1.0
        hLength = vLength * (width / height)

        v *= vLength
        h *= hLength

        x = mousex - width / 2
        y = height - mousey - height / 2

        x /= (width / 2)
        y /= (height / 2)
        camerapos = Vector3(self.offset_x, self.offset_z, self.camera_height)

        pos = camerapos + view * 1.0 + h * x + v * y
        dir = pos - camerapos

        if yisup:
            tmp = pos.y
            pos.y = -pos.z
            pos.z = tmp

            tmp = dir.y
            dir.y = -dir.z
            dir.z = tmp

        return Line(pos, dir)
Exemple #2
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._zoom_factor = 10
        self.setFocusPolicy(Qt.ClickFocus)

        self.SIZEX = 1024  #768#1024
        self.SIZEY = 1024  #768#1024

        self.canvas_width, self.canvas_height = self.width(), self.height()

        #self.setMinimumSize(QSize(self.SIZEX, self.SIZEY))
        #self.setMaximumSize(QSize(self.SIZEX, self.SIZEY))
        self.setObjectName("bw_map_screen")

        self.origin_x = self.SIZEX // 2
        self.origin_z = self.SIZEY // 2

        self.offset_x = 0
        self.offset_z = 0

        self.left_button_down = False
        self.mid_button_down = False
        self.right_button_down = False
        self.drag_last_pos = None

        self.selected = []

        #self.p = QPainter()
        #self.p2 = QPainter()
        # self.show_terrain_mode = SHOW_TERRAIN_REGULAR

        self.selectionbox_start = None
        self.selectionbox_end = None

        self.visualize_cursor = None

        self.click_mode = 0

        self.level_image = None

        self.collision = None

        self.highlighttriangle = None

        self.setMouseTracking(True)

        self.pikmin_generators = None
        self.waterboxes = []

        self.mousemode = MOUSE_MODE_NONE

        self.overlapping_wp_index = 0
        self.editorconfig = None

        #self.setContextMenuPolicy(Qt.CustomContextMenu)

        self.spawnpoint = None

        self.shift_is_pressed = False
        self.rotation_is_pressed = False
        self.last_drag_update = 0
        self.change_height_is_pressed = False
        self.last_mouse_move = None

        self.timer = QtCore.QTimer()
        self.timer.setInterval(2)
        self.timer.timeout.connect(self.render_loop)
        self.timer.start()
        self._lastrendertime = 0
        self._lasttime = 0

        self._frame_invalid = False

        self.MOVE_UP = 0
        self.MOVE_DOWN = 0
        self.MOVE_LEFT = 0
        self.MOVE_RIGHT = 0
        self.MOVE_FORWARD = 0
        self.MOVE_BACKWARD = 0
        self.SPEEDUP = 0

        self._wasdscrolling_speed = 1
        self._wasdscrolling_speedupfactor = 3

        self.main_model = None
        self.buffered_deltas = []

        # 3D Setup
        self.mode = MODE_TOPDOWN
        self.camera_horiz = pi * (1 / 2)
        self.camera_vertical = -pi * (1 / 4)
        self.camera_height = 1000
        self.last_move = None

        #self.selection_queue = []
        self.selectionqueue = SelectionQueue()

        self.selectionbox_projected_start = None
        self.selectionbox_projected_end = None

        #self.selectionbox_projected_2d = None
        self.selectionbox_projected_origin = None
        self.selectionbox_projected_up = None
        self.selectionbox_projected_right = None
        self.selectionbox_projected_coords = None
        self.last_position_update = 0
        self.move_collision_plane = Plane(Vector3(0.0, 0.0, 0.0),
                                          Vector3(1.0, 0.0, 0.0),
                                          Vector3(0.0, 1.0, 0.0))

        self.paths = Paths()
        self.usercontrol = UserControl(self)

        # Initialize some models
        with open("resources/gizmo.obj", "r") as f:
            self.gizmo = Gizmo.from_obj(f, rotate=True)

        #self.generic_object = GenericObject()
        self.models = ObjectModels()
        self.grid = Grid(10000, 10000)

        self.modelviewmatrix = None
        self.projectionmatrix = None
Exemple #3
0
class BolMapViewer(QtWidgets.QOpenGLWidget):
    mouse_clicked = pyqtSignal(QMouseEvent)
    entity_clicked = pyqtSignal(QMouseEvent, str)
    mouse_dragged = pyqtSignal(QMouseEvent)
    mouse_released = pyqtSignal(QMouseEvent)
    mouse_wheel = pyqtSignal(QWheelEvent)
    position_update = pyqtSignal(QMouseEvent, tuple)
    height_update = pyqtSignal(float)
    select_update = pyqtSignal()
    move_points = pyqtSignal(float, float, float)
    connect_update = pyqtSignal(int, int)
    create_waypoint = pyqtSignal(float, float)
    create_waypoint_3d = pyqtSignal(float, float, float)

    rotate_current = pyqtSignal(Vector3)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._zoom_factor = 80
        self.setFocusPolicy(Qt.ClickFocus)

        self.SIZEX = 1024  #768#1024
        self.SIZEY = 1024  #768#1024

        self.canvas_width, self.canvas_height = self.width(), self.height()
        self.resize(600, self.canvas_height)
        #self.setMinimumSize(QSize(self.SIZEX, self.SIZEY))
        #self.setMaximumSize(QSize(self.SIZEX, self.SIZEY))
        self.setObjectName("bw_map_screen")

        self.origin_x = self.SIZEX // 2
        self.origin_z = self.SIZEY // 2

        self.offset_x = 0
        self.offset_z = 0

        self.left_button_down = False
        self.mid_button_down = False
        self.right_button_down = False
        self.drag_last_pos = None

        self.selected = []
        self.selected_positions = []
        self.selected_rotations = []

        #self.p = QPainter()
        #self.p2 = QPainter()
        # self.show_terrain_mode = SHOW_TERRAIN_REGULAR

        self.selectionbox_start = None
        self.selectionbox_end = None

        self.visualize_cursor = None

        self.click_mode = 0

        self.level_image = None

        self.collision = None

        self.highlighttriangle = None

        self.setMouseTracking(True)

        self.level_file: BOL = None
        self.waterboxes = []

        self.mousemode = MOUSE_MODE_NONE

        self.overlapping_wp_index = 0
        self.editorconfig = None
        self.visibility_menu = None

        #self.setContextMenuPolicy(Qt.CustomContextMenu)

        self.spawnpoint = None
        self.alternative_mesh = None
        self.highlight_colltype = None

        self.shift_is_pressed = False
        self.rotation_is_pressed = False
        self.last_drag_update = 0
        self.change_height_is_pressed = False
        self.last_mouse_move = None

        self.timer = QtCore.QTimer()
        self.timer.setInterval(2)
        self.timer.timeout.connect(self.render_loop)
        self.timer.start()
        self._lastrendertime = 0
        self._lasttime = 0

        self._frame_invalid = False

        self.MOVE_UP = 0
        self.MOVE_DOWN = 0
        self.MOVE_LEFT = 0
        self.MOVE_RIGHT = 0
        self.MOVE_FORWARD = 0
        self.MOVE_BACKWARD = 0
        self.SPEEDUP = 0

        self._wasdscrolling_speed = 1
        self._wasdscrolling_speedupfactor = 3

        self.main_model = None
        self.buffered_deltas = []

        # 3D Setup
        self.mode = MODE_TOPDOWN
        self.camera_horiz = pi * (1 / 2)
        self.camera_vertical = -pi * (1 / 4)
        self.camera_height = 1000
        self.last_move = None
        self.backgroundcolor = (255, 255, 255, 255)

        #self.selection_queue = []
        self.selectionqueue = SelectionQueue()

        self.selectionbox_projected_start = None
        self.selectionbox_projected_end = None

        #self.selectionbox_projected_2d = None
        self.selectionbox_projected_origin = None
        self.selectionbox_projected_up = None
        self.selectionbox_projected_right = None
        self.selectionbox_projected_coords = None
        self.last_position_update = 0
        self.move_collision_plane = Plane(Vector3(0.0, 0.0, 0.0),
                                          Vector3(1.0, 0.0, 0.0),
                                          Vector3(0.0, 1.0, 0.0))

        self.paths = Paths()
        self.usercontrol = UserControl(self)

        # Initialize some models
        with open("resources/gizmo.obj", "r") as f:
            self.gizmo = Gizmo.from_obj(f, rotate=True)

        #self.generic_object = GenericObject()
        self.models = ObjectModels()
        self.grid = Grid(100000, 100000, 10000)

        self.modelviewmatrix = None
        self.projectionmatrix = None

        self.arrow = None
        self.minimap = Minimap(Vector3(-1000.0, 0.0, -1000.0),
                               Vector3(1000.0, 0.0, 1000.0), 0, None)

    @catch_exception_with_dialog
    def initializeGL(self):
        self.rotation_visualizer = glGenLists(1)
        glNewList(self.rotation_visualizer, GL_COMPILE)
        glColor4f(0.0, 0.0, 1.0, 1.0)

        glBegin(GL_LINES)
        glVertex3f(0.0, 0.0, 0.0)
        glVertex3f(0.0, 40.0, 0.0)
        glEnd()
        glEndList()

        self.models.init_gl()
        self.arrow = Material(texturepath="resources/arrow.png")

        self.minimap = Minimap(Vector3(-1000.0, 0.0, -1000.0),
                               Vector3(1000.0, 0.0, 1000.0), 0,
                               "resources/arrow.png")

    def resizeGL(self, width, height):
        # Called upon window resizing: reinitialize the viewport.
        # update the window size
        self.canvas_width, self.canvas_height = width, height
        # paint within the whole window
        glEnable(GL_DEPTH_TEST)
        glViewport(0, 0, self.canvas_width, self.canvas_height)

    @catch_exception
    def set_editorconfig(self, config):
        self.editorconfig = config
        self._wasdscrolling_speed = config.getfloat("wasdscrolling_speed")
        self._wasdscrolling_speedupfactor = config.getfloat(
            "wasdscrolling_speedupfactor")
        backgroundcolor = config["3d_background"].split(" ")
        self.backgroundcolor = (int(backgroundcolor[0]) / 255.0,
                                int(backgroundcolor[1]) / 255.0,
                                int(backgroundcolor[2]) / 255.0, 1.0)

    def change_from_topdown_to_3d(self):
        if self.mode == MODE_3D:
            return
        else:
            self.mode = MODE_3D

            if self.mousemode == MOUSE_MODE_NONE:
                self.setContextMenuPolicy(Qt.DefaultContextMenu)

            # This is necessary so that the position of the 3d camera equals the middle of the topdown view
            self.offset_x *= -1
            self.do_redraw()

    def change_from_3d_to_topdown(self):
        if self.mode == MODE_TOPDOWN:
            return
        else:
            self.mode = MODE_TOPDOWN
            if self.mousemode == MOUSE_MODE_NONE:
                self.setContextMenuPolicy(Qt.CustomContextMenu)

            self.offset_x *= -1
            self.do_redraw()

    def logic(self, delta, diff):
        self.dolphin.logic(self, delta, diff)

    @catch_exception
    def render_loop(self):
        now = default_timer()

        diff = now - self._lastrendertime
        timedelta = now - self._lasttime

        if self.mode == MODE_TOPDOWN:
            self.handle_arrowkey_scroll(timedelta)
        else:
            self.handle_arrowkey_scroll_3d(timedelta)

        self.logic(timedelta, diff)

        if diff > 1 / 60.0:
            if self._frame_invalid:
                self.update()
                self._lastrendertime = now
                self._frame_invalid = False
        self._lasttime = now

    def handle_arrowkey_scroll(self, timedelta):
        if self.selectionbox_projected_coords is not None:
            return

        diff_x = diff_y = 0
        #print(self.MOVE_UP, self.MOVE_DOWN, self.MOVE_LEFT, self.MOVE_RIGHT)
        speedup = 1

        if self.shift_is_pressed:
            speedup = self._wasdscrolling_speedupfactor

        if self.MOVE_FORWARD == 1 and self.MOVE_BACKWARD == 1:
            diff_y = 0
        elif self.MOVE_FORWARD == 1:
            diff_y = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_BACKWARD == 1:
            diff_y = -1 * speedup * self._wasdscrolling_speed * timedelta

        if self.MOVE_LEFT == 1 and self.MOVE_RIGHT == 1:
            diff_x = 0
        elif self.MOVE_LEFT == 1:
            diff_x = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_RIGHT == 1:
            diff_x = -1 * speedup * self._wasdscrolling_speed * timedelta

        if diff_x != 0 or diff_y != 0:
            if self.zoom_factor > 1.0:
                self.offset_x += diff_x * (1.0 +
                                           (self.zoom_factor - 1.0) / 2.0)
                self.offset_z += diff_y * (1.0 +
                                           (self.zoom_factor - 1.0) / 2.0)
            else:
                self.offset_x += diff_x
                self.offset_z += diff_y
            # self.update()

            self.do_redraw()

    def handle_arrowkey_scroll_3d(self, timedelta):
        if self.selectionbox_projected_coords is not None:
            return

        diff_x = diff_y = diff_height = 0
        #print(self.MOVE_UP, self.MOVE_DOWN, self.MOVE_LEFT, self.MOVE_RIGHT)
        speedup = 1

        forward_vec = Vector3(cos(self.camera_horiz), sin(self.camera_horiz),
                              0)
        sideways_vec = Vector3(sin(self.camera_horiz), -cos(self.camera_horiz),
                               0)

        if self.shift_is_pressed:
            speedup = self._wasdscrolling_speedupfactor

        if self.MOVE_FORWARD == 1 and self.MOVE_BACKWARD == 1:
            forward_move = forward_vec * 0
        elif self.MOVE_FORWARD == 1:
            forward_move = forward_vec * (
                1 * speedup * self._wasdscrolling_speed * timedelta)
        elif self.MOVE_BACKWARD == 1:
            forward_move = forward_vec * (
                -1 * speedup * self._wasdscrolling_speed * timedelta)
        else:
            forward_move = forward_vec * 0

        if self.MOVE_LEFT == 1 and self.MOVE_RIGHT == 1:
            sideways_move = sideways_vec * 0
        elif self.MOVE_LEFT == 1:
            sideways_move = sideways_vec * (
                -1 * speedup * self._wasdscrolling_speed * timedelta)
        elif self.MOVE_RIGHT == 1:
            sideways_move = sideways_vec * (
                1 * speedup * self._wasdscrolling_speed * timedelta)
        else:
            sideways_move = sideways_vec * 0

        if self.MOVE_UP == 1 and self.MOVE_DOWN == 1:
            diff_height = 0
        elif self.MOVE_UP == 1:
            diff_height = 1 * speedup * self._wasdscrolling_speed * timedelta
        elif self.MOVE_DOWN == 1:
            diff_height = -1 * speedup * self._wasdscrolling_speed * timedelta

        if not forward_move.is_zero() or not sideways_move.is_zero(
        ) or diff_height != 0:
            #if self.zoom_factor > 1.0:
            #    self.offset_x += diff_x * (1.0 + (self.zoom_factor - 1.0) / 2.0)
            #    self.offset_z += diff_y * (1.0 + (self.zoom_factor - 1.0) / 2.0)
            #else:
            self.offset_x += (forward_move.x + sideways_move.x)
            self.offset_z += (forward_move.y + sideways_move.y)
            self.camera_height += diff_height
            # self.update()

            self.do_redraw()

    def set_arrowkey_movement(self, up, down, left, right):
        self.MOVE_UP = up
        self.MOVE_DOWN = down
        self.MOVE_LEFT = left
        self.MOVE_RIGHT = right

    def do_redraw(self, force=False):
        self._frame_invalid = True
        if force:
            self._lastrendertime = 0
            self.update()

    def reset(self, keep_collision=False):
        self.highlight_colltype = None
        self.overlapping_wp_index = 0
        self.shift_is_pressed = False
        self.SIZEX = 1024
        self.SIZEY = 1024
        self.origin_x = self.SIZEX // 2
        self.origin_z = self.SIZEY // 2
        self.last_drag_update = 0

        self.left_button_down = False
        self.mid_button_down = False
        self.right_button_down = False
        self.drag_last_pos = None

        self.selectionbox_start = None
        self.selectionbox_end = None

        self.selected = []

        if not keep_collision:
            # Potentially: Clear collision object too?
            self.level_image = None
            self.offset_x = 0
            self.offset_z = 0
            self._zoom_factor = 80

        self.pikmin_generators = None

        self.mousemode = MOUSE_MODE_NONE
        self.spawnpoint = None
        self.rotation_is_pressed = False

        self._frame_invalid = False

        self.MOVE_UP = 0
        self.MOVE_DOWN = 0
        self.MOVE_LEFT = 0
        self.MOVE_RIGHT = 0
        self.SPEEDUP = 0

    def set_collision(self, verts, faces, alternative_mesh):
        self.collision = Collision(verts, faces)

        if self.main_model is None:
            self.main_model = glGenLists(1)

        self.alternative_mesh = alternative_mesh

        glNewList(self.main_model, GL_COMPILE)
        #glBegin(GL_TRIANGLES)
        draw_collision(verts, faces)
        #glEnd()
        glEndList()

    def set_mouse_mode(self, mode):
        assert mode in (MOUSE_MODE_NONE, MOUSE_MODE_ADDWP,
                        MOUSE_MODE_CONNECTWP, MOUSE_MODE_MOVEWP)

        self.mousemode = mode

        if self.mousemode == MOUSE_MODE_NONE and self.mode == MODE_TOPDOWN:
            self.setContextMenuPolicy(Qt.CustomContextMenu)
        else:
            self.setContextMenuPolicy(Qt.DefaultContextMenu)

    @property
    def zoom_factor(self):
        return self._zoom_factor / 10.0

    def zoom(self, fac):
        if self._zoom_factor <= 60:
            mult = 20.0
        elif self._zoom_factor >= 600:
            mult = 100.0
        else:
            mult = 40.0

        if 10 < (self._zoom_factor + fac * mult) <= 1500:
            self._zoom_factor += int(fac * mult)
            #self.update()
            self.do_redraw()

    def mouse_coord_to_world_coord(self, mouse_x, mouse_y):
        zf = self.zoom_factor
        width, height = self.canvas_width, self.canvas_height
        camera_width = width * zf
        camera_height = height * zf

        topleft_x = -camera_width / 2 - self.offset_x
        topleft_y = camera_height / 2 + self.offset_z

        relx = mouse_x / width
        rely = mouse_y / height
        res = (topleft_x + relx * camera_width,
               topleft_y - rely * camera_height)

        return res

    def mouse_coord_to_world_coord_transform(self, mouse_x, mouse_y):
        mat4x4 = Matrix4x4.from_opengl_matrix(
            *glGetFloatv(GL_PROJECTION_MATRIX))
        width, height = self.canvas_width, self.canvas_height
        result = mat4x4.multiply_vec4(mouse_x - width / 2,
                                      mouse_y - height / 2, 0, 1)

        return result

    #@catch_exception_with_dialog
    #@catch_exception
    def paintGL(self):
        start = default_timer()
        offset_x = self.offset_x
        offset_z = self.offset_z

        #start = default_timer()
        glClearColor(1.0, 1.0, 1.0, 0.0)
        #glClearColor(*self.backgroundcolor)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        width, height = self.canvas_width, self.canvas_height

        if self.mode == MODE_TOPDOWN:
            glMatrixMode(GL_PROJECTION)
            glLoadIdentity()
            zf = self.zoom_factor
            #glOrtho(-6000.0, 6000.0, -6000.0, 6000.0, -3000.0, 2000.0)
            camera_width = width * zf
            camera_height = height * zf

            glOrtho(-camera_width / 2 - offset_x, camera_width / 2 - offset_x,
                    -camera_height / 2 + offset_z,
                    camera_height / 2 + offset_z, -120000.0, 80000.0)

            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()
        else:
            #glEnable(GL_CULL_FACE)
            # set yellow color for subsequent drawing rendering calls

            glMatrixMode(GL_PROJECTION)
            glLoadIdentity()
            gluPerspective(75, width / height, 256.0, 160000.0)

            glMatrixMode(GL_MODELVIEW)
            glLoadIdentity()

            look_direction = Vector3(cos(self.camera_horiz),
                                     sin(self.camera_horiz),
                                     sin(self.camera_vertical))
            # look_direction.unify()
            fac = 1.01 - abs(look_direction.z)
            # print(fac, look_direction.z, look_direction)

            gluLookAt(self.offset_x, self.offset_z, self.camera_height,
                      self.offset_x + look_direction.x * fac,
                      self.offset_z + look_direction.y * fac,
                      self.camera_height + look_direction.z, 0, 0, 1)

            self.camera_direction = Vector3(look_direction.x * fac,
                                            look_direction.y * fac,
                                            look_direction.z)

            #print(self.camera_direction)

        self.modelviewmatrix = numpy.transpose(
            numpy.reshape(glGetFloatv(GL_MODELVIEW_MATRIX), (4, 4)))
        self.projectionmatrix = numpy.transpose(
            numpy.reshape(glGetFloatv(GL_PROJECTION_MATRIX), (4, 4)))
        self.mvp_mat = numpy.dot(self.projectionmatrix, self.modelviewmatrix)
        self.modelviewmatrix_inv = numpy.linalg.inv(self.modelviewmatrix)

        campos = Vector3(self.offset_x, self.camera_height, -self.offset_z)
        self.campos = campos

        if self.mode == MODE_TOPDOWN:
            gizmo_scale = 3 * zf
        else:
            gizmo_scale = (self.gizmo.position - campos).norm() / 130.0

        self.gizmo_scale = gizmo_scale

        #print(self.gizmo.position, campos)
        vismenu: FilterViewMenu = self.visibility_menu
        while len(self.selectionqueue) > 0:
            glClearColor(1.0, 1.0, 1.0, 1.0)
            #
            click_x, click_y, clickwidth, clickheight, shiftpressed, do_gizmo = self.selectionqueue.queue_pop(
            )
            click_y = height - click_y
            hit = 0xFF

            #print("received request", do_gizmo)

            if clickwidth == 1 and clickheight == 1:
                self.gizmo.render_collision_check(gizmo_scale,
                                                  is3d=self.mode == MODE_3D)
                pixels = glReadPixels(click_x, click_y, clickwidth,
                                      clickheight, GL_RGB, GL_UNSIGNED_BYTE)
                #print(pixels)
                hit = pixels[2]
                if do_gizmo and hit != 0xFF:
                    self.gizmo.run_callback(hit)
                    self.gizmo.was_hit_at_all = True
                #if hit != 0xFF and do_:

            glClearColor(1.0, 1.0, 1.0, 1.0)

            if self.level_file is not None and hit == 0xFF and not do_gizmo:
                #objects = self.pikmin_generators.generators
                glDisable(GL_TEXTURE_2D)
                #for i, pikminobject in enumerate(objects):
                #    self.models.render_object_coloredid(pikminobject, i)

                id = 0x100000

                objlist = []
                offset = 0
                if self.minimap is not None and vismenu.minimap.is_selectable(
                ) and self.minimap.is_available():
                    objlist.append((self.minimap, self.minimap.corner1,
                                    self.minimap.corner2, None))
                    self.models.render_generic_position_colored_id(
                        self.minimap.corner1, id + (offset) * 4)
                    self.models.render_generic_position_colored_id(
                        self.minimap.corner2, id + (offset) * 4 + 1)
                    offset = 1
                """
                for ptr, pos in self.karts:
                    objlist.append((ptr, pos, None, None))
                    self.models.render_generic_position_colored_id(pos, id + (offset) * 4)
                    offset += 1"""

                self.dolphin.render_collision(self, objlist)
                offset = len(objlist)

                if vismenu.enemyroute.is_selectable():
                    for i, obj in enumerate(
                            self.level_file.enemypointgroups.points()):
                        objlist.append((obj, obj.position, None, None))
                        self.models.render_generic_position_colored_id(
                            obj.position, id + (offset + i) * 4)

                offset = len(objlist)

                if vismenu.itemroutes.is_selectable():
                    i = 0
                    for route in self.level_file.routes:
                        for obj in route.points:
                            objlist.append((obj, obj.position, None, None))
                            self.models.render_generic_position_colored_id(
                                obj.position, id + (offset + i) * 4)
                            i += 1

                offset = len(objlist)

                if vismenu.checkpoints.is_selectable():
                    for i, obj in enumerate(
                            self.level_file.objects_with_2positions()):
                        objlist.append((obj, obj.start, obj.end, None))
                        self.models.render_generic_position_colored_id(
                            obj.start, id + (offset + i) * 4)
                        self.models.render_generic_position_colored_id(
                            obj.end, id + (offset + i) * 4 + 1)

                for is_selectable, collection in (
                    (vismenu.objects.is_selectable(),
                     self.level_file.objects.objects),
                    (vismenu.kartstartpoints.is_selectable(),
                     self.level_file.kartpoints.positions),
                    (vismenu.areas.is_selectable(),
                     self.level_file.areas.areas),
                    (vismenu.cameras.is_selectable(), self.level_file.cameras),
                    (vismenu.respawnpoints.is_selectable(),
                     self.level_file.respawnpoints)):
                    offset = len(objlist)
                    if not is_selectable:
                        continue

                    for i, obj in enumerate(collection):
                        objlist.append((obj, obj.position, None, obj.rotation))
                        self.models.render_generic_position_rotation_colored_id(
                            obj.position, obj.rotation,
                            id + (offset + i) * 4 + 2)

                assert len(objlist) * 4 < id
                print("We queued up", len(objlist))
                pixels = glReadPixels(click_x, click_y, clickwidth,
                                      clickheight, GL_RGB, GL_UNSIGNED_BYTE)
                #print(pixels, click_x, click_y, clickwidth, clickheight)
                selected = {}
                selected_positions = []
                selected_rotations = []
                #for i in range(0, clickwidth*clickheight, 4):
                start = default_timer()

                for i in range(0, clickwidth * clickheight, 13):
                    # | (pixels[i*3+0] << 16)
                    if pixels[i * 3] != 0xFF:
                        upper = pixels[i * 3] & 0x0F
                        index = (upper << 16) | (
                            pixels[i * 3 + 1] << 8) | pixels[i * 3 + 2]
                        if index & 0b1:
                            # second position
                            entry = objlist[index // 4]
                            if entry[0] not in selected:
                                selected[entry[0]] = 2

                                selected_positions.append(entry[2])
                            elif selected[entry[0]] == 1:
                                selected[entry[0]] = 3
                                selected_positions.append(entry[2])
                        else:
                            entry = objlist[index // 4]
                            if entry[0] not in selected:
                                selected[entry[0]] = 1

                                selected_positions.append(entry[1])

                                if index & 0b10:
                                    print("found a rotation")
                                    selected_rotations.append(entry[3])

                            elif selected[entry[0]] == 2:
                                selected[entry[0]] = 3
                                selected_positions.append(entry[1])

                #print("select time taken", default_timer() - start)
                #print("result:", selected)
                selected = [x for x in selected.keys()]
                if not shiftpressed:
                    self.selected = selected
                    self.selected_positions = selected_positions
                    self.selected_rotations = selected_rotations
                    self.select_update.emit()

                else:
                    for obj in selected:
                        if obj not in self.selected:
                            self.selected.append(obj)
                    for pos in selected_positions:
                        if pos not in self.selected_positions:
                            self.selected_positions.append(pos)

                    for rot in selected_rotations:
                        if rot not in self.selected_rotations:
                            self.selected_rotations.append(rot)

                    self.select_update.emit()

                self.gizmo.move_to_average(self.selected_positions)
                if len(selected) == 0:
                    #print("Select did register")
                    self.gizmo.hidden = True
                if self.mode == MODE_3D:  # In case of 3D mode we need to update scale due to changed gizmo position
                    gizmo_scale = (self.gizmo.position - campos).norm() / 130.0
                #print("total time taken", default_timer() - start)
        #print("gizmo status", self.gizmo.was_hit_at_all)
        #glClearColor(1.0, 1.0, 1.0, 0.0)
        glClearColor(*self.backgroundcolor)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glEnable(GL_DEPTH_TEST)
        glDisable(GL_TEXTURE_2D)
        glColor4f(1.0, 1.0, 1.0, 1.0)
        if self.main_model is not None:
            if self.alternative_mesh is None:
                glCallList(self.main_model)
            else:
                glPushMatrix()
                glScalef(1.0, -1.0, 1.0)
                self.alternative_mesh.render(
                    selectedPart=self.highlight_colltype)
                glPopMatrix()

        glDisable(GL_TEXTURE_2D)
        glColor4f(1.0, 1.0, 1.0, 1.0)
        self.grid.render()
        if self.mode == MODE_TOPDOWN:
            glClear(GL_DEPTH_BUFFER_BIT)

            if self.minimap is not None and vismenu.minimap.is_visible(
            ) and self.minimap.is_available():
                self.minimap.render()
                glClear(GL_DEPTH_BUFFER_BIT)
        #else:
        #    if self.minimap is not None and vismenu.minimap.is_visible():
        #        self.minimap.render()
        #    glDisable(GL_DEPTH_TEST)

        glEnable(GL_ALPHA_TEST)
        glAlphaFunc(GL_GEQUAL, 0.5)
        p = 0

        self.dolphin.render_visual(self, self.selected)
        """for valid, kartpos in self.karts:
            if valid:
                self.models.render_player_position_colored(kartpos, valid in self.selected, p)
            p += 1"""

        if self.level_file is not None:
            selected = self.selected
            positions = self.selected_positions

            select_optimize = {x: True for x in selected}
            #objects = self.pikmin_generators.generators

            #for pikminobject in objects:
            #    self.models.render_object(pikminobject, pikminobject in selected)

            vismenu = self.visibility_menu
            if vismenu.itemroutes.is_visible():
                for route in self.level_file.routes:
                    for point in route.points:
                        self.models.render_generic_position_colored(
                            point.position, point in select_optimize,
                            "itempoint")

                    glBegin(GL_LINE_STRIP)
                    glColor3f(0.0, 0.0, 0.0)
                    for point in route.points:
                        pos = point.position
                        glVertex3f(pos.x, -pos.z, pos.y)
                    glEnd()

            if vismenu.enemyroute.is_visible():
                for group in self.level_file.enemypointgroups.groups:
                    for point in group.points:
                        if point in select_optimize:
                            glColor3f(0.3, 0.3, 0.3)
                            self.models.draw_sphere(point.position,
                                                    point.scale)
                        self.models.render_generic_position_colored(
                            point.position, point in select_optimize,
                            "enemypoint")

                    glBegin(GL_LINE_STRIP)
                    glColor3f(0.0, 0.0, 0.0)
                    for point in group.points:
                        pos = point.position
                        glVertex3f(pos.x, -pos.z, pos.y)
                    glEnd()

                groups = self.level_file.enemypointgroups.groups
                links = {}
                for group in groups:
                    for point in group.points:
                        if point.link != -1:

                            if point.link not in links:
                                links[point.link] = [point.position]
                            else:
                                links[point.link].append(point.position)
                """
                            and point.link in groups and len(groups[point.link].points) > 0:
                            if point != groups[point.link].points[0]:
                                pos1 = point.position
                                pos2 = groups[point.link].points[0].position
                                glVertex3f(pos1.x, -pos1.z, pos1.y)
                                glVertex3f(pos2.x, -pos2.z, pos2.y)"""

                glColor3f(0.0, 0.0, 1.0)
                for link, points in links.items():
                    glBegin(GL_LINE_LOOP)
                    for point in points:
                        glVertex3f(point.x, -point.z, point.y)
                    glEnd()

            if vismenu.checkpoints.is_visible():
                for i, group in enumerate(self.level_file.checkpoints.groups):

                    prev = None
                    for checkpoint in group.points:
                        self.models.render_generic_position_colored(
                            checkpoint.start, checkpoint.start in positions,
                            "checkpointleft")
                        self.models.render_generic_position_colored(
                            checkpoint.end, checkpoint.end in positions,
                            "checkpointright")

                    glColor3f(*colors[i % 4])

                    glBegin(GL_LINES)
                    for checkpoint in group.points:
                        pos1 = checkpoint.start
                        pos2 = checkpoint.end

                        #self.models.render_generic_position(pos1, False)
                        #self.models.render_generic_position(pos2, False)

                        glVertex3f(pos1.x, -pos1.z, pos1.y)
                        glVertex3f(pos2.x, -pos2.z, pos2.y)
                        #glColor3f(0.0, 0.0, 0.0)

                        if prev is not None:
                            pos3 = prev.start
                            pos4 = prev.end

                            glVertex3f(pos1.x, -pos1.z, pos1.y)
                            glVertex3f(pos3.x, -pos3.z, pos3.y)
                            glVertex3f(pos2.x, -pos2.z, pos2.y)
                            glVertex3f(pos4.x, -pos4.z, pos4.y)

                        prev = checkpoint

                    glEnd()

            #glColor3f(1.0, 1.0, 1.0)
            #glEnable(GL_TEXTURE_2D)
            #glBindTexture(GL_TEXTURE_2D, self.arrow.tex)
            glPushMatrix()
            #lines = []
            if vismenu.checkpoints.is_visible():
                for group in self.level_file.checkpoints.groups:
                    prev = None
                    for checkpoint in group.points:
                        if prev is None:
                            prev = checkpoint
                        else:
                            #mid1 = prev.mid
                            #mid2 = checkpoint.mid
                            mid1 = (prev.start + prev.end) / 2.0
                            mid2 = (checkpoint.start + checkpoint.end) / 2.0

                            self.models.draw_arrow_head(mid1, mid2)
                            #lines.append((mid1, mid2))
                            prev = checkpoint
            glPopMatrix()
            glBegin(GL_LINES)
            """for linestart, lineend in lines:
                glVertex3f(linestart.x, -linestart.z, linestart.y)
                glVertex3f(lineend.x, -lineend.z, lineend.y)"""
            if vismenu.checkpoints.is_visible():
                for group in self.level_file.checkpoints.groups:
                    prev = None
                    for checkpoint in group.points:
                        if prev is None:
                            prev = checkpoint
                        else:
                            mid1 = (prev.start + prev.end) / 2.0
                            mid2 = (checkpoint.start + checkpoint.end) / 2.0
                            #mid1 = prev.mid
                            #mid2 = checkpoint.mid
                            glVertex3f(mid1.x, -mid1.z, mid1.y)
                            glVertex3f(mid2.x, -mid2.z, mid2.y)
                            prev = checkpoint
            glEnd()

            if vismenu.objects.is_visible():
                for object in self.level_file.objects.objects:
                    self.models.render_generic_position_rotation_colored(
                        "objects", object.position, object.rotation, object
                        in select_optimize)
            if vismenu.kartstartpoints.is_visible():
                for object in self.level_file.kartpoints.positions:
                    self.models.render_generic_position_rotation_colored(
                        "startpoints", object.position, object.rotation, object
                        in select_optimize)
            if vismenu.areas.is_visible():
                for object in self.level_file.areas.areas:
                    self.models.render_generic_position_rotation_colored(
                        "areas", object.position, object.rotation, object
                        in select_optimize)
                    if object in select_optimize:
                        glColor4f(*colors_selection)
                    else:
                        glColor4f(*colors_area)

                    self.models.draw_wireframe_cube(object.position,
                                                    object.rotation,
                                                    object.scale * 100)
            if vismenu.cameras.is_visible():
                for object in self.level_file.cameras:
                    self.models.render_generic_position_rotation_colored(
                        "camera", object.position, object.rotation, object
                        in select_optimize)

            if vismenu.respawnpoints.is_visible():
                for object in self.level_file.respawnpoints:
                    self.models.render_generic_position_rotation_colored(
                        "respawn", object.position, object.rotation, object
                        in select_optimize)
            if self.minimap is not None and self.minimap.is_available(
            ) and vismenu.minimap.is_visible():
                self.models.render_generic_position(
                    self.minimap.corner1, self.minimap.corner1 in positions)
                self.models.render_generic_position(
                    self.minimap.corner2, self.minimap.corner2 in positions)
            #glDisable(GL_TEXTURE_2D)

        glColor3f(0.0, 0.0, 0.0)
        glDisable(GL_TEXTURE_2D)
        glColor4f(0.0, 1.0, 0.0, 1.0)
        rendered = {}
        for p1i, p2i in self.paths.unique_paths:
            p1 = self.paths.waypoints[p1i]
            p2 = self.paths.waypoints[p2i]

            glBegin(GL_LINES)
            glVertex3f(p1.position.x, -p1.position.z, p1.position.y + 5)
            glVertex3f(p2.position.x, -p2.position.z, p2.position.y + 5)
            glEnd()

            if p1i not in rendered:
                self.models.draw_sphere(p1.position, p1.radius / 2)
                rendered[p1i] = True
            if p2i not in rendered:
                self.models.draw_sphere(p2.position, p2.radius / 2)
                rendered[p2i] = True
        glColor4f(0.0, 1.0, 1.0, 1.0)
        """for points in self.paths.wide_paths:
            glBegin(GL_LINE_LOOP)
            for p in points:
                glVertex3f(p.x, -p.z, p.y + 5)

            glEnd()"""

        self.gizmo.render_scaled(gizmo_scale, is3d=self.mode == MODE_3D)
        glDisable(GL_DEPTH_TEST)
        if self.selectionbox_start is not None and self.selectionbox_end is not None:
            #print("drawing box")
            startx, startz = self.selectionbox_start
            endx, endz = self.selectionbox_end
            glColor4f(1.0, 0.0, 0.0, 1.0)
            glLineWidth(2.0)
            glBegin(GL_LINE_LOOP)
            glVertex3f(startx, startz, 0)
            glVertex3f(startx, endz, 0)
            glVertex3f(endx, endz, 0)
            glVertex3f(endx, startz, 0)

            glEnd()

        if self.selectionbox_projected_origin is not None and self.selectionbox_projected_coords is not None:
            #print("drawing box")
            origin = self.selectionbox_projected_origin
            point2, point3, point4 = self.selectionbox_projected_coords
            glColor4f(1.0, 0.0, 0.0, 1.0)
            glLineWidth(2.0)

            point1 = origin

            glBegin(GL_LINE_LOOP)
            glVertex3f(point1.x, point1.y, point1.z)
            glVertex3f(point2.x, point2.y, point2.z)
            glVertex3f(point3.x, point3.y, point3.z)
            glVertex3f(point4.x, point4.y, point4.z)
            glEnd()

        glEnable(GL_DEPTH_TEST)
        glFinish()
        now = default_timer() - start
        #print("Frame time:", now, 1/now, "fps")

    @catch_exception
    def mousePressEvent(self, event):
        self.usercontrol.handle_press(event)

    @catch_exception
    def mouseMoveEvent(self, event):
        self.usercontrol.handle_move(event)

    @catch_exception
    def mouseReleaseEvent(self, event):
        self.usercontrol.handle_release(event)

    def wheelEvent(self, event):
        wheel_delta = event.angleDelta().y()

        if self.editorconfig is not None:
            invert = self.editorconfig.getboolean("invertzoom")
            if invert:
                wheel_delta = -1 * wheel_delta

        if wheel_delta < 0:
            self.zoom_out()

        elif wheel_delta > 0:
            self.zoom_in()

    def zoom_in(self):
        current = self.zoom_factor

        fac = calc_zoom_out_factor(current)

        self.zoom(fac)

    def zoom_out(self):
        current = self.zoom_factor
        fac = calc_zoom_in_factor(current)

        self.zoom(fac)

    def create_ray_from_mouseclick(self, mousex, mousey, yisup=False):
        self.camera_direction.normalize()
        height = self.canvas_height
        width = self.canvas_width

        view = self.camera_direction.copy()

        h = view.cross(Vector3(0, 0, 1))
        v = h.cross(view)

        h.normalize()
        v.normalize()

        rad = 75 * pi / 180.0
        vLength = tan(rad / 2) * 1.0
        hLength = vLength * (width / height)

        v *= vLength
        h *= hLength

        x = mousex - width / 2
        y = height - mousey - height / 2

        x /= (width / 2)
        y /= (height / 2)
        camerapos = Vector3(self.offset_x, self.offset_z, self.camera_height)

        pos = camerapos + view * 1.0 + h * x + v * y
        dir = pos - camerapos

        if yisup:
            tmp = pos.y
            pos.y = -pos.z
            pos.z = tmp

            tmp = dir.y
            dir.y = -dir.z
            dir.z = tmp

        return Line(pos, dir)