Beispiel #1
0
    def cursor_snap(self, context, event):
        if self.tree is None or context.scene.sprytile_ui.use_mouse is True:
            return

        # get the context arguments
        scene = context.scene
        region = context.region
        rv3d = context.region_data
        coord = event.mouse_region_x, event.mouse_region_y

        # get the ray from the viewport and mouse
        ray_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
        ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            scene)

        if event.type in self.is_keyboard_list and event.shift and event.value == 'PRESS':
            if scene.sprytile_data.cursor_snap == 'GRID':
                scene.sprytile_data.cursor_snap = 'VERTEX'
            else:
                scene.sprytile_data.cursor_snap = 'GRID'

        # Snap cursor, depending on setting
        if scene.sprytile_data.cursor_snap == 'GRID':
            location = intersect_line_plane(ray_origin,
                                            ray_origin + ray_vector,
                                            scene.cursor_location,
                                            plane_normal)
            if location is None:
                return
            world_pixels = scene.sprytile_data.world_pixels
            target_grid = sprytile_utils.get_grid(
                context, context.object.sprytile_gridid)
            grid_x = target_grid.grid[0]
            grid_y = target_grid.grid[1]

            grid_position, x_vector, y_vector = sprytile_utils.get_grid_pos(
                location, scene.cursor_location, right_vector.copy(),
                up_vector.copy(), world_pixels, grid_x, grid_y)
            scene.cursor_location = grid_position

        elif scene.sprytile_data.cursor_snap == 'VERTEX':
            location, normal, face_index, distance = self.raycast_object(
                context.object, ray_origin, ray_vector)
            if location is None:
                return
            # Location in world space, convert to object space
            matrix = context.object.matrix_world.copy()
            matrix_inv = matrix.inverted()
            location, normal, face_index, dist = self.tree.find_nearest(
                matrix_inv * location)
            if location is None:
                return

            # Found the nearest face, go to BMesh to find the nearest vertex
            if self.bmesh is None:
                self.refresh_mesh = True
                return
            if face_index >= len(self.bmesh.faces) or face_index < 0:
                return
            face = self.bmesh.faces[face_index]
            closest_vtx = -1
            closest_dist = float('inf')
            # positions are in object space
            for vtx_idx, vertex in enumerate(face.verts):
                test_dist = (location - vertex.co).magnitude
                if test_dist < closest_dist:
                    closest_vtx = vtx_idx
                    closest_dist = test_dist
            # convert back to world space
            if closest_vtx != -1:
                scene.cursor_location = matrix * face.verts[closest_vtx].co
Beispiel #2
0
    def cursor_snap(self, context, event):
        if self.tree is None or context.scene.sprytile_ui.use_mouse is True:
            return

        # get the context arguments
        scene = context.scene
        region = context.region
        rv3d = context.region_data
        coord = event.mouse_region_x, event.mouse_region_y

        # get the ray from the viewport and mouse
        ray_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
        ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            scene)

        if event.type in self.is_keyboard_list and event.shift and event.value == 'PRESS':
            if scene.sprytile_data.cursor_snap == 'GRID':
                scene.sprytile_data.cursor_snap = 'VERTEX'
            else:
                scene.sprytile_data.cursor_snap = 'GRID'

        # Snap cursor, depending on setting
        if scene.sprytile_data.cursor_snap == 'GRID':
            location = intersect_line_plane(ray_origin,
                                            ray_origin + ray_vector,
                                            scene.cursor_location,
                                            plane_normal)
            if location is None:
                return
            world_pixels = scene.sprytile_data.world_pixels
            target_grid = sprytile_utils.get_grid(
                context, context.object.sprytile_gridid)
            grid_x = target_grid.grid[0]
            grid_y = target_grid.grid[1]

            grid_position, x_vector, y_vector = sprytile_utils.get_grid_pos(
                location, scene.cursor_location, right_vector.copy(),
                up_vector.copy(), world_pixels, grid_x, grid_y)
            scene.cursor_location = grid_position

        elif scene.sprytile_data.cursor_snap == 'VERTEX':
            # Get if user is holding down tile picker modifier
            check_modifier = False
            addon_prefs = context.user_preferences.addons[
                __package__].preferences
            if addon_prefs.tile_picker_key == 'Alt':
                check_modifier = event.alt
            if addon_prefs.tile_picker_key == 'Ctrl':
                check_modifier = event.ctrl
            if addon_prefs.tile_picker_key == 'Shift':
                check_modifier = event.shift

            location, normal, face_index, distance = self.raycast_object(
                context.object, ray_origin, ray_vector)
            if location is None:
                if check_modifier:
                    scene.sprytile_data.lock_normal = False
                return
            # Location in world space, convert to object space
            matrix = context.object.matrix_world.copy()
            matrix_inv = matrix.inverted()
            location, normal, face_index, dist = self.tree.find_nearest(
                matrix_inv * location)
            if location is None:
                return

            # Found the nearest face, go to BMesh to find the nearest vertex
            if self.bmesh is None:
                self.refresh_mesh = True
                return
            if face_index >= len(self.bmesh.faces) or face_index < 0:
                return
            face = self.bmesh.faces[face_index]
            closest_vtx = -1
            closest_dist = float('inf')
            # positions are in object space
            for vtx_idx, vertex in enumerate(face.verts):
                test_dist = (location - vertex.co).magnitude
                if test_dist < closest_dist:
                    closest_vtx = vtx_idx
                    closest_dist = test_dist
            # convert back to world space
            if closest_vtx != -1:
                scene.cursor_location = matrix * face.verts[closest_vtx].co

            # If find face tile button pressed, set work plane normal too
            if check_modifier:
                sprytile_data = context.scene.sprytile_data
                # Check if mouse is hitting object
                target_normal = context.object.matrix_world.to_quaternion(
                ) * normal
                face_up_vector, face_right_vector = self.get_face_up_vector(
                    context, face_index, 0.4)
                if face_up_vector is not None:
                    sprytile_data.paint_normal_vector = target_normal
                    sprytile_data.paint_up_vector = face_up_vector
                    sprytile_data.lock_normal = True
Beispiel #3
0
    def execute_fill(self, context, scene, ray_origin, ray_vector):
        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(scene, with_rotation=False)

        # Intersect on the virtual plane
        plane_hit = intersect_line_plane(ray_origin, ray_origin + ray_vector, scene.cursor.location, plane_normal)
        # Didn't hit the plane exit
        if plane_hit is None:
            return
        grid = sprytile_utils.get_grid(context, context.object.sprytile_gridid)
        sprytile_data = scene.sprytile_data

        world_pixels = sprytile_data.world_pixels
        grid_x = grid.grid[0]
        grid_y = grid.grid[1]

        # Find the position of the plane hit, in terms of grid coordinates
        hit_coord, grid_right, grid_up = sprytile_utils.get_grid_pos(
            plane_hit, scene.cursor.location,
            right_vector.copy(), up_vector.copy(),
            world_pixels, grid_x, grid_y, as_coord=True
        )

        # Check hit_coord is inside the work plane grid
        plane_size = sprytile_data.fill_plane_size

        grid_min, grid_max = sprytile_utils.get_workplane_area(plane_size[0], plane_size[1])

        x_offset = 1
        if plane_size[0] % 2 == 1:
            grid_min[0] += x_offset
            grid_max[0] += x_offset

        if hit_coord.x < grid_min[0] or hit_coord.x >= grid_max[0]:
            return
        if hit_coord.y < grid_min[1] or hit_coord.y >= grid_max[1]:
            return

        # Build the fill map
        sel_coords, sel_size, sel_ids = sprytile_utils.get_grid_selection_ids(context, grid)
        fill_map, face_idx_array = self.build_fill_map(context, grid_up, grid_right, plane_normal,
                                                       plane_size, grid_min, grid_max, sel_ids)

        # Convert from grid coordinate to map coordinate
        hit_array_coord = [int(hit_coord.x) - grid_min[0],
                           int(hit_coord.y) - grid_min[1]]

        # For getting paint settings later
        paint_setting_layer = self.modal.bmesh.faces.layers.int.get(UvDataLayers.PAINT_SETTINGS)

        # Get vectors again, to apply tile rotations in UV stage
        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(scene)

        # Get the content in hit coordinate
        hit_coord_content = int(fill_map[hit_array_coord[1]][hit_array_coord[0]])
        # Get the coordinates that would be flood filled
        fill_coords = self.flood_fill(fill_map, hit_array_coord, -2, hit_coord_content)

        # If lock transform on, cache the paint settings before doing any operations
        paint_setting_cache = None
        if sprytile_data.fill_lock_transform and paint_setting_layer is not None:
            paint_setting_cache = [len(fill_coords)]
            for idx, cell_coord in fill_coords:
                face_index = face_idx_array[cell_coord[1]][cell_coord[0]]
                if face_index > -1:
                    face = self.modal.faces[face_index]
                    paint_setting_cache[idx] = face[paint_setting_layer]

        # Get the work layer filter, based on layer settings
        work_layer_mask = sprytile_utils.get_work_layer_data(sprytile_data)
        require_base_layer = sprytile_data.work_layer != 'BASE'

        origin_xy = (grid.tile_selection[0], grid.tile_selection[1])
        data = scene.sprytile_data
        # Loop through list of coords to be filled
        for idx, cell_coord in enumerate(fill_coords):
            # Fetch the paint settings from cache
            if paint_setting_cache is not None:
                paint_setting = paint_setting_cache[idx]
                sprytile_utils.from_paint_settings(data, paint_setting)

            # Convert map coord to grid coord
            grid_coord = [grid_min[0] + cell_coord[0],
                          grid_min[1] + cell_coord[1]]

            sub_x = (grid_coord[0] - int(hit_coord.x)) % sel_size[0]
            sub_y = (grid_coord[1] - int(hit_coord.y)) % sel_size[1]
            sub_xy = sel_coords[(sub_y * sel_size[0]) + sub_x]
            self.modal.construct_face(context, grid_coord, [1,1],
                                      sub_xy, origin_xy,
                                      grid_up, grid_right,
                                      up_vector, right_vector,
                                      plane_normal,
                                      require_base_layer=require_base_layer,
                                      work_layer_mask=work_layer_mask)
Beispiel #4
0
    def execute_fill(self, context, scene, ray_origin, ray_vector):
        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            scene, with_rotation=False)

        # Intersect on the virtual plane
        plane_hit = intersect_line_plane(ray_origin, ray_origin + ray_vector,
                                         scene.cursor_location, plane_normal)
        # Didn't hit the plane exit
        if plane_hit is None:
            return
        grid = sprytile_utils.get_grid(context, context.object.sprytile_gridid)
        sprytile_data = scene.sprytile_data

        world_pixels = sprytile_data.world_pixels
        grid_x = grid.grid[0]
        grid_y = grid.grid[1]

        # Find the position of the plane hit, in terms of grid coordinates
        hit_coord, grid_right, grid_up = sprytile_utils.get_grid_pos(
            plane_hit,
            scene.cursor_location,
            right_vector.copy(),
            up_vector.copy(),
            world_pixels,
            grid_x,
            grid_y,
            as_coord=True)

        # Check hit_coord is inside the work plane grid
        plane_size = sprytile_data.axis_plane_size
        if hit_coord.x < -plane_size[0] or hit_coord.x >= plane_size[0]:
            return
        if hit_coord.y < -plane_size[1] or hit_coord.y >= plane_size[1]:
            return

        # Build the fill map
        fill_map, face_idx_array = self.build_fill_map(context, grid_up,
                                                       grid_right,
                                                       plane_normal,
                                                       plane_size)

        # Convert from grid coordinate to map coordinate
        hit_array_coord = [
            int(hit_coord.x) + plane_size[0],
            int((plane_size[1] * 2) - 1 - (hit_coord.y + plane_size[1]))
        ]

        # Calculate the tile index of currently selected tile
        tile_xy = (grid.tile_selection[0], grid.tile_selection[1])
        # For getting paint settings later
        paint_setting_layer = self.modal.bmesh.faces.layers.int.get(
            'paint_settings')

        # Pre calculate for auto merge
        shift_vec = plane_normal.normalized() * 0.01
        threshold = (1 / context.scene.sprytile_data.world_pixels) * 2

        # Get vectors again, to apply tile rotations in UV stage
        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            scene)

        # Flood fill targets map cell coordinates
        hit_coord_content = int(
            fill_map[hit_array_coord[1]][hit_array_coord[0]])
        fill_coords = self.flood_fill(fill_map, hit_array_coord, -1,
                                      hit_coord_content)
        for cell_coord in fill_coords:
            self.construct_fill(context, scene, sprytile_data, cell_coord,
                                plane_size, face_idx_array,
                                paint_setting_layer, tile_xy, ray_vector,
                                shift_vec, threshold, up_vector, right_vector,
                                plane_normal, grid_up, grid_right)