int main(){ const uint64_t N = 1000; clock_t start_t = 0; clock_t end_t = 0; double *A_matrix, *B_matrix, *A_matrix_dev, *B_matrix_dev, *result_cpu, *result_gpu; TIMEIT_START; // allocate memmory on HOST A_matrix = (double*)malloc(N*N*sizeof(double)); B_matrix = (double*)malloc(N*N*sizeof(double)); result_cpu = (double*)malloc(N*N*sizeof(double)); result_gpu = (double*)malloc(N*N*sizeof(double)); TIMEIT_END(clock_t host_alloc_t); print_timeit(host_alloc_t,"allocating memory on host:"); fill_matrix(A_matrix,N); fill_matrix(B_matrix,N); //print_matrix(A_matrix,N); printf("\n"); TIMEIT_START; mult_matrix(A_matrix,B_matrix,result_cpu,N); TIMEIT_END(clock_t cpu_mult_t); print_timeit(cpu_mult_t,"multiplying matrix by a matrix with into another one:"); //print_matrix(result_cpu,N); TIMEIT_START; cudaMalloc((void **) &A_matrix_dev,N*N*sizeof(double)); cudaMalloc((void **) &B_matrix_dev,N*N*sizeof(double)); cudaMalloc((void **) &result_gpu,N*N*sizeof(double)); TIMEIT_END(clock_t gpu_alloc_t); print_timeit(gpu_alloc_t,"allocation memory on device:"); TIMEIT_START; cudaMemcpy(A_matrix_dev, A_matrix, N*N*sizeof(double), cudaMemcpyHostToDevice); cudaMemcpy(B_matrix_dev, B_matrix, N*N*sizeof(double), cudaMemcpyHostToDevice); TIMEIT_END(clock_t gpu_copy_t); print_timeit(gpu_copy_t,"allocation memory on device:"); free(A_matrix); free(B_matrix); free(result_cpu); free(result_gpu); return EXIT_SUCCESS; }
static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref) { #ifdef DEBUG_PRINT size_t size_expanded_prev, size_compacted_prev; BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); #endif #ifdef DEBUG_TIME TIMEIT_START(mesh_undo_compact); #endif um_arraystore_compact(um, um_ref); #ifdef DEBUG_TIME TIMEIT_END(mesh_undo_compact); #endif #ifdef DEBUG_PRINT { size_t size_expanded, size_compacted; BLI_array_store_at_size_calc_memory_usage(&um_arraystore.bs_stride, &size_expanded, &size_compacted); const double percent_total = size_expanded ? (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; size_t size_expanded_step = size_expanded - size_expanded_prev; size_t size_compacted_step = size_compacted - size_compacted_prev; const double percent_step = size_expanded_step ? (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0; printf("overall memory use: %.8f%% of expanded size\n", percent_total); printf("step memory use: %.8f%% of expanded size\n", percent_step); } #endif }
/** * A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations. */ void BLI_polyfill_calc_arena(const float (*coords)[2], const uint coords_tot, const int coords_sign, uint (*r_tris)[3], struct MemArena *arena) { PolyFill pf; PolyIndex *indices = BLI_memarena_alloc(arena, sizeof(*indices) * coords_tot); #ifdef DEBUG_TIME TIMEIT_START(polyfill2d); #endif polyfill_prepare(&pf, coords, coords_tot, coords_sign, r_tris, /* cache */ indices); #ifdef USE_KDTREE if (pf.coords_tot_concave) { pf.kdtree.nodes = BLI_memarena_alloc(arena, sizeof(*pf.kdtree.nodes) * pf.coords_tot_concave); pf.kdtree.nodes_map = memset( BLI_memarena_alloc(arena, sizeof(*pf.kdtree.nodes_map) * coords_tot), 0xff, sizeof(*pf.kdtree.nodes_map) * coords_tot); } else { pf.kdtree.totnode = 0; } #endif polyfill_calc(&pf); /* indices are no longer needed, * caller can clear arena */ #ifdef DEBUG_TIME TIMEIT_END(polyfill2d); #endif }
/** * Triangulates the given (convex or concave) simple polygon to a list of triangle vertices. * * \param coords: 2D coordinates describing vertices of the polygon, * in either clockwise or counterclockwise order. * \param coords_tot: Total points in the array. * \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations. * * \param r_tris: This array is filled in with triangle indices in clockwise order. * The length of the array must be ``coords_tot - 2``. * Indices are guaranteed to be assigned to unique triangles, with valid indices, * even in the case of degenerate input (self intersecting polygons, zero area ears... etc). */ void BLI_polyfill_calc(const float (*coords)[2], const uint coords_tot, const int coords_sign, uint (*r_tris)[3]) { PolyFill pf; PolyIndex *indices = BLI_array_alloca(indices, coords_tot); #ifdef DEBUG_TIME TIMEIT_START(polyfill2d); #endif polyfill_prepare(&pf, coords, coords_tot, coords_sign, r_tris, /* cache */ indices); #ifdef USE_KDTREE if (pf.coords_tot_concave) { pf.kdtree.nodes = BLI_array_alloca(pf.kdtree.nodes, pf.coords_tot_concave); pf.kdtree.nodes_map = memset(BLI_array_alloca(pf.kdtree.nodes_map, coords_tot), 0xff, sizeof(*pf.kdtree.nodes_map) * coords_tot); } else { pf.kdtree.totnode = 0; } #endif polyfill_calc(&pf); #ifdef DEBUG_TIME TIMEIT_END(polyfill2d); #endif }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const float min[3], const float max[3], const float viewnormal[3]) { if (!sds->tex || !sds->tex_shadow) { fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n"); return; } const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; GPUShader *shader = GPU_shader_get_builtin_shader( (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); return; } const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), 1.0f / fabsf(ob->size[2]) }; const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* setup smoke shader */ int soot_location = GPU_shader_get_uniform(shader, "soot_texture"); int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); int flame_location = GPU_shader_get_uniform(shader, "flame_texture"); int actcol_location = GPU_shader_get_uniform(shader, "active_color"); int stepsize_location = GPU_shader_get_uniform(shader, "step_size"); int densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); int invsize_location = GPU_shader_get_uniform(shader, "invsize"); int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); int min_location = GPU_shader_get_uniform(shader, "min"); GPU_shader_bind(shader); GPU_texture_bind(sds->tex, 0); GPU_shader_uniform_texture(shader, soot_location, sds->tex); GPU_texture_bind(sds->tex_shadow, 1); GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); GPUTexture *tex_spec = NULL; if (use_fire) { GPU_texture_bind(sds->tex_flame, 2); GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); tex_spec = create_flame_spectrum_texture(); GPU_texture_bind(tex_spec, 3); GPU_shader_uniform_texture(shader, spec_location, tex_spec); } float active_color[3] = { 0.9, 0.9, 0.9 }; float density_scale = 10.0f; if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) mul_v3_v3(active_color, sds->active_color); GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); GPU_shader_uniform_vector(shader, min_location, 3, 1, min); GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); /* setup slicing information */ const int max_slices = 256; const int max_points = max_slices * 12; VolumeSlicer slicer; copy_v3_v3(slicer.min, min); copy_v3_v3(slicer.max, max); copy_v3_v3(slicer.size, size); slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); /* setup buffer and draw */ int gl_depth = 0, gl_blend = 0; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); glDrawArrays(GL_TRIANGLES, 0, num_points); glDisableClientState(GL_VERTEX_ARRAY); #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif /* cleanup */ glBindBuffer(GL_ARRAY_BUFFER, 0); glDeleteBuffers(1, &vertex_buffer); GPU_texture_unbind(sds->tex); GPU_texture_unbind(sds->tex_shadow); if (use_fire) { GPU_texture_unbind(sds->tex_flame); GPU_texture_unbind(tex_spec); GPU_texture_free(tex_spec); } MEM_freeN(slicer.verts); GPU_shader_unbind(); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); } }
static void correctivesmooth_modifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, struct BMEditMesh *em) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC)); bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0; MDeformVert *dvert = NULL; int defgrp_index; modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index); /* if rest bind_coords not are defined, set them (only run during bind) */ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && /* signal to recalculate, whoever sets MUST also free bind coords */ (csmd->bind_coords_num == (unsigned int)-1)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); csmd->bind_coords_num = numVerts; BLI_assert(csmd->bind_coords != NULL); } if (UNLIKELY(use_only_smooth)) { smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); return; } if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) { modifier_setError(md, "Bind data required"); goto error; } /* If the number of verts has changed, the bind is invalid, so we do nothing */ if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { if (csmd->bind_coords_num != numVerts) { modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts); goto error; } } else { /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */ if (ob->type != OB_MESH) { modifier_setError(md, "Object is not a mesh"); goto error; } else { unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); if (me_numVerts != numVerts) { modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); goto error; } } } /* check to see if our deltas are still valid */ if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { const float (*rest_coords)[3]; bool is_rest_coords_alloc = false; if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* caller needs to do sanity check here */ csmd->bind_coords_num = numVerts; rest_coords = (const float (*)[3])csmd->bind_coords; } else { int me_numVerts; rest_coords = (const float (*)[3]) ((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) : BKE_mesh_vertexCos_get(ob->data, &me_numVerts)); BLI_assert((unsigned int)me_numVerts == numVerts); is_rest_coords_alloc = true; } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth_deltas); #endif calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts); #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth_deltas); #endif if (is_rest_coords_alloc) { MEM_freeN((void *)rest_coords); } } if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* this could be a check, but at this point it _must_ be valid */ BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache); } #ifdef DEBUG_TIME TIMEIT_START(corrective_smooth); #endif /* do the actual delta mush */ smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts); { unsigned int i; float (*tangent_spaces)[3][3]; /* calloc, since values are accumulated */ tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__); calc_tangent_spaces(dm, vertexCos, tangent_spaces); for (i = 0; i < numVerts; i++) { float delta[3]; #ifdef USE_TANGENT_CALC_INLINE calc_tangent_ortho(tangent_spaces[i]); #endif mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); add_v3_v3(vertexCos[i], delta); } MEM_freeN(tangent_spaces); } #ifdef DEBUG_TIME TIMEIT_END(corrective_smooth); #endif return; /* when the modifier fails to execute */ error: MEM_SAFE_FREE(csmd->delta_cache); csmd->delta_cache_num = 0; }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const float min[3], const float max[3], const float viewnormal[3]) { if (!sds->tex || !sds->tex_shadow) { fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n"); return; } const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); return; } GPUShader *fire_shader = NULL; if (use_fire) { fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE); if (!fire_shader) { fprintf(stderr, "Unable to create GLSL fire shader.\n"); return; } } const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), 1.0f / fabsf(ob->size[2]) }; const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* setup slicing information */ const int max_slices = 256; const int max_points = max_slices * 12; VolumeSlicer slicer; copy_v3_v3(slicer.min, min); copy_v3_v3(slicer.max, max); copy_v3_v3(slicer.size, size); slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); /* setup buffer and draw */ int gl_depth = 0, gl_blend = 0, gl_depth_write = 0; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write); glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); /* Draw fire separately (T47639). */ if (use_fire) { glBlendFunc(GL_ONE, GL_ONE); draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif MEM_freeN(slicer.verts); glDepthMask(gl_depth_write); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md; DerivedMesh *dm = derivedData; MDeformVert *dvert = NULL; MDeformWeight **dw, **tdw; int numVerts; float (*v_cos)[3] = NULL; /* The vertices coordinates. */ Object *obr = NULL; /* Our target object. */ int defgrp_index; float *tw = NULL; float *org_w = NULL; float *new_w = NULL; int *tidx, *indices = NULL; int numIdx = 0; int i; /* Flags. */ #if 0 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0; #endif #ifdef USE_TIMEIT TIMEIT_START(perf); #endif /* Get number of verts. */ numVerts = dm->getNumVerts(dm); /* Check if we can just return the original mesh. * Must have verts and therefore verts assigned to vgroups to do anything useful! */ if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase)) return dm; /* Get our target object. */ obr = wmd->proximity_ob_target; if (obr == NULL) return dm; /* Get vgroup idx from its name. */ defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); if (defgrp_index == -1) return dm; dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts); /* If no vertices were ever added to an object's vgroup, dvert might be NULL. * As this modifier never add vertices to vgroup, just return. */ if (!dvert) return dm; /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */ tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx"); tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw"); tdw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGProximity Modifier, tdw"); for (i = 0; i < numVerts; i++) { MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index); if (_dw) { tidx[numIdx] = i; tw[numIdx] = _dw->weight; tdw[numIdx++] = _dw; } } /* If no vertices found, return org data! */ if (numIdx == 0) { MEM_freeN(tidx); MEM_freeN(tw); MEM_freeN(tdw); return dm; } if (numIdx != numVerts) { indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices"); memcpy(indices, tidx, sizeof(int) * numIdx); org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w"); memcpy(org_w, tw, sizeof(float) * numIdx); dw = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGProximity Modifier, dw"); memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx); MEM_freeN(tw); MEM_freeN(tdw); } else { org_w = tw; dw = tdw; } new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w"); MEM_freeN(tidx); /* Get our vertex coordinates. */ v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos"); if (numIdx != numVerts) { /* XXX In some situations, this code can be up to about 50 times more performant * than simply using getVertCo for each affected vertex... */ float (*tv_cos)[3] = MEM_mallocN(sizeof(float[3]) * numVerts, "WeightVGProximity Modifier, tv_cos"); dm->getVertCos(dm, tv_cos); for (i = 0; i < numIdx; i++) copy_v3_v3(v_cos[i], tv_cos[indices[i]]); MEM_freeN(tv_cos); } else dm->getVertCos(dm, v_cos); /* Compute wanted distances. */ if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) { const float dist = get_ob2ob_distance(ob, obr); for (i = 0; i < numIdx; i++) new_w[i] = dist; } else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) { const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS); const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES); const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES); if (use_trgt_verts || use_trgt_edges || use_trgt_faces) { DerivedMesh *target_dm = obr->derivedFinal; bool free_target_dm = false; if (!target_dm) { if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT)) target_dm = CDDM_from_curve(obr); else if (obr->type == OB_MESH) { Mesh *me = (Mesh *)obr->data; if (me->edit_btmesh) target_dm = CDDM_from_editbmesh(me->edit_btmesh, false, false); else target_dm = CDDM_from_mesh(me); } free_target_dm = true; } /* We must check that we do have a valid target_dm! */ if (target_dm) { SpaceTransform loc2trgt; float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "dists_v") : NULL; float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL; float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL; BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, target_dm, &loc2trgt); for (i = 0; i < numIdx; i++) { new_w[i] = dists_v ? dists_v[i] : FLT_MAX; if (dists_e) new_w[i] = min_ff(dists_e[i], new_w[i]); if (dists_f) new_w[i] = min_ff(dists_f[i], new_w[i]); } if (free_target_dm) target_dm->release(target_dm); if (dists_v) MEM_freeN(dists_v); if (dists_e) MEM_freeN(dists_e); if (dists_f) MEM_freeN(dists_f); } /* Else, fall back to default obj2vert behavior. */ else { get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr); } } else { get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr); } } /* Map distances to weights. */ do_map(ob, new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type); /* Do masking. */ weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant, wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture, wmd->mask_tex_use_channel, wmd->mask_tex_mapping, wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name); /* Update vgroup. Note we never add nor remove vertices from vgroup here. */ weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f); /* If weight preview enabled... */ #if 0 /* XXX Currently done in mod stack :/ */ if (do_prev) DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices); #endif /* Freeing stuff. */ MEM_freeN(org_w); MEM_freeN(new_w); MEM_freeN(dw); if (indices) MEM_freeN(indices); MEM_freeN(v_cos); #ifdef USE_TIMEIT TIMEIT_END(perf); #endif /* Return the vgroup-modified mesh. */ return dm; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DecimateModifierData *dmd = (DecimateModifierData *) md; DerivedMesh *dm = derivedData, *result = NULL; BMesh *bm; bool calc_face_normal; float *vweights = NULL; #ifdef USE_TIMEIT TIMEIT_START(decim); #endif /* set up front so we dont show invalid info in the UI */ dmd->face_count = dm->getNumPolys(dm); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: if (dmd->percent == 1.0f) { return dm; } calc_face_normal = true; break; case MOD_DECIM_MODE_UNSUBDIV: if (dmd->iter == 0) { return dm; } calc_face_normal = false; break; case MOD_DECIM_MODE_DISSOLVE: if (dmd->angle == 0.0f) { return dm; } calc_face_normal = true; break; default: return dm; } if (dmd->face_count <= 3) { modifier_setError(md, "Modifier requires more than 3 input faces"); return dm; } if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) { if (dmd->defgrp_name[0]) { MDeformVert *dvert; int defgrp_index; modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index); if (dvert) { const unsigned int vert_tot = dm->getNumVerts(dm); unsigned int i; vweights = MEM_mallocN(vert_tot * sizeof(float), __func__); if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) { for (i = 0; i < vert_tot; i++) { const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } else { for (i = 0; i < vert_tot; i++) { const float f = defvert_find_weight(&dvert[i], defgrp_index); vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX; } } } } } bm = DM_to_bmesh(dm, calc_face_normal); switch (dmd->mode) { case MOD_DECIM_MODE_COLLAPSE: { const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0; BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate); break; } case MOD_DECIM_MODE_UNSUBDIV: { BM_mesh_decimate_unsubdivide(bm, dmd->iter); break; } case MOD_DECIM_MODE_DISSOLVE: { const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0; BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit); break; } } if (vweights) { MEM_freeN(vweights); } /* update for display only */ dmd->face_count = bm->totface; result = CDDM_from_bmesh(bm, false); BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */ BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL); BM_mesh_free(bm); #ifdef USE_TIMEIT TIMEIT_END(decim); #endif result->dirty = DM_DIRTY_NORMALS; return result; }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float UNUSED(base_scale), float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame) { int i, j, k, n, good_index; float d /*, d0 */ /* UNUSED */, dd, ds; float *points = NULL; int numpoints = 0; float cor[3] = {1.0f, 1.0f, 1.0f}; int gl_depth = 0, gl_blend = 0; /* draw slices of smoke is adapted from c++ code authored * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; /* Fragment program to calculate the view3d of smoke */ /* using 4 textures, density, shadow, flame and flame spectrum */ const char *shader_basic = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 temp, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, temp.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, darkness.r;\n" "MUL temp.g, temp.g, darkness.g;\n" "MUL temp.b, temp.b, darkness.b;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; /* color shader */ const char *shader_color = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* unpremultiply volume texture */ "RCP value.r, temp.a;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 value.r, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, value.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; GLuint prog; float size[3]; if (!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; } } } } tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); sub_v3_v3v3(size, max, min); /* maxx, maxy, maxz */ cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; /* minx, maxy, maxz */ cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; /* minx, miny, maxz */ cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; /* maxx, miny, maxz */ cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; /* maxx, maxy, minz */ cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; /* minx, maxy, minz */ cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; /* minx, miny, minz */ cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; /* maxx, miny, minz */ cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */ // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); /* find cube vertex that is closest to the viewer */ for (i = 0; i < 8; i++) { float x, y, z; x = cv[i][0] - viewnormal[0] * size[0] * 0.5f; y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; if ((x >= min[0]) && (x <= max[0]) && (y >= min[1]) && (y <= max[1]) && (z >= min[2]) && (z <= max[2])) { break; } } if (i >= 8) { /* fallback, avoid using buffer over-run */ i = 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &prog); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); /* set shader */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color); else glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic); /* cell spacing */ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0); else glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if (tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (tex_flame) { GPU_texture_bind(tex_flame, 2); GPU_texture_bind(tex_spec, 3); } if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]); cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]); cor[2] = (float)res[2] / (float)power_of_2_max_i(res[2]); } /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 * (a,b,c), the plane normal, are given by viewdir * d is the parameter along the view direction. the first d is given by * inserting previously found vertex into the plane equation */ /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */ ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(float) * 12 * 3, "smoke_points_preview"); while (1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if (dd * (float)n > ds) break; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(tmp_point2, viewnormal); // printf("my d: %f\n", d); /* intersect_edges returns the intersection points of all cube edges with * the given plane that lie within the cube */ numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { copy_v3_v3(p0, points); /* sort points to get a convex polygon */ for (i = 1; i < numpoints - 1; i++) { for (j = i + 1; j < numpoints; j++) { if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) { float tmp2[3]; copy_v3_v3(tmp2, &points[j * 3]); copy_v3_v3(&points[j * 3], &points[i * 3]); copy_v3_v3(&points[i * 3], tmp2); } } } /* render fire slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0], (points[i * 3 + 1] - min[1]) * cor[1] / size[1], (points[i * 3 + 2] - min[2]) * cor[2] / size[2]); glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); /* render smoke slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0], (points[i * 3 + 1] - min[1]) * cor[1] / size[1], (points[i * 3 + 2] - min[2]) * cor[2] / size[2]); glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); } n++; } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif if (tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if (tex_flame) { GPU_texture_unbind(tex_flame); GPU_texture_unbind(tex_spec); } GPU_texture_free(tex_spec); free(spec_data); free(spec_pixels); if (GLEW_ARB_fragment_program) { glDisable(GL_FRAGMENT_PROGRAM_ARB); glDeleteProgramsARB(1, &prog); } MEM_freeN(points); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } }
/** * \note This function sets the edge indices to invalid values. */ void BM_mesh_beautify_fill( BMesh *bm, BMEdge **edge_array, const int edge_array_len, const short flag, const short method, const short oflag_edge, const short oflag_face) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__); BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP); int i; #ifdef DEBUG_TIME TIMEIT_START(beautify_fill); #endif eheap = BLI_heap_new_ex((uint)edge_array_len); eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__); /* build heap */ for (i = 0; i < edge_array_len; i++) { BMEdge *e = edge_array[i]; const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } else { eheap_table[i] = NULL; } BM_elem_index_set(e, i); /* set_dirty */ } bm->elem_index_dirty |= BM_EDGE; while (BLI_heap_is_empty(eheap) == false) { BMEdge *e = BLI_heap_popmin(eheap); i = BM_elem_index_get(e); eheap_table[i] = NULL; BLI_assert(BM_edge_face_count_is_equal(e, 2)); e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS); BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2)); if (LIKELY(e)) { GSet *e_state_set = edge_state_arr[i]; /* add the new state into the set so we don't move into this state again * note: we could add the previous state too but this isn't essential) * for avoiding eternal loops */ EdRotState *e_state = BLI_mempool_alloc(edge_state_pool); erot_state_current(e, e_state); if (UNLIKELY(e_state_set == NULL)) { edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */ } BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false); BLI_gset_insert(e_state_set, e_state); // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)); /* maintain the index array */ edge_array[i] = e; BM_elem_index_set(e, i); /* recalculate faces connected on the heap */ bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr, (const BMEdge **)edge_array, edge_array_len, flag, method); /* update flags */ if (oflag_edge) { BMO_edge_flag_enable(bm, e, oflag_edge); } if (oflag_face) { BMO_face_flag_enable(bm, e->l->f, oflag_face); BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face); } } } BLI_heap_free(eheap, NULL); MEM_freeN(eheap_table); for (i = 0; i < edge_array_len; i++) { if (edge_state_arr[i]) { BLI_gset_free(edge_state_arr[i], NULL); } } MEM_freeN(edge_state_arr); BLI_mempool_destroy(edge_state_pool); #ifdef DEBUG_TIME TIMEIT_END(beautify_fill); #endif }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPUTexture *tex, const float min[3], const float max[3], const int res[3], float dx, float UNUSED(base_scale), const float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame) { const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), 1.0f / fabsf(ob->size[2])}; int i, j, k, n, good_index; float d /*, d0 */ /* UNUSED */, dd, ds; float (*points)[3] = NULL; int numpoints = 0; float cor[3] = {1.0f, 1.0f, 1.0f}; int gl_depth = 0, gl_blend = 0; int use_fire = (sds->active_fields & SM_ACTIVE_FIRE); /* draw slices of smoke is adapted from c++ code authored * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; GPUProgram *smoke_program; int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE; float size[3]; if (!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; } } } } tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); #undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE sub_v3_v3v3(size, max, min); /* maxx, maxy, maxz */ cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; /* minx, maxy, maxz */ cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; /* minx, miny, maxz */ cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; /* maxx, miny, maxz */ cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; /* maxx, maxy, minz */ cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; /* minx, maxy, minz */ cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; /* minx, miny, minz */ cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; /* maxx, miny, minz */ cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */ // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); /* find cube vertex that is closest to the viewer */ for (i = 0; i < 8; i++) { float x, y, z; x = cv[i][0] - viewnormal[0] * size[0] * 0.5f; y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; if ((x >= min[0]) && (x <= max[0]) && (y >= min[1]) && (y <= max[1]) && (z >= min[2]) && (z <= max[2])) { break; } } if (i >= 8) { /* fallback, avoid using buffer over-run */ i = 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); smoke_program = GPU_shader_get_builtin_program(progtype); if (smoke_program) { GPU_program_bind(smoke_program); /* cell spacing */ GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0); else GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if (tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (tex_flame) { GPU_texture_bind(tex_flame, 2); GPU_texture_bind(tex_spec, 3); } if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]); cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]); cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]); } cor[0] /= size[0]; cor[1] /= size[1]; cor[2] /= size[2]; /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 * (a,b,c), the plane normal, are given by viewdir * d is the parameter along the view direction. the first d is given by * inserting previously found vertex into the plane equation */ /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */ ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview"); while (1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if (dd * (float)n > ds) break; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(tmp_point2, viewnormal); // printf("my d: %f\n", d); /* intersect_edges returns the intersection points of all cube edges with * the given plane that lie within the cube */ numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { copy_v3_v3(p0, points[0]); /* sort points to get a convex polygon */ for (i = 1; i < numpoints - 1; i++) { for (j = i + 1; j < numpoints; j++) { if (!convex(p0, viewnormal, points[j], points[i])) { swap_v3_v3(points[i], points[j]); } } } /* render fire slice */ if (use_fire) { if (GLEW_VERSION_1_4) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE); else glBlendFunc(GL_SRC_ALPHA, GL_ONE); GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i][0] - min[0]) * cor[0], (points[i][1] - min[1]) * cor[1], (points[i][2] - min[2]) * cor[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); } glEnd(); } /* render smoke slice */ if (GLEW_VERSION_1_4) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i][0] - min[0]) * cor[0], (points[i][1] - min[1]) * cor[1], (points[i][2] - min[2]) * cor[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); } glEnd(); } n++; } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif if (tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if (tex_flame) { GPU_texture_unbind(tex_flame); GPU_texture_unbind(tex_spec); } GPU_texture_free(tex_spec); free(spec_data); free(spec_pixels); if (smoke_program) GPU_program_unbind(smoke_program); MEM_freeN(points); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); } }