From: hgn Date: Tue, 12 Apr 2022 06:06:18 +0000 (+0100) Subject: python interface revision X-Git-Url: https://harrygodden.com/git/?p=convexer.git;a=commitdiff_plain;h=e6de1b2b1d8456cdebd75ccc7640bc0a5740a3b0 python interface revision --- diff --git a/__init__.py b/__init__.py index 544d770..fc20f05 100644 --- a/__init__.py +++ b/__init__.py @@ -105,7 +105,7 @@ class cxr_vmf_context(Structure): # Public API libcxr_decompose = extern( "cxr_decompose", \ - [POINTER(cxr_static_mesh)], c_void_p ) + [POINTER(cxr_static_mesh), POINTER(c_int32)], c_void_p ) libcxr_free_world = extern( "cxr_free_world", [c_void_p], None ) libcxr_write_test_data = extern( "cxr_write_test_data", \ @@ -250,15 +250,16 @@ def cxr_draw(): debug_gpu_shader.bind() - gpu.state.depth_test_set('LESS_EQUAL') gpu.state.depth_mask_set(False) gpu.state.line_width_set(1.5) gpu.state.face_culling_set('BACK') + gpu.state.depth_test_set('NONE') gpu.state.blend_set('ALPHA') if debug_gpu_lines != None: debug_gpu_lines.draw(debug_gpu_shader) + gpu.state.depth_test_set('LESS_EQUAL') gpu.state.blend_set('ADDITIVE') if debug_gpu_mesh != None: debug_gpu_mesh.draw(debug_gpu_shader) @@ -813,6 +814,10 @@ def material_info(mat): return info def mesh_cxr_format(obj): + orig_state = obj.mode + if orig_state != 'OBJECT': + bpy.ops.object.mode_set(mode='OBJECT') + dgraph = bpy.context.evaluated_depsgraph_get() data = obj.evaluated_get(dgraph).data @@ -885,6 +890,7 @@ def mesh_cxr_format(obj): mesh.loop_count = len(data.loops) mesh.material_count = len(obj.material_slots) + bpy.ops.object.mode_set(mode=orig_state) return mesh class CXR_WRITE_VMF(bpy.types.Operator): @@ -909,8 +915,8 @@ class CXR_WRITE_VMF(bpy.types.Operator): os.makedirs( model_dir, exist_ok=True ) # States + libcxr_reset_debug_lines() material_info.references = set() - output_vmf = F"{directory}/{settings.project_name}.vmf" with vdf_structure(output_vmf) as m: @@ -995,7 +1001,7 @@ class CXR_WRITE_VMF(bpy.types.Operator): nonlocal m baked = mesh_cxr_format( brush[0] ) - world = libcxr_decompose.call( baked ) + world = libcxr_decompose.call( baked, None ) if world == None: return False @@ -1013,7 +1019,8 @@ class CXR_WRITE_VMF(bpy.types.Operator): # World geometry for brush in _collect.geo: if not _buildsolid( brush[0], brush[1] ): - print( "error" ) + libcxr_batch_debug_lines() + scene_redraw() return {'CANCELLED'} m.edon() @@ -1034,6 +1041,8 @@ class CXR_WRITE_VMF(bpy.types.Operator): else: m.kv( kv[0], str(kv[2]) ) if not _buildsolid( obj, ctx ): + libcxr_batch_debug_lines() + scene_redraw() return {'CANCELLED'} m.edon() @@ -1069,22 +1078,61 @@ class CXR_DEV_OPERATOR(bpy.types.Operator): class CXR_PREVIEW_OPERATOR(bpy.types.Operator): bl_idname="convexer.preview" - bl_label="Preview" + bl_label="Preview Brushes" + + LASTERR = None + RUNNING = False def execute(_,context): - libcxr_use() + return {'FINISHED'} + + def modal(_,context,event): + global debug_gpu_mesh + static = _.__class__ + + if event.type == 'ESC': + libcxr_reset_debug_lines() + libcxr_batch_debug_lines() + debug_gpu_mesh = None + scene_redraw() + + static.RUNNING = False + return {'FINISHED'} + return {'PASS_THROUGH'} + + def invoke(_,context,event): + global debug_gpu_shader, debug_gpu_mesh + static = _.__class__ + static.LASTERR = None + + libcxr_use() libcxr_reset_debug_lines() mesh_src = mesh_cxr_format(context.active_object) - world = libcxr_decompose.call( mesh_src ) - - global debug_gpu_shader, debug_gpu_mesh + + err = c_int32(0) + world = libcxr_decompose.call( mesh_src, pointer(err) ) if world == None: debug_gpu_mesh = None libcxr_batch_debug_lines() - return {'CANCELLED'} + scene_redraw() + + static.LASTERR = ["There is no error", \ + "Non-Manifold",\ + "Bad-Manifold",\ + "No-Candidate",\ + "Internal-Fail",\ + "Non-Coplanar",\ + "Non-Convex Polygon"]\ + [err.value] + + if static.RUNNING: + return {'CANCELLED'} + else: + context.window_manager.modal_handler_add(_) + return {'RUNNING_MODAL'} ptrpreview = libcxr_world_preview.call( world ) preview = ptrpreview[0] @@ -1107,10 +1155,36 @@ class CXR_PREVIEW_OPERATOR(bpy.types.Operator): libcxr_free_tri_mesh.call( ptrpreview ) libcxr_free_world.call( world ) - libcxr_batch_debug_lines() scene_redraw() - return {'FINISHED'} + + if static.RUNNING: + return {'CANCELLED'} + if not static.RUNNING: + static.RUNNING = True + context.window_manager.modal_handler_add(_) + return {'RUNNING_MODAL'} + +class CXR_VIEW3D( bpy.types.Panel ): + bl_idname = "VIEW3D_PT_convexer" + bl_label = "Convexer" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "Convexer" + + @classmethod + def poll(cls, context): + return (context.object is not None) + + def draw(_, context): + layout = _.layout + row = layout.row() + row.scale_y = 2 + row.operator("convexer.preview") + + if CXR_PREVIEW_OPERATOR.LASTERR != None: + box = layout.box() + box.label(text=CXR_PREVIEW_OPERATOR.LASTERR, icon='ERROR') class CXR_INTERFACE(bpy.types.Panel): bl_label="Convexer" @@ -1587,7 +1661,8 @@ classes = [ CXR_RELOAD, CXR_DEV_OPERATOR, CXR_INTERFACE, \ CXR_WRITE_VMF, CXR_MATERIAL_PANEL, CXR_IMAGE_SETTINGS,\ CXR_MODEL_SETTINGS, CXR_ENTITY_SETTINGS, CXR_CUBEMAP_SETTINGS,\ CXR_LIGHT_SETTINGS, CXR_SCENE_SETTINGS, CXR_DETECT_COMPILERS,\ - CXR_ENTITY_PANEL, CXR_LIGHT_PANEL, CXR_PREVIEW_OPERATOR ] + CXR_ENTITY_PANEL, CXR_LIGHT_PANEL, CXR_PREVIEW_OPERATOR,\ + CXR_VIEW3D ] def register(): global debug_draw_handler, vmt_param_dynamic_class diff --git a/cxr/cxr.h b/cxr/cxr.h index 5a4542a..bb904c4 100644 --- a/cxr/cxr.h +++ b/cxr/cxr.h @@ -107,7 +107,7 @@ typedef struct cxr_tri_mesh cxr_tri_mesh; /* Main convexer algorithms */ /* Convex decomp from mesh */ -CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ); +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode ); CXR_API void cxr_free_world( cxr_world *world ); CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world ); CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ); @@ -276,7 +276,9 @@ enum cxr_soliderr k_soliderr_non_manifold, k_soliderr_bad_manifold, k_soliderr_no_solids, - k_soliderr_degenerate_implicit + k_soliderr_degenerate_implicit, + k_soliderr_non_coplanar_vertices, + k_soliderr_non_convex_poly }; /* @@ -1556,6 +1558,19 @@ static cxr_mesh *cxr_pull_best_solid( #ifdef CXR_DEBUG cxr_log( "non-manifold edges are in the mesh: " "implicit internal geometry does not have full support\n" ); + + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + + for( int i=0; iabloops.count; i++ ) + { + cxr_loop *lp = &mesh->loops[i]; + + if( lp->poly_left == -1 || lp->poly_right == -1 ) + { + cxr_edge *edge = &mesh->edges[lp->edge_index]; + cxr_debug_line( verts[edge->i0], verts[edge->i1], colour_error ); + } + } #endif *err = k_soliderr_non_manifold; return NULL; @@ -1948,6 +1963,40 @@ static cxr_mesh *cxr_to_internal_format( return mesh; } +static int cxr_poly_convex( cxr_mesh *mesh, cxr_polygon *poly ) +{ + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + + for( int i=0; iloop_total; i++ ) + { + int li0 = poly->loop_start + i, + li1 = poly->loop_start + cxr_range( i+1, poly->loop_total ), + li2 = poly->loop_start + cxr_range( i+2, poly->loop_total ); + int i0 = mesh->loops[li0].index, + i1 = mesh->loops[li1].index, + i2 = mesh->loops[li2].index; + + v3f v0, v1, c; + + v3_sub( verts[i1], verts[i0], v0 ); + v3_sub( verts[i2], verts[i1], v1 ); + + v3_cross( v0, v1, c ); + if( v3_dot( c, poly->normal ) <= 0.0 ) + { +#if CXR_DEBUG + cxr_debug_line( verts[i0], verts[i1], colour_error ); + cxr_debug_box( verts[i1], 0.1, colour_error ); + cxr_debug_line( verts[i1], verts[i2], colour_error ); + cxr_debug_line( verts[i1], poly->center, colour_error ); +#endif + return 0; + } + } + + return 1; +} + static int cxr_solid_checkerr( cxr_mesh *mesh ) { v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); @@ -2113,8 +2162,9 @@ CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ) free( mesh ); } -CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src, i32 *perrcode ) { + u32 error = 0x00; cxr_world *world = malloc( sizeof(*world) ); /* Copy data to internal formats */ @@ -2164,12 +2214,20 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) if( edge->freestyle ) goto displacement; } + + if( !cxr_poly_convex( pinf->pmesh, poly ) ) + { + pinf->invalid = 1; + invalid_count ++; + error = k_soliderr_non_convex_poly; + } } if( cxr_solid_checkerr( pinf->pmesh ) ) { pinf->invalid = 1; invalid_count ++; + error = k_soliderr_non_coplanar_vertices; } continue; @@ -2182,7 +2240,6 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) * Main convex decomp algorithm */ int sources_count = world->absolids.count; - u32 error = 0x00; if( invalid_count ) goto decomp_failed; @@ -2228,6 +2285,10 @@ CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) decomp_failed: cxr_log( "Error %d\n", error ); cxr_free_world( world ); + + if( perrcode ) + *perrcode = error; + return NULL; }