def __init__(self, model: OBJ, controller):
        self._model = model  # type: OBJ
        self._controller = controller  # type: Controller

        # init pattern data
        self._split_factor = 0.2  # type: float
        self.MAX_SEGMENTS = -1  # type: int
        self._pattern_offsets = None  # type: np.array
        self._pattern_indexes = None  # type: np.array
        self._pattern_parameters = None  # type: np.array
        self._need_recompute = True  # type: bool
        self._need_update_split_factor = True  # type: bool
        self._splited_triangle_number = -1  # type: int
        self.init_pattern_data()

        # declare buffer
        self._original_vertex_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 0, None, GL_DYNAMIC_DRAW)
        self._original_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 1, None, GL_DYNAMIC_DRAW)
        self._original_tex_coord_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 22, None, GL_DYNAMIC_DRAW)
        if self._model.from_bezier:
            self._original_uv_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 24, None, GL_DYNAMIC_DRAW)
        self._original_index_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 2, None, GL_DYNAMIC_DRAW)
        self._splited_triangle_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 0, None, GL_DYNAMIC_DRAW)
        self._adjacency_info_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 3, None, GL_DYNAMIC_DRAW)
        self._share_adjacency_pn_triangle_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 4, None, GL_DYNAMIC_DRAW)
        self._share_adjacency_pn_triangle_position_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 19, None, GL_DYNAMIC_DRAW)
        self._splited_triangle_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 5, None, GL_DYNAMIC_DRAW)

        # init shader
        self._program_gen_pn_triangle = ProgramWrap().add_shader(
            ShaderWrap(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_pn_oo.glsl')))
        self._program = ProgramWrap().add_shader(
            PreviousComputeShader(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_oo.glsl'),
                                  self))  # type: ProgramWrap
Example #2
0
    def __init__(self, size: list):
        # check input
        if len(size) != 3:
            raise Exception('b spline body size number error')
        if any(i < 0 for i in size):
            raise Exception('b spline body size < 0, error')

        # init b-spline body
        self._b_spline_body = BSplineBody(*size)  # type: BSplineBody

        # init shader program
        self._renderer_program = ProgramWrap().add_shader(ShaderWrap(GL_VERTEX_SHADER, add_prefix('aux.v.glsl'))) \
            .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_prefix('aux.f.glsl')))  # type: ProgramWrap

        # init buffer
        self._control_point_position_vbo = ACVBO(GL_ARRAY_BUFFER, -1, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        if conf.IS_FAST_MODE:
            self._control_point_for_sample_ubo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None,
                                                       GL_DYNAMIC_DRAW)  # type: ACVBO
        else:
            self._control_point_for_sample_ubo = ACVBO(GL_UNIFORM_BUFFER, 1, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        self._b_spline_body_info_ubo = ACVBO(GL_UNIFORM_BUFFER, 0, None, GL_STATIC_DRAW)  # type: ACVBO
        self._selected_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 1, None, GL_DYNAMIC_DRAW)
        self._vao_control_point = -1  # type: int
        self._normal_control_mode = False  # type: bool
        self._pick_region = None  # type: ACRect
        self._control_points_changed = True  # type: bool
        self._direct_control_point = []  # type:  list
        self._intersect_point_parameter = None

        # init compute select point shader program
        self._select_point_program = ProgramWrap() \
            .add_shader(ShaderWrap(GL_COMPUTE_SHADER, add_compute_prefix('select_point.glsl')))
        self._intersect_result_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 20, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        self._need_select_point = False
        self._select_argument = None

        self._delta_for_dffd = [0, 0, 0]
class PreviousComputeControllerGPU:
    def __init__(self, model: OBJ, controller):
        self._model = model  # type: OBJ
        self._controller = controller  # type: Controller

        # init pattern data
        self._split_factor = 0.2  # type: float
        self.MAX_SEGMENTS = -1  # type: int
        self._pattern_offsets = None  # type: np.array
        self._pattern_indexes = None  # type: np.array
        self._pattern_parameters = None  # type: np.array
        self._need_recompute = True  # type: bool
        self._need_update_split_factor = True  # type: bool
        self._splited_triangle_number = -1  # type: int
        self.init_pattern_data()

        # declare buffer
        self._original_vertex_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 0, None, GL_DYNAMIC_DRAW)
        self._original_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 1, None, GL_DYNAMIC_DRAW)
        self._original_tex_coord_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 22, None, GL_DYNAMIC_DRAW)
        if self._model.from_bezier:
            self._original_uv_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 24, None, GL_DYNAMIC_DRAW)
        self._original_index_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 2, None, GL_DYNAMIC_DRAW)
        self._splited_triangle_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 0, None, GL_DYNAMIC_DRAW)
        self._adjacency_info_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 3, None, GL_DYNAMIC_DRAW)
        self._share_adjacency_pn_triangle_normal_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 4, None, GL_DYNAMIC_DRAW)
        self._share_adjacency_pn_triangle_position_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 19, None, GL_DYNAMIC_DRAW)
        self._splited_triangle_ssbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 5, None, GL_DYNAMIC_DRAW)

        # init shader
        self._program_gen_pn_triangle = ProgramWrap().add_shader(
            ShaderWrap(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_pn_oo.glsl')))
        self._program = ProgramWrap().add_shader(
            PreviousComputeShader(GL_COMPUTE_SHADER, add_prefix('previous_compute_shader_oo.glsl'),
                                  self))  # type: ProgramWrap

    @staticmethod
    def compute_triangle_quality(p1, p2, p3):
        points = [np.array(p) for p in (p1, p2, p3)]
        vecs = [points[0] - points[1], points[1] - points[2], points[2] - points[0]]
        area = np.linalg.norm(np.cross(vecs[0], vecs[1]) / 2)
        lens = [np.linalg.norm(v) for v in vecs]
        perimeter = sum(lens)
        return (2 * area / perimeter) / max(lens) * 2 * (3 ** 0.5)

    @staticmethod
    def compute_triangle_area(p1, p2, p3):
        def len(v1, v2):
            return sum([(x - y) ** 2 for x, y in zip(v1, v2)]) ** 0.5

        ls = [len(p1, p2), len(p2, p3), len(p3, p1)]
        s = sum(ls) / 2
        temp = [s - x for x in ls]
        return (temp[0] * temp[1] * temp[2] * s) ** 0.5

    def get_average_area_and_triangle_quality(self):
        triangles = self._splited_triangle_ssbo.get_value(ctypes.c_float, shape=(self._splited_triangle_number, 100))
        temp = 0
        temp_quality = 0
        for t in triangles:
            three_points = [x[:3] for x in zip(*[iter(t[:12])] * 4)]
            temp += PreviousComputeControllerGPU.compute_triangle_area(*three_points)
            # temp_quality += PreviousComputeControllerGPU.compute_triangle_quality(*three_points)
            temp_quality += t[-1]
        return temp / self.splited_triangle_number, temp_quality / self.splited_triangle_number

    def change_model(self, model):
        self._model = model
        self.gl_async_update_buffer_for_self_about_model()
        self._need_recompute = True  # type: bool

    def gl_init(self):
        self._program_gen_pn_triangle.link()
        self._program.link()
        self.gl_set_split_factor()
        # async update vbo
        self.gl_async_update_buffer_for_self()

    def gl_init_split_counter(self):
        self._splited_triangle_counter_acbo.async_update(np.array([0], dtype=np.uint32))
        self._splited_triangle_counter_acbo.gl_sync()

    def gl_async_update_buffer_for_self(self):
        indexes_size = self._pattern_indexes.size * self._pattern_indexes.itemsize
        parameter_size = self._pattern_parameters.size * self._pattern_parameters.itemsize
        offset_size = self._pattern_offsets.size * self._pattern_offsets.itemsize
        split_info_buffer = glGenBuffers(1)
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, split_info_buffer)
        glBufferData(GL_SHADER_STORAGE_BUFFER, offset_size + indexes_size + parameter_size,
                     None,
                     usage=GL_DYNAMIC_DRAW)
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, indexes_size, self._pattern_indexes)
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, indexes_size, parameter_size, self._pattern_parameters)
        glBufferSubData(GL_SHADER_STORAGE_BUFFER, indexes_size + parameter_size, offset_size, self._pattern_offsets)
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 9, split_info_buffer)
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0)

        self.gl_async_update_buffer_for_self_about_model()

    def gl_async_update_buffer_for_self_about_model(self):
        self._original_vertex_ssbo.async_update(self._model.vertex)
        self._original_normal_ssbo.async_update(self._model.normal)
        self._original_tex_coord_ssbo.async_update(self._model.tex_coord)
        if self._model.from_bezier:
            self._original_uv_ssbo.async_update(self._model.bezier_uv)
        self._original_index_ssbo.async_update(self._model.index)
        self._adjacency_info_ssbo.async_update(self._model.adjacency)
        self.gl_async_update_buffer_about_output()

    def gl_update_index(self, is_original):
        if not is_original:
            self._original_index_ssbo.async_update(self._model.index)
        else:
            print('update index for original')
            self._original_index_ssbo.async_update(self._model.index_without_mark)

    def gl_async_update_buffer_about_output(self):
        self._share_adjacency_pn_triangle_normal_ssbo.capacity = self._model._original_triangle_number \
                                                                 * PER_TRIANGLE_PN_NORMAL_TRIANGLE_SIZE

        self._share_adjacency_pn_triangle_position_ssbo.capacity = self._model._original_triangle_number \
                                                                   * PER_TRIANGLE_PN_POSITION_TRIANGLE_SIZE

        # 用于储存原始三角面片的PN-triangle
        self._splited_triangle_ssbo.capacity = self._model._original_triangle_number \
                                               * MAX_SPLITED_TRIANGLE_PRE_ORIGINAL_TRIANGLE \
                                               * SPLITED_TRIANGLE_SIZE

    def gl_sync(self):
        self._original_vertex_ssbo.gl_sync()
        self._original_normal_ssbo.gl_sync()
        self._original_tex_coord_ssbo.gl_sync()
        if self._model.from_bezier:
            self._original_uv_ssbo.gl_sync()
        self._original_index_ssbo.gl_sync()
        self._adjacency_info_ssbo.gl_sync()
        self._share_adjacency_pn_triangle_normal_ssbo.gl_sync()
        self._share_adjacency_pn_triangle_position_ssbo.gl_sync()
        self._splited_triangle_ssbo.gl_sync()

    def gl_compute(self, op) -> (int, bool):
        if not self._need_recompute:
            return self._splited_triangle_number, False
        self.gl_sync()
        op()
        if self._need_update_split_factor:
            self.gl_set_split_factor()
            self._need_update_split_factor = False
        self._program_gen_pn_triangle.use()

        gl_timing(lambda: glDispatchCompute(*self.group_size), 'gen PN triangle time')
        glFinish()

        self._program.use()
        self.gl_init_split_counter()

        self._controller.add_time(gl_timing(lambda: glDispatchCompute(*self.group_size), 'pre compute time'))

        glUseProgram(0)

        self._splited_triangle_number = self.get_splited_triangles_number()
        glFinish()

        self._need_recompute = False
        # print('gl_compute:', 'gpu splited triangle number: %d' % self._splited_triangle_number)
        self._controller.add_splited_number(self.splited_triangle_number)
        area, quality = self.get_average_area_and_triangle_quality()
        self._controller.add_area(area)
        self._controller.add_quality(quality)
        return self._splited_triangle_number, True

    @property
    def need_compute(self):
        return self._need_recompute

    @need_compute.setter
    def need_compute(self, b):
        self._need_recompute = b

    @property
    def split_factor(self):
        return self._split_factor

    @property
    def model(self):
        return self._model

    @property
    def group_size(self):
        return [int(self._model._original_triangle_number / 512 + 1), 1, 1]

    @split_factor.setter
    def split_factor(self, split_factor):
        self._split_factor = split_factor
        self._need_recompute = True
        self._need_update_split_factor = True

    def gl_set_split_factor(self):
        glProgramUniform1f(self._program.program, 0, self._split_factor)

    @property
    def pattern_offsets(self):
        return self._pattern_offsets

    @property
    def pattern_indexes(self):
        return self._pattern_indexes

    @property
    def pattern_parameters(self):
        return self._pattern_parameters

    def init_pattern_data(self):
        with open(PATTERN_FILE_PATH) as file:
            max_factor, offset_line, indexes_line, parameter_line = file
        print('read pattern file ok')
        self.MAX_SEGMENTS = int(max_factor)
        self._pattern_offsets = np.asarray([int(x) for x in offset_line.strip().split(" ")], dtype=np.uint32)
        self._pattern_indexes = np.asarray([int(x) for x in indexes_line.strip().split(" ")], dtype=np.uint32)
        self._pattern_parameters = np.asarray([abs(float(x)) for x in parameter_line.strip().split(" ")],
                                              dtype=np.float32)
        print('translate to np array ok')
        indexes_size = self._pattern_indexes.size * self._pattern_indexes.itemsize
        parameter_size = self._pattern_parameters.size * self._pattern_parameters.itemsize
        offset_size = self._pattern_offsets.size * self._pattern_offsets.itemsize
        print('pattern size ', (offset_size + indexes_size + parameter_size) / 1024 / 1024, "mb")

    def get_offset_for_i(self) -> str:
        look_up_table_for_i = [0]
        for i in range(1, self.MAX_SEGMENTS):
            ii = min(self.MAX_SEGMENTS - i, i)
            look_up_table_for_i.append(
                int(look_up_table_for_i[-1] + (1 + ii) * ii / 2 + max(0, (i + 1) * (self.MAX_SEGMENTS - 2 * i))))
        return '{' + ','.join([str(i) for i in look_up_table_for_i]) + '}'

    def get_splited_triangles_number(self) -> int:
        return self._splited_triangle_counter_acbo.get_value(ctypes.c_uint32)[0]

    @property
    def splited_triangle_number(self):
        return self._splited_triangle_number

    @property
    def share_adjacency_pn_triangle_normal_ssbo(self):
        return self._share_adjacency_pn_triangle_normal_ssbo

    @property
    def share_adjacency_pn_triangle_position_ssbo(self):
        return self._share_adjacency_pn_triangle_position_ssbo

    @property
    def splited_triangle_ssbo(self):
        return self._splited_triangle_ssbo

    @property
    def original_vertex_ssbo(self):
        return self._original_vertex_ssbo

    @property
    def original_normal_ssbo(self):
        return self._original_normal_ssbo

    @property
    def original_tex_coord_ssbo(self):
        return self._original_tex_coord_ssbo

    @property
    def original_index_ssbo(self):
        return self._original_index_ssbo
    def __init__(self, has_texture, previous_controller, model, aux_controller: AuxController, controller=None):
        self.need_export_obj = False
        self._screen_shot = False
        self._screen_width = 0
        self._screen_height = 0
        self._time_number = -3
        self._time_total = 0
        self._aux_controller = aux_controller  # type: AuxController
        self.model = model
        self._previous_controller = previous_controller  # type: PreviousComputeControllerGPU
        self._controller = controller
        self._splited_triangle_number = -1

        self._tessellation_level = -1  # type: int
        self._final_tessellation_level = 0.02  # type: int
        self._tessellated_point_number_pre_splited_triangle = -1  # type: int
        self._tessellated_triangle_number_pre_splited_triangle = -1  # type: int
        self._tessellation_parameter = None  # type: list
        self._tessellation_index = None  # type: list
        self._tessellation_factor_changed = False  # type: bool
        self._splited_triangle_number_changed = False  # type: bool
        self._tessellation_aux = None

        if config.IS_UNIFORM_ADAPTIVE_TESSELLATION_FACTOR:
            self.init_tessellation_pattern_data(
                int(self._previous_controller.split_factor / self._final_tessellation_level))
        else:
            self.init_tessellation_pattern_data(10)

        self._need_deform = True  # type: bool
        self._need_update_uniform_about_b_spline = False

        self._need_update_show_splited_edge_flag = True
        self._splited_edge_visibility = False

        self._need_update_triangle_quality_flag = True
        self._show_quality = False

        self._need_update_normal_diff_flag = True
        self._show_normal_diff = False

        self._need_update_position_diff_flag = True
        self._show_position_diff = False

        self._need_update_adjust_control_point_flag = True
        self._adjust_control_point = True

        self._need_comparison = False

        self._need_update_show_original = True
        self._show_original = False

        self._need_update_use_pn_normal_for_renderer = True
        self._use_pn_normal_for_renderer = False

        self._need_update_show_real_flag = True
        self._show_real = False

        self._need_update_use_texture_flag = False
        self._has_texture = has_texture

        # vbo
        self._vertex_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 6, None, GL_DYNAMIC_COPY)  # type: ACVBO
        self._normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 7, None, GL_DYNAMIC_COPY)  # type: ACVBO
        self._index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 8, None, GL_DYNAMIC_COPY)  # type: ACVBO
        if self.model.from_bezier:
            self._bezier_control_point_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 25, None, GL_DYNAMIC_DRAW)
        self._model_vao = -1  # type: int
        self._original_model_vao = -1  # type: int

        self._parameter_in_BSpline_body_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 21, None, GL_DYNAMIC_DRAW)  # type: ACVBO

        if not conf.IS_FAST_MODE:
            self._tex_coord_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 23, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._parameter_in_splited_triangle_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 10, None,
                                                            GL_DYNAMIC_DRAW)  # type: ACVBO
            self._parameter_in_original_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 11, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._real_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 12, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._real_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_DYNAMIC_DRAW)  # type: ACVBO

            self._show_control_point = False
            self._control_point_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._control_point_index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._control_point_vao = -1  # type: int

            self._show_normal = False
            self._show_normal_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 17, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._show_normal_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 18, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._show_normal_vao = -1  # type: int

        # program
        self._deform_program = DeformComputeProgram(self) \
            .add_shader(
            DeformComputeShader(GL_COMPUTE_SHADER, add_compute_prefix('deform_compute_shader_oo.glsl'), self))

        self._renderer_program = ModelRendererShader(self) \
            .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('vertex.glsl'))) \
            .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('fragment.glsl')))  # type: ProgramWrap

        if not conf.IS_FAST_MODE:
            self._renderer_control_point_program = ProgramWrap() \
                .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('control_points.v.glsl'))) \
                .add_shader(
                ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('control_points.f.glsl')))  # type: ProgramWrap

            self._renderer_normal_program = ProgramWrap() \
                .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('normal.v.glsl'))) \
                .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('normal.f.glsl'))) \
                .add_shader(ShaderWrap(GL_GEOMETRY_SHADER, add_renderer_prefix('normal.g.glsl')))  # type: ProgramWrap
class DeformAndDrawController:
    @property
    def final_tessellation_level(self):
        return self._final_tessellation_level

    def __init__(self, has_texture, previous_controller, model, aux_controller: AuxController, controller=None):
        self.need_export_obj = False
        self._screen_shot = False
        self._screen_width = 0
        self._screen_height = 0
        self._time_number = -3
        self._time_total = 0
        self._aux_controller = aux_controller  # type: AuxController
        self.model = model
        self._previous_controller = previous_controller  # type: PreviousComputeControllerGPU
        self._controller = controller
        self._splited_triangle_number = -1

        self._tessellation_level = -1  # type: int
        self._final_tessellation_level = 0.02  # type: int
        self._tessellated_point_number_pre_splited_triangle = -1  # type: int
        self._tessellated_triangle_number_pre_splited_triangle = -1  # type: int
        self._tessellation_parameter = None  # type: list
        self._tessellation_index = None  # type: list
        self._tessellation_factor_changed = False  # type: bool
        self._splited_triangle_number_changed = False  # type: bool
        self._tessellation_aux = None

        if config.IS_UNIFORM_ADAPTIVE_TESSELLATION_FACTOR:
            self.init_tessellation_pattern_data(
                int(self._previous_controller.split_factor / self._final_tessellation_level))
        else:
            self.init_tessellation_pattern_data(10)

        self._need_deform = True  # type: bool
        self._need_update_uniform_about_b_spline = False

        self._need_update_show_splited_edge_flag = True
        self._splited_edge_visibility = False

        self._need_update_triangle_quality_flag = True
        self._show_quality = False

        self._need_update_normal_diff_flag = True
        self._show_normal_diff = False

        self._need_update_position_diff_flag = True
        self._show_position_diff = False

        self._need_update_adjust_control_point_flag = True
        self._adjust_control_point = True

        self._need_comparison = False

        self._need_update_show_original = True
        self._show_original = False

        self._need_update_use_pn_normal_for_renderer = True
        self._use_pn_normal_for_renderer = False

        self._need_update_show_real_flag = True
        self._show_real = False

        self._need_update_use_texture_flag = False
        self._has_texture = has_texture

        # vbo
        self._vertex_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 6, None, GL_DYNAMIC_COPY)  # type: ACVBO
        self._normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 7, None, GL_DYNAMIC_COPY)  # type: ACVBO
        self._index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 8, None, GL_DYNAMIC_COPY)  # type: ACVBO
        if self.model.from_bezier:
            self._bezier_control_point_buffer = ACVBO(GL_SHADER_STORAGE_BUFFER, 25, None, GL_DYNAMIC_DRAW)
        self._model_vao = -1  # type: int
        self._original_model_vao = -1  # type: int

        self._parameter_in_BSpline_body_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 21, None, GL_DYNAMIC_DRAW)  # type: ACVBO

        if not conf.IS_FAST_MODE:
            self._tex_coord_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 23, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._parameter_in_splited_triangle_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 10, None,
                                                            GL_DYNAMIC_DRAW)  # type: ACVBO
            self._parameter_in_original_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 11, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._real_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 12, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._real_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 13, None, GL_DYNAMIC_DRAW)  # type: ACVBO

            self._show_control_point = False
            self._control_point_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._control_point_index_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 16, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._control_point_vao = -1  # type: int

            self._show_normal = False
            self._show_normal_position_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 17, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._show_normal_normal_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 18, None, GL_DYNAMIC_DRAW)  # type: ACVBO
            self._show_normal_vao = -1  # type: int

        # program
        self._deform_program = DeformComputeProgram(self) \
            .add_shader(
            DeformComputeShader(GL_COMPUTE_SHADER, add_compute_prefix('deform_compute_shader_oo.glsl'), self))

        self._renderer_program = ModelRendererShader(self) \
            .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('vertex.glsl'))) \
            .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('fragment.glsl')))  # type: ProgramWrap

        if not conf.IS_FAST_MODE:
            self._renderer_control_point_program = ProgramWrap() \
                .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('control_points.v.glsl'))) \
                .add_shader(
                ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('control_points.f.glsl')))  # type: ProgramWrap

            self._renderer_normal_program = ProgramWrap() \
                .add_shader(ShaderWrap(GL_VERTEX_SHADER, add_renderer_prefix('normal.v.glsl'))) \
                .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_renderer_prefix('normal.f.glsl'))) \
                .add_shader(ShaderWrap(GL_GEOMETRY_SHADER, add_renderer_prefix('normal.g.glsl')))  # type: ProgramWrap

    def gl_init(self):
        self._model_vao = glGenVertexArrays(1)
        glBindVertexArray(self._model_vao)
        # set vertice attribute
        self._vertex_vbo.as_array_buffer(0, 4, GL_FLOAT)
        # set normal attribute
        self._normal_vbo.as_array_buffer(1, 4, GL_FLOAT)
        # specific index buffer
        self._index_vbo.as_element_array_buffer()

        if not conf.IS_FAST_MODE:
            self._tex_coord_vbo.as_array_buffer(6, 2, GL_FLOAT)
            # set tessellate parameter attribute
            self._parameter_in_splited_triangle_vbo.as_array_buffer(2, 4, GL_FLOAT)
            # set split parameter attribute
            self._parameter_in_original_vbo.as_array_buffer(3, 4, GL_FLOAT)
            self._real_normal_vbo.as_array_buffer(4, 4, GL_FLOAT)
            self._real_position_vbo.as_array_buffer(5, 4, GL_FLOAT)
        # unbind program
        glBindVertexArray(0)

        if not conf.IS_FAST_MODE:
            self._original_model_vao = glGenVertexArrays(1)  # type: int
            glBindVertexArray(self._original_model_vao)
            self._previous_controller.original_vertex_ssbo.as_array_buffer(0, 4, GL_FLOAT)
            self._previous_controller.original_normal_ssbo.as_array_buffer(1, 4, GL_FLOAT)
            self._previous_controller.original_tex_coord_ssbo.as_array_buffer(6, 2, GL_FLOAT)
            self._previous_controller.original_index_ssbo.as_element_array_buffer()
            glBindVertexArray(0)

            self._control_point_vao = glGenVertexArrays(1)
            glBindVertexArray(self._control_point_vao)
            self._control_point_vbo.as_array_buffer(0, 4, GL_FLOAT)
            self._control_point_index_vbo.as_element_array_buffer()
            glBindVertexArray(0)

            self._show_normal_vao = glGenVertexArrays(1)
            glBindVertexArray(self._show_normal_vao)
            self._show_normal_position_vbo.as_array_buffer(0, 4, GL_FLOAT)
            self._show_normal_normal_vbo.as_array_buffer(1, 4, GL_FLOAT)
            glBindVertexArray(0)

        self.gl_async_update_buffer_for_self()

        # init for texture
        texture_name = glGenTextures(1)

        glActiveTexture(GL_TEXTURE1)
        glEnable(GL_TEXTURE_2D)

        # "Bind" the newly created texture : all future texture functions will modify this texture
        glBindTexture(GL_TEXTURE_2D, texture_name)

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

        # image = DeformAndDrawController.load_texture_data('res/3d_model/rabbit_real/rabbit256.png')
        # image = DeformAndDrawController.load_texture_data('res/3d_model/ship/ship_texture.png')
        image = DeformAndDrawController.load_texture_data('res/colormap.png')
        # Give the image to OpenGL
        image_data = np.array(list(image.getdata()), dtype=np.uint8)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.size[0], image.size[1],
                     0, GL_RGBA, GL_UNSIGNED_BYTE, image_data)
        glActiveTexture(GL_TEXTURE0)

    @staticmethod
    def load_texture_data(filename):
        return Image.open(filename)

    def gl_async_update_buffer_for_self(self):
        if self._vertex_vbo is not None:
            self._vertex_vbo.capacity = self.splited_triangle_number \
                                        * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE
        if self._normal_vbo is not None:
            self._normal_vbo.capacity = self.splited_triangle_number \
                                        * self.tessellated_point_number_pre_splited_triangle * NORMAL_SIZE

        if self._index_vbo is not None:
            self._index_vbo.capacity = self.splited_triangle_number \
                                       * self.tessellated_triangle_number_pre_splited_triangle * PER_TRIANGLE_INDEX_SIZE

        if self._parameter_in_BSpline_body_vbo is not None:
            self._parameter_in_BSpline_body_vbo.capacity = self.splited_triangle_number \
                                                           * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE

        if not conf.IS_FAST_MODE:
            if self._tex_coord_vbo is not None:
                self._tex_coord_vbo.capacity = self.splited_triangle_number \
                                               * self.tessellated_point_number_pre_splited_triangle * TEX_COORD_SIZE
            if self._parameter_in_splited_triangle_vbo is not None:
                self._parameter_in_splited_triangle_vbo.capacity = self.splited_triangle_number \
                                                                   * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE
            if self._parameter_in_original_vbo is not None:
                self._parameter_in_original_vbo.capacity = self.splited_triangle_number \
                                                           * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE
            if self._real_normal_vbo is not None:
                self._real_normal_vbo.capacity = self.splited_triangle_number \
                                                 * self.tessellated_point_number_pre_splited_triangle * NORMAL_SIZE
            if self._real_position_vbo is not None:
                self._real_position_vbo.capacity = self.splited_triangle_number \
                                                   * self.tessellated_point_number_pre_splited_triangle * VERTEX_SIZE

            if self._control_point_vbo is not None:
                self._control_point_vbo.capacity = self.splited_triangle_number * CONTROL_POINT_NUMBER * VERTEX_SIZE

            if self._control_point_index_vbo is not None:
                self._control_point_index_vbo.capacity = self.splited_triangle_number * CONTROL_POINT_TRIANGLE_NUMBER * PER_TRIANGLE_INDEX_SIZE

            if self._show_normal_position_vbo is not None:
                self._show_normal_position_vbo.capacity = self.splited_triangle_number * SHOW_NORMAL_POINT_NUMBER_PER_TRIANGLE * VERTEX_SIZE

            if self._show_normal_normal_vbo is not None:
                self._show_normal_normal_vbo.capacity = self.splited_triangle_number * SHOW_NORMAL_POINT_NUMBER_PER_TRIANGLE * NORMAL_SIZE

            if self.model.from_bezier and self._bezier_control_point_buffer is not None:
                self._bezier_control_point_buffer.async_update(self.model.bezier_control_points)

    def gl_sync_buffer(self):
        self._vertex_vbo.gl_sync()
        self._normal_vbo.gl_sync()
        self._index_vbo.gl_sync()
        self._parameter_in_BSpline_body_vbo.gl_sync()
        if not conf.IS_FAST_MODE:
            self._tex_coord_vbo.gl_sync()
            self._parameter_in_splited_triangle_vbo.gl_sync()
            self._parameter_in_original_vbo.gl_sync()
            self._real_normal_vbo.gl_sync()
            self._real_position_vbo.gl_sync()
            self._control_point_vbo.gl_sync()
            self._control_point_index_vbo.gl_sync()
            self._show_normal_position_vbo.gl_sync()
            self._show_normal_normal_vbo.gl_sync()
            self._previous_controller.original_index_ssbo.gl_sync()
            if self.model.from_bezier:
                self._bezier_control_point_buffer.gl_sync()

    def gl_deform(self, operator):
        if not self.need_deform:
            return
        operator()
        self._deform_program.use()
        if self._tessellation_factor_changed:
            self._deform_program.update_uniform_about_tessellation()
            self._tessellation_factor_changed = False
        if self._splited_triangle_number_changed:
            self._deform_program.update_uniform_triangle_number()
            self._splited_triangle_number_changed = False
        if self._need_update_adjust_control_point_flag:
            self._deform_program.update_uniform_about_adjust_control_point_flag()
            self._need_update_adjust_control_point_flag = False
        if self._need_update_use_pn_normal_for_renderer:
            self._deform_program.update_uniform_about_use_pn_triangle()
            self._need_update_use_pn_normal_for_renderer = False

        self._deform_program.update_uniform_about_modify_range()

        self._controller.add_time(GLUtil.gl_timing(lambda: glDispatchCompute(*self.group_size), "deformation", 3))

        self._need_deform = False
        glUseProgram(0)

    def gl_renderer(self, model_view_matrix: np.array, perspective_matrix: np.array, operator):
        self.gl_sync_buffer()
        self.gl_deform(operator)
        self._renderer_program.use()
        if self._need_update_show_splited_edge_flag:
            self._renderer_program.update_uniform_about_split_edge()
            self._need_update_show_splited_edge_flag = False

        if self._need_update_use_texture_flag:
            self._renderer_program.update_uniform_about_texture()
            self._need_update_use_texture_flag = False

        if self._need_update_show_original:
            self._renderer_program.update_uniform_about_show_original()
            self._need_update_show_original = False

        if self._need_update_triangle_quality_flag:
            self._renderer_program.update_uniform_about_triangle_quality()
            self._need_update_triangle_quality_flag = False

        if self._need_update_normal_diff_flag:
            self._renderer_program.update_uniform_about_normal_diff()
            self._need_update_normal_diff_flag = False

        if self._need_update_position_diff_flag:
            self._renderer_program.update_uniform_about_position_diff()
            self._need_update_position_diff_flag = False

        if self._need_update_show_real_flag:
            self._renderer_program.update_uniform_about_real()
            self._need_update_show_real_flag = False

        if self.need_export_obj:
            self.gl_export_obj()
            self.need_export_obj = False

        glEnable(GL_DEPTH_TEST)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        # common bind
        wvp_matrix = multiply(model_view_matrix, perspective_matrix)
        glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix)
        glUniformMatrix4fv(1, 1, GL_FALSE, model_view_matrix)

        glActiveTexture(GL_TEXTURE1)
        if conf.IS_FAST_MODE:
            glBindVertexArray(self._model_vao)
        else:
            if self._show_original:
                glBindVertexArray(self._original_model_vao)
            else:
                glBindVertexArray(self._model_vao)

        if conf.IS_FAST_MODE or not self._show_control_point:
            number = int(self.splited_triangle_number * self.tessellated_triangle_number_pre_splited_triangle * 3)
            glDrawElements(GL_TRIANGLES, number, GL_UNSIGNED_INT, None)
        glActiveTexture(GL_TEXTURE0)
        glBindVertexArray(0)
        glUseProgram(0)

        if not conf.IS_FAST_MODE:
            if self._show_control_point:
                glBindVertexArray(self._control_point_vao)
                self._renderer_control_point_program.use()
                glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix)
                number = int(self.splited_triangle_number * CONTROL_POINT_TRIANGLE_NUMBER * 3)
                glDrawElements(GL_TRIANGLES, number, GL_UNSIGNED_INT, None)
                glFinish()
                glBindVertexArray(0)
                glUseProgram(0)

            if self._show_normal:
                glBindVertexArray(self._show_normal_vao)
                self._renderer_normal_program.use()
                glUniformMatrix4fv(0, 1, GL_FALSE, wvp_matrix)
                glUniformMatrix4fv(1, 1, GL_FALSE, model_view_matrix)
                number = int(self.splited_triangle_number * 3)
                glDrawArrays(GL_TRIANGLES, 0, number)
                glFinish()
                glUseProgram(0)
                glBindVertexArray(0)
            if self._screen_shot:
                if self._screen_height > self._screen_width:
                    x = 0
                    y = (self._screen_height - self._screen_width) / 2
                    w = self._screen_width
                    h = self._screen_width
                else:
                    x = (self._screen_width - self._screen_height) / 2
                    y = 0
                    w = self._screen_height
                    h = self._screen_height
                image_data = glReadPixels(x, y, w, h, GL_RGB, GL_FLOAT)
                shape = image_data.shape
                print('save size', shape)
                i = 0
                while os.path.exists('sc%d.png' % i):
                    i += 1

                mpimg.imsave('sc%d.png' % i, image_data.reshape((shape[1], shape[0], shape[2])), origin='lower')
                self._screen_shot = False

        glDisable(GL_DEPTH_TEST)
        glDisable(GL_BLEND)
        if self._vertex_vbo.capacity == 0:
            return

        if not self._need_comparison:
            return
        self._need_comparison = False
        self.comparison()
        # self.compute_area(self._vertex_vbo, self._index_vbo)

    def gl_export_obj(self):
        positions = self._vertex_vbo.get_value(ctypes.c_float, (int(self._vertex_vbo.capacity / 4 / 4), 4))
        positions = [(round(x, 5) for x in y) for y in positions]
        aux = {}
        index_map = {}
        counter = 0
        new_position = []
        for i in range(len(positions)):
            l = tuple(positions[i])
            positions[i] = l
            if l not in aux:
                aux[l] = counter
                new_position.append(l)
                counter += 1
            index_map[i] = aux[l]
        indices = self._index_vbo.get_value(ctypes.c_int, (int(self._index_vbo.capacity / 4 / 3), 3))
        with open('volume.obj', mode='w') as f:
            for p in new_position:
                f.write('v ' + ' '.join([str(x) for x in p[:3]]) + '\n')

            for i in indices:
                points = [np.array(positions[x][:3]) for x in i]

                v01 = points[1] - points[0]
                v02 = points[2] - points[0]
                if np.dot(np.cross(v01, v02), points[0]) < 0:
                    i[0], i[1] = i[1], i[0]
                f.write('f ' + ' '.join([str(index_map[x] + 1) + '//' for x in i]) + '\n')
        copyfile('volume.obj', '/home/ac/volume.obj')

    def save_screen(self, w, h):
        self._screen_shot = True
        self._screen_width = w
        self._screen_height = h

    @property
    def splited_triangle_number(self):
        return self._splited_triangle_number

    def set_number_and_need_deform(self, number: int, need_deform: bool):
        self._need_deform = (self._need_deform or need_deform or number != self._splited_triangle_number)
        if number != self._splited_triangle_number:
            self._splited_triangle_number = number
            self.gl_async_update_buffer_for_self()
            self._splited_triangle_number_changed = True

    @property
    def splited_triangle_number_changed(self):
        return self._splited_triangle_number_changed

    @property
    def group_size(self):
        return [int(self.splited_triangle_number / 64) + 1, 1, 1]

    @property
    def tessellation_level(self):
        return self._tessellation_level

    def init_tessellation_pattern_data(self, tessellation_level):
        self._tessellation_level = int(tessellation_level)
        self._tessellated_point_number_pre_splited_triangle = (self._tessellation_level + 1) \
                                                              * (self._tessellation_level + 2) / 2
        self._tessellated_triangle_number_pre_splited_triangle = self._tessellation_level * self._tessellation_level
        self._tessellation_parameter = []  # type: list
        u = self._tessellation_level
        for i in range(self._tessellation_level + 1):
            v = self._tessellation_level - u
            for j in range(i + 1):
                self._tessellation_parameter.append([u / self._tessellation_level, v / self._tessellation_level,
                                                     (self._tessellation_level - u - v) / self._tessellation_level, 0])
                v -= 1
            u -= 1

        rfactorialt = [0.166666666,
                       0.5, 0.5,
                       0.5, 1, 0.5,
                       0.166666666, 0.5, 0.5, 0.166666666]

        self._tessellation_aux = []
        for p in self._tessellation_parameter:
            index = 0
            for i in range(3, -1, -1):
                for j in range(3 - i, -1, -1):
                    k = 3 - i - j
                    t = 6 * rfactorialt[index] * power(p[0], i) * power(p[1], j) * power(p[2], k)
                    index += 1
                    self._tessellation_aux.append(t)
            self._tessellation_aux.append(0)
            self._tessellation_aux.append(0)

        self._tessellation_index = []  # type: list
        for i in range(self._tessellation_level):
            start = int((i + 1) * (i + 2) / 2)
            prev = [start, start + 1, start - 1 - i]
            self._tessellation_index.append(prev)
            for j in range(i * 2):
                next_index = [prev[2], prev[2] + 1, prev[1]]
                if j % 2 == 0:
                    self._tessellation_index.append([next_index[1], next_index[0], next_index[2]])
                else:
                    self._tessellation_index.append(next_index)
                prev = next_index
        self._tessellation_index = [x + [0] for x in self._tessellation_index]
        self._tessellation_factor_changed = True

    @property
    def tessellated_point_number_pre_splited_triangle(self):
        return self._tessellated_point_number_pre_splited_triangle

    @property
    def tessellated_triangle_number_pre_splited_triangle(self):
        return self._tessellated_triangle_number_pre_splited_triangle

    @property
    def tessellation_parameter(self):
        return np.array(self._tessellation_parameter, dtype=np.float32)

    @property
    def tessellation_aux(self):
        return np.array(self._tessellation_aux, dtype=np.float32)

    @property
    def tessellation_index(self):
        return np.array(self._tessellation_index, dtype=np.uint32)

    @property
    def need_deform(self):
        return self._need_deform

    @property
    def splited_edge_visibility(self):
        return self._splited_edge_visibility

    @property
    def show_quality(self):
        return self._show_quality

    @property
    def show_normal_diff(self):
        return self._show_normal_diff

    @property
    def show_position_diff(self):
        return self._show_position_diff

    @property
    def adjust_control_point(self):
        return self._adjust_control_point

    def set_show_normal_diff(self, v):
        self._show_normal_diff = v
        self._need_update_normal_diff_flag = True

    def set_show_position_diff(self, v):
        self._show_position_diff = v
        self._need_update_position_diff_flag = True

    def set_splited_edge_visibility(self, v):
        self._splited_edge_visibility = v
        self._need_update_show_splited_edge_flag = True

    def set_show_triangle_quality(self, v):
        self._show_quality = v
        self._need_update_triangle_quality_flag = True

    def set_show_real(self, is_show):
        self._show_real = is_show
        self._need_update_show_real_flag = True

    def set_show_original(self, is_show):
        self._show_original = is_show
        self._need_update_show_original = True

    def use_texture(self, b):
        self._has_texture = b
        self._need_update_use_texture_flag = True

    def set_adjust_control_point(self, v):
        self._adjust_control_point = v
        self._need_update_adjust_control_point_flag = True
        self._need_deform = True

    @need_deform.setter
    def need_deform(self, value):
        self._need_deform = value

    def set_tessellation_factor(self, tessellation_factor):
        self.init_tessellation_pattern_data(tessellation_factor)
        self.gl_async_update_buffer_for_self()
        self._need_deform = True

    @property
    def show_control_point(self):
        return self._show_control_point

    @show_control_point.setter
    def show_control_point(self, is_show):
        self._show_control_point = is_show

    @property
    def show_normal(self):
        return self._show_normal

    @show_normal.setter
    def show_normal(self, is_show):
        self._show_normal = is_show

    @property
    def show_real(self):
        return self._show_real

    def set_need_comparison(self):
        self._need_comparison = True

    @staticmethod
    def comparison_helper(vbo1: ACVBO, vbo2: ACVBO, fun):
        point_number = int(vbo1.capacity / 16)
        acc = 0
        max_e = -1
        es = []
        for i, j in zip(vbo1.get_value(ctypes.c_float, (point_number, 4)),
                        vbo2.get_value(ctypes.c_float, (point_number, 4))):
            e = fun(i, j)
            max_e = max(e, max_e)
            acc += e
            es.append(e)

        average = acc / point_number
        acc = 0
        for e in es:
            acc += ((e - average) ** 2)
        standard_deviation = (acc / point_number) ** 0.5
        return average, max_e, standard_deviation

    def comparison(self):
        dr1 = DeformAndDrawController.comparison_helper(self._vertex_vbo, self._real_position_vbo,
                                                        lambda i, j: sqrt(
                                                            reduce(lambda p, x: p + x,
                                                                   [e * e for e in (i - j)[:3]],
                                                                   0)))

        def fun(i, j):
            cos_value = np.dot(i[:3], j[:3])
            if cos_value > 1:
                cos_value = 1
            elif cos_value < -1:
                cos_value = -1
            return acos(cos_value) / pi * 180

        dr2 = DeformAndDrawController.comparison_helper(self._normal_vbo, self._real_normal_vbo, fun)
        self._controller.add_diff_result((dr1, dr2))

    @property
    def has_texture(self):
        return self._has_texture

    @property
    def show_original(self):
        return self._show_original

    @property
    def use_pn_normal_for_renderer(self):
        return self._use_pn_normal_for_renderer

    @use_pn_normal_for_renderer.setter
    def use_pn_normal_for_renderer(self, use):
        self._use_pn_normal_for_renderer = use
        self._need_update_use_pn_normal_for_renderer = True
        self._need_deform = True

    def get_modify_range(self):
        return self._aux_controller.get_modify_range()

    def get_tessed_triangles_number(self) -> int:
        res = self._tessed_triangle_counter_acbo.get_value(ctypes.c_uint32)[0]
        return res

    def export_obj(self):
        self.need_export_obj = True
Example #6
0
class AuxController:
    def __init__(self, size: list):
        # check input
        if len(size) != 3:
            raise Exception('b spline body size number error')
        if any(i < 0 for i in size):
            raise Exception('b spline body size < 0, error')

        # init b-spline body
        self._b_spline_body = BSplineBody(*size)  # type: BSplineBody

        # init shader program
        self._renderer_program = ProgramWrap().add_shader(ShaderWrap(GL_VERTEX_SHADER, add_prefix('aux.v.glsl'))) \
            .add_shader(ShaderWrap(GL_FRAGMENT_SHADER, add_prefix('aux.f.glsl')))  # type: ProgramWrap

        # init buffer
        self._control_point_position_vbo = ACVBO(GL_ARRAY_BUFFER, -1, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        if conf.IS_FAST_MODE:
            self._control_point_for_sample_ubo = ACVBO(GL_SHADER_STORAGE_BUFFER, 15, None,
                                                       GL_DYNAMIC_DRAW)  # type: ACVBO
        else:
            self._control_point_for_sample_ubo = ACVBO(GL_UNIFORM_BUFFER, 1, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        self._b_spline_body_info_ubo = ACVBO(GL_UNIFORM_BUFFER, 0, None, GL_STATIC_DRAW)  # type: ACVBO
        self._selected_counter_acbo = ACVBO(GL_ATOMIC_COUNTER_BUFFER, 1, None, GL_DYNAMIC_DRAW)
        self._vao_control_point = -1  # type: int
        self._normal_control_mode = False  # type: bool
        self._pick_region = None  # type: ACRect
        self._control_points_changed = True  # type: bool
        self._direct_control_point = []  # type:  list
        self._intersect_point_parameter = None

        # init compute select point shader program
        self._select_point_program = ProgramWrap() \
            .add_shader(ShaderWrap(GL_COMPUTE_SHADER, add_compute_prefix('select_point.glsl')))
        self._intersect_result_vbo = ACVBO(GL_SHADER_STORAGE_BUFFER, 20, None, GL_DYNAMIC_DRAW)  # type: ACVBO
        self._need_select_point = False
        self._select_argument = None

        self._delta_for_dffd = [0, 0, 0]

    def change_size(self, size):
        # check input
        if len(size) != 3:
            raise Exception('b spline body size number error')
        if any(i < 0 for i in size):
            raise Exception('b spline body size < 0, error')
        self._b_spline_body = BSplineBody(*size)  # type: BSplineBody
        self.async_upload_to_gpu()

    def gl_init(self):
        # init vao
        self._vao_control_point = glGenVertexArrays(1)
        glBindVertexArray(self._vao_control_point)
        self._control_point_position_vbo.as_array_buffer(0, 4, GL_FLOAT)
        glBindVertexArray(0)

        # upload_to_gpu
        self.async_upload_to_gpu()

    def async_upload_to_gpu(self):
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._b_spline_body_info_ubo.async_update(self._b_spline_body.get_info())

    def gl_sync_buffer_for_self(self):
        self._control_point_position_vbo.gl_sync()

    def gl_sync_buffer_for_previous_computer(self):
        self._b_spline_body_info_ubo.gl_sync()

    def gl_sync_buffer_for_deformation(self):
        def op():
            self._control_point_for_sample_ubo.gl_sync()
            self._b_spline_body_info_ubo.gl_sync()

        GLUtil.gl_timing(op, 'copy control to gpu', 3)

    def gl_draw(self, model_view_matrix: np.array, perspective_matrix: np.array):
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_PROGRAM_POINT_SIZE)
        self._renderer_program.use()
        glBindVertexArray(self._vao_control_point)
        self.gl_pick_control_point(model_view_matrix, perspective_matrix)
        glFinish()
        self.gl_sync_buffer_for_self()
        self.gl_draw_control_points(model_view_matrix, perspective_matrix)
        glFinish()
        glBindVertexArray(0)
        glUseProgram(0)
        self.gl_select_point_gpu()
        glFinish()

    def gl_draw_control_points(self, model_view_matrix, perspective_matrix):
        glUniformMatrix4fv(0, 1, GL_FALSE, multiply(model_view_matrix, perspective_matrix))
        glDrawArrays(GL_POINTS, 0, self.get_control_point_number())

    def gl_pick_control_point(self, model_view_matrix, perspective_matrix):
        if not self._pick_region:
            return
        self._b_spline_body.reset_hit_record()
        glSelectBuffer(1024)
        glRenderMode(GL_SELECT)
        glInitNames()
        glPushName(0)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        w = max(10, self._pick_region.w)
        h = max(10, self._pick_region.h)
        gluPickMatrix((self._pick_region.x1 + self._pick_region.x2) / 2,
                      (self._pick_region.y1 + self._pick_region.y2) / 2,
                      w, h,
                      glGetDoublev(GL_VIEWPORT))
        glUniformMatrix4fv(0, 1, GL_FALSE, multiply(model_view_matrix,
                                                    multiply(perspective_matrix,
                                                             glGetDoublev(GL_PROJECTION_MATRIX))))
        for i in range(self._b_spline_body.get_control_point_number()):
            glLoadName(i)
            glDrawArrays(GL_POINTS, i, 1)
        hit_info = glRenderMode(GL_RENDER)
        for r in hit_info:
            for select_name in r.names:
                self._b_spline_body.hit_point(select_name)
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._pick_region = None

    def pick_control_point(self, region: ACRect):
        self._pick_region = region

    def move_selected_control_points(self, xyz):
        self._b_spline_body.move([d / 10 for d in xyz])
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._control_points_changed = True

    def rotate_selected_control_points(self, m):
        self._b_spline_body.rotate(m)
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._control_points_changed = True

    def get_control_point_data(self):
        if self._normal_control_mode:
            return self._b_spline_body.control_points
        else:
            return np.array(self._direct_control_point, dtype='f4')

    def get_normal_control_point_data(self):
        return self._b_spline_body.normal_control_points

    def get_control_point_number(self):
        if self._normal_control_mode:
            return self._b_spline_body.get_control_point_number()
        else:
            return len(self._direct_control_point)

    def get_control_point_for_sample(self):
        return self._b_spline_body.get_control_point_for_sample()

    def get_cage_size(self) -> list:
        return self._b_spline_body.get_cage_size()

    def change_control_point_number(self, u, v, w):
        self._b_spline_body.change_control_point_number(u, v, w)
        self.async_upload_to_gpu()

    def change_control_point_order(self, order):
        self._b_spline_body.change_control_point_order(order)
        self.async_upload_to_gpu()

    @property
    def b_spline_body(self):
        return self._b_spline_body

    @property
    def is_normal_control_point_mode(self):
        return self._normal_control_mode

    @is_normal_control_point_mode.setter
    def is_normal_control_point_mode(self, v):
        self._normal_control_mode = v
        if self._normal_control_mode:
            self.clear_all_direct_control_point()
        self._control_point_position_vbo.async_update(self.get_control_point_data())

    def add_direct_control_point(self, intersect_point):
        if intersect_point is not None:
            self._direct_control_point = [np.append(intersect_point, 0)]
            self._control_point_position_vbo.async_update(self.get_control_point_data())

    def clear_dst_direct_control_point(self):
        self._direct_control_point = self._direct_control_point[:1]
        self._b_spline_body.save_control_point_position()
        self._control_point_position_vbo.async_update(self.get_control_point_data())

    def clear_all_direct_control_point(self):
        self._direct_control_point.clear()
        self._delta_for_dffd = [0, 0, 0]
        self._b_spline_body.save_control_point_position()
        self._control_point_position_vbo.async_update(self.get_control_point_data())

    @property
    def normal_control_mode(self):
        return self._normal_control_mode

    def move_direct_control_point(self, direction):
        self._b_spline_body.move_dffd(self._intersect_point_parameter, direction)
        target_point = np.append(self._direct_control_point[0][:3] + direction, 1)
        if len(self._direct_control_point) <= 1:
            self._direct_control_point.append(target_point)
        else:
            self._direct_control_point[1] = target_point
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._control_points_changed = True

    def move_direct_control_point_delta(self, direction):
        self._delta_for_dffd = [x + y for x, y in zip(self._delta_for_dffd, direction)]
        self._b_spline_body.move_dffd(self._intersect_point_parameter, self._delta_for_dffd)
        target_point = np.append(self._direct_control_point[0][:3] + self._delta_for_dffd, 1)
        if len(self._direct_control_point) <= 1:
            self._direct_control_point.append(target_point)
        else:
            self._direct_control_point[1] = target_point
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._control_points_changed = True

    def is_direct_control_point_selected(self):
        return len(self._direct_control_point) != 0

    def gl_select_point_gpu(self):
        if not self._need_select_point:
            return
        self._selected_counter_acbo.async_update(np.array([0], dtype=np.uint32))
        self._selected_counter_acbo.gl_sync()
        start_point, direction, triangle_number = self._select_argument
        self._intersect_result_vbo.gl_sync()
        self._select_point_program.use()
        glUniform1ui(0, int(triangle_number))
        glUniform3f(1, start_point[0], start_point[1], start_point[2])
        glUniform3f(2, direction[0], direction[1], direction[2])
        glDispatchCompute(*self.group_size)
        selected_triangle_number = self._selected_counter_acbo.get_value(ctypes.c_uint32)[0]
        res = self._intersect_result_vbo.get_value(ctypes.c_float, (selected_triangle_number, 4))
        closet = [0, 0, 0, 9999999]
        for r in res:
            if r[3] < closet[3]:
                closet = r
        self._need_select_point = False
        if closet[3] != 9999999 and closet[3] > 0:
            self.add_direct_control_point(start_point + closet[3] * direction)
            self._intersect_point_parameter = np.array(closet[:3], dtype='f4')

    def select_point_gpu(self, start_point, direction, triangle_number):
        self._need_select_point = True
        self._intersect_result_vbo.capacity = triangle_number * 16
        self._select_argument = [np.array(start_point).reshape((4,))[:3], np.array(direction).reshape((4,))[:3],
                                 triangle_number]

    @property
    def group_size(self):
        return [int(self._select_argument[2] / 512 + 1), 1, 1]

    def set_control_points(self, control_points):
        self._b_spline_body.change_control_points(control_points)
        self._control_point_position_vbo.async_update(self.get_control_point_data())
        self._control_point_for_sample_ubo.async_update(self._b_spline_body.get_control_point_for_sample())
        self._control_points_changed = True

    def get_control_point_str(self):
        return '_'.join([str(x) for x in self._b_spline_body.control_point_number])

    def get_bspline_body_size(self):
        return self._b_spline_body.step

    def get_modify_range(self):
        return self._b_spline_body.modify_range