static bool kdtree2d_isect_tri_recursive(
        const struct KDTree2D *tree,
        const unsigned int tri_index[3],
        const float       *tri_coords[3],
        const float        tri_center[2],
        const struct KDRange2D bounds[2],
        const KDTreeNode2D *node)
{
	const float *co = tree->coords[node->index];

	/* bounds then triangle intersect */
	if ((node->flag & KDNODE_FLAG_REMOVED) == 0) {
		/* bounding box test first */
		if ((co[0] >= bounds[0].min) &&
		    (co[0] <= bounds[0].max) &&
		    (co[1] >= bounds[1].min) &&
		    (co[1] <= bounds[1].max))
		{
			if ((span_tri_v2_sign(tri_coords[0], tri_coords[1], co) != CONCAVE) &&
			    (span_tri_v2_sign(tri_coords[1], tri_coords[2], co) != CONCAVE) &&
			    (span_tri_v2_sign(tri_coords[2], tri_coords[0], co) != CONCAVE))
			{
				if (!ELEM(node->index, tri_index[0], tri_index[1], tri_index[2])) {
					return true;
				}
			}
		}
	}

#define KDTREE2D_ISECT_TRI_RECURSE_NEG \
	(((node->neg != KDNODE_UNSET) && (co[node->axis] > bounds[node->axis].min)) &&   \
	  (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
	                                &tree->nodes[node->neg])))
#define KDTREE2D_ISECT_TRI_RECURSE_POS \
	(((node->pos != KDNODE_UNSET) && (co[node->axis] < bounds[node->axis].max)) &&   \
	  (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
	                                &tree->nodes[node->pos])))

	if (tri_center[node->axis] > co[node->axis]) {
		if (KDTREE2D_ISECT_TRI_RECURSE_POS) {
			return true;
		}
		if (KDTREE2D_ISECT_TRI_RECURSE_NEG) {
			return true;
		}
	}
	else {
		if (KDTREE2D_ISECT_TRI_RECURSE_NEG) {
			return true;
		}
		if (KDTREE2D_ISECT_TRI_RECURSE_POS) {
			return true;
		}
	}

#undef KDTREE2D_ISECT_TRI_RECURSE_NEG
#undef KDTREE2D_ISECT_TRI_RECURSE_POS

	BLI_assert(node->index != KDNODE_UNSET);

	return false;
}
Example #2
0
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
{
	Cloth *cloth = clmd->clothObject;
	ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
	unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
	unsigned int i = 0;
	unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
	unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
	unsigned int numpolys = (unsigned int)dm->getNumPolys(dm);
	float shrink_factor;
	const MEdge *medge = dm->getEdgeArray(dm);
	const MPoly *mpoly = dm->getPolyArray(dm);
	const MLoop *mloop = dm->getLoopArray(dm);
	int index2 = 0; // our second vertex index
	LinkNodePair *edgelist;
	EdgeSet *edgeset = NULL;
	LinkNode *search = NULL, *search2 = NULL;
	
	// error handling
	if ( numedges==0 )
		return 0;

	/* NOTE: handling ownership of springs and edgeset is quite sloppy
	 * currently they are never initialized but assert just to be sure */
	BLI_assert(cloth->springs == NULL);
	BLI_assert(cloth->edgeset == NULL);

	cloth->springs = NULL;
	cloth->edgeset = NULL;

	edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
	
	if (!edgelist)
		return 0;

	// structural springs
	for ( i = 0; i < numedges; i++ ) {
		spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );

		if ( spring ) {
			spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2);
			if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) {
				// handle sewing (loose edges will be pulled together)
				spring->restlen = 0.0f;
				spring->stiffness = 1.0f;
				spring->type = CLOTH_SPRING_TYPE_SEWING;
			}
			else {
				shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
				spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
				spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
				spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;

				clmd->sim_parms->avg_spring_len += spring->restlen;
				cloth->verts[spring->ij].avg_spring_len += spring->restlen;
				cloth->verts[spring->kl].avg_spring_len += spring->restlen;
				cloth->verts[spring->ij].spring_count++;
				cloth->verts[spring->kl].spring_count++;
				struct_springs_real++;
			}

			spring->flags = 0;
			struct_springs++;
			
			BLI_linklist_prepend ( &cloth->springs, spring );
		}
		else {
			cloth_free_errorsprings(cloth, edgelist);
			return 0;
		}
	}

	if (struct_springs_real > 0)
		clmd->sim_parms->avg_spring_len /= struct_springs_real;
	
	for (i = 0; i < mvert_num; i++) {
		if (cloth->verts[i].spring_count > 0)
			cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
	}

	// shear springs
	for (i = 0; i < numpolys; i++) {
		/* triangle faces already have shear springs due to structural geometry */
		if (mpoly[i].totloop == 4) {
			int j;

			for (j = 0; j != 2; j++) {
				spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");

				if (!spring) {
					cloth_free_errorsprings(cloth, edgelist);
					return 0;
				}

				spring_verts_ordered_set(
				        spring,
				        mloop[mpoly[i].loopstart + (j + 0)].v,
				        mloop[mpoly[i].loopstart + (j + 2)].v);

				shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
				spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
				spring->type = CLOTH_SPRING_TYPE_SHEAR;
				spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;

				BLI_linklist_append(&edgelist[spring->ij], spring);
				BLI_linklist_append(&edgelist[spring->kl], spring);

				shear_springs++;

				BLI_linklist_prepend(&cloth->springs, spring);
			}
		}
	}

	edgeset = BLI_edgeset_new_ex(__func__, numedges);
	cloth->edgeset = edgeset;

	if (numpolys) {
		// bending springs
		search2 = cloth->springs;
		for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) {
			if ( !search2 )
				break;

			tspring2 = search2->link;
			search = edgelist[tspring2->kl].list;
			while ( search ) {
				tspring = search->link;
				index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );

				// check for existing spring
				// check also if startpoint is equal to endpoint
				if ((index2 != tspring2->ij) &&
				    !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
				{
					spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );

					if (!spring) {
						cloth_free_errorsprings(cloth, edgelist);
						return 0;
					}

					spring_verts_ordered_set(spring, tspring2->ij, index2);
					shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
					spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
					spring->type = CLOTH_SPRING_TYPE_BENDING;
					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
					BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
					bend_springs++;

					BLI_linklist_prepend ( &cloth->springs, spring );
				}
				search = search->next;
			}
			search2 = search2->next;
		}
	}
	else if (struct_springs > 2) {
		if (G.debug_value != 1112) {
			search = cloth->springs;
			search2 = search->next;
			while (search && search2) {
				tspring = search->link;
				tspring2 = search2->link;
				
				if (tspring->ij == tspring2->kl) {
					spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
					
					if (!spring) {
						cloth_free_errorsprings(cloth, edgelist);
						return 0;
					}
					
					spring->ij = tspring2->ij;
					spring->kl = tspring->ij;
					spring->mn = tspring->kl;
					spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
					spring->type = CLOTH_SPRING_TYPE_BENDING_ANG;
					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
					bend_springs++;
					
					BLI_linklist_prepend ( &cloth->springs, spring );
				}
				
				search = search->next;
				search2 = search2->next;
			}
		}
		else {
			/* bending springs for hair strands */
			/* The current algorightm only goes through the edges in order of the mesh edges list	*/
			/* and makes springs between the outer vert of edges sharing a vertice. This works just */
			/* fine for hair, but not for user generated string meshes. This could/should be later	*/
			/* extended to work with non-ordered edges so that it can be used for general "rope		*/
			/* dynamics" without the need for the vertices or edges to be ordered through the length*/
			/* of the strands. -jahka */
			search = cloth->springs;
			search2 = search->next;
			while (search && search2) {
				tspring = search->link;
				tspring2 = search2->link;
				
				if (tspring->ij == tspring2->kl) {
					spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
					
					if (!spring) {
						cloth_free_errorsprings(cloth, edgelist);
						return 0;
					}
					
					spring->ij = tspring2->ij;
					spring->kl = tspring->kl;
					spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
					spring->type = CLOTH_SPRING_TYPE_BENDING;
					spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
					bend_springs++;
					
					BLI_linklist_prepend ( &cloth->springs, spring );
				}
				
				search = search->next;
				search2 = search2->next;
			}
		}
		
		cloth_hair_update_bending_rest_targets(clmd);
	}
	
	/* note: the edges may already exist so run reinsert */

	/* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
	for (i = 0; i < numedges; i++) { /* struct springs */
		BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
	}

	for (i = 0; i < numpolys; i++) { /* edge springs */
		if (mpoly[i].totloop == 4) {
			BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v);
			BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v);
		}
	}
	
	
	cloth->numsprings = struct_springs + shear_springs + bend_springs;
	
	cloth_free_edgelist(edgelist, mvert_num);

#if 0
	if (G.debug_value > 0)
		printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len);
#endif

	return 1;

} /* cloth_build_springs */
Example #3
0
static int bake(
        Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
        const eScenePassType pass_type, const int pass_filter, const int margin,
        const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
        const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
        const float cage_extrusion, const int normal_space, const eBakeNormalSwizzle normal_swizzle[],
        const char *custom_cage, const char *filepath, const int width, const int height,
        const char *identifier, ScrArea *sa, const char *uv_layer)
{
	int op_result = OPERATOR_CANCELLED;
	bool ok = false;

	Object *ob_cage = NULL;

	BakeHighPolyData *highpoly = NULL;
	int tot_highpoly = 0;

	char restrict_flag_low = ob_low->restrictflag;
	char restrict_flag_cage = 0;

	Mesh *me_low = NULL;
	Mesh *me_cage = NULL;

	MultiresModifierData *mmd_low = NULL;
	int mmd_flags_low = 0;

	float *result = NULL;

	BakePixel *pixel_array_low = NULL;
	BakePixel *pixel_array_high = NULL;

	const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
	const bool is_noncolor = is_noncolor_pass(pass_type);
	const int depth = RE_pass_depth(pass_type);

	BakeImages bake_images = {NULL};

	size_t num_pixels;
	int tot_materials;

	RE_bake_engine_set_engine_parameters(re, bmain, scene);

	if (!RE_bake_has_engine(re)) {
		BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
		goto cleanup;
	}

	tot_materials = ob_low->totcol;

	if (uv_layer && uv_layer[0] != '\0') {
		Mesh *me = (Mesh *)ob_low->data;
		if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) {
			BKE_reportf(reports, RPT_ERROR,
			            "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2);
			goto cleanup;
		}
	}

	if (tot_materials == 0) {
		if (is_save_internal) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found, add a material or bake to an external file");

			goto cleanup;
		}
		else if (is_split_materials) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found, add a material or bake without the Split Materials option");

			goto cleanup;
		}
		else {
			/* baking externally without splitting materials */
			tot_materials = 1;
		}
	}

	/* we overallocate in case there is more materials than images */
	bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)");
	bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)");

	build_image_lookup(bmain, ob_low, &bake_images);

	if (is_save_internal) {
		num_pixels = initialize_internal_images(&bake_images, reports);

		if (num_pixels == 0) {
			goto cleanup;
		}
	}
	else {
		/* when saving extenally always use the size specified in the UI */

		num_pixels = (size_t)width * (size_t)height * bake_images.size;

		for (int i = 0; i < bake_images.size; i++) {
			bake_images.data[i].width = width;
			bake_images.data[i].height = height;
			bake_images.data[i].offset = (is_split_materials ? num_pixels : 0);
			bake_images.data[i].image = NULL;
		}

		if (!is_split_materials) {
			/* saving a single image */
			for (int i = 0; i < tot_materials; i++) {
				bake_images.lookup[i] = 0;
			}
		}
	}

	if (is_selected_to_active) {
		CollectionPointerLink *link;
		tot_highpoly = 0;

		for (link = selected_objects->first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			tot_highpoly ++;
		}

		if (is_cage && custom_cage[0] != '\0') {
			ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2);

			if (ob_cage == NULL || ob_cage->type != OB_MESH) {
				BKE_report(reports, RPT_ERROR, "No valid cage object");
				goto cleanup;
			}
			else {
				restrict_flag_cage = ob_cage->restrictflag;
				ob_cage->restrictflag |= OB_RESTRICT_RENDER;
			}
		}
	}

	pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
	pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
	result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");

	/* for multires bake, use linear UV subdivision to match low res UVs */
	if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && !is_selected_to_active) {
		mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires);
		if (mmd_low) {
			mmd_flags_low = mmd_low->flags;
			mmd_low->flags |= eMultiresModifierFlag_PlainUv;
		}
	}

	/* get the mesh as it arrives in the renderer */
	me_low = bake_mesh_new_from_object(bmain, scene, ob_low);

	/* populate the pixel array with the face data */
	if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
		RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer);
	/* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh)  */

	if (is_selected_to_active) {
		CollectionPointerLink *link;
		ModifierData *md, *nmd;
		ListBase modifiers_tmp, modifiers_original;
		int i = 0;

		/* prepare cage mesh */
		if (ob_cage) {
			me_cage = bake_mesh_new_from_object(bmain, scene, ob_cage);
			if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) {
				BKE_report(reports, RPT_ERROR,
				           "Invalid cage object, the cage mesh must have the same number "
				           "of faces as the active object");
				goto cleanup;
			}
		}
		else if (is_cage) {
			modifiers_original = ob_low->modifiers;
			BLI_listbase_clear(&modifiers_tmp);

			for (md = ob_low->modifiers.first; md; md = md->next) {
				/* Edge Split cannot be applied in the cage,
				 * the cage is supposed to have interpolated normals
				 * between the faces unless the geometry is physically
				 * split. So we create a copy of the low poly mesh without
				 * the eventual edge split.*/

				if (md->type == eModifierType_EdgeSplit)
					continue;

				nmd = modifier_new(md->type);
				BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
				modifier_copyData(md, nmd);
				BLI_addtail(&modifiers_tmp, nmd);
			}

			/* temporarily replace the modifiers */
			ob_low->modifiers = modifiers_tmp;

			/* get the cage mesh as it arrives in the renderer */
			me_cage = bake_mesh_new_from_object(bmain, scene, ob_low);
			RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
		}

		highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects");

		/* populate highpoly array */
		for (link = selected_objects->first; link; link = link->next) {
			TriangulateModifierData *tmd;
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			/* initialize highpoly_data */
			highpoly[i].ob = ob_iter;
			highpoly[i].restrict_flag = ob_iter->restrictflag;

			/* triangulating so BVH returns the primitive_id that will be used for rendering */
			highpoly[i].tri_mod = ED_object_modifier_add(
			        reports, bmain, scene, highpoly[i].ob,
			        "TmpTriangulate", eModifierType_Triangulate);
			tmd = (TriangulateModifierData *)highpoly[i].tri_mod;
			tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
			tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;

			highpoly[i].me = bake_mesh_new_from_object(bmain, scene, highpoly[i].ob);
			highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;

			/* lowpoly to highpoly transformation matrix */
			copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
			invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);

			highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat);

			i++;
		}

		BLI_assert(i == tot_highpoly);

		ob_low->restrictflag |= OB_RESTRICT_RENDER;

		/* populate the pixel arrays with the corresponding face data for each high poly object */
		if (!RE_bake_pixels_populate_from_objects(
		            me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
		            cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage))
		{
			BKE_report(reports, RPT_ERROR, "Error handling selected objects");
			goto cage_cleanup;
		}

		/* the baking itself */
		for (i = 0; i < tot_highpoly; i++) {
			ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
			                    num_pixels, depth, pass_type, pass_filter, result);
			if (!ok) {
				BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
				goto cage_cleanup;
			}
		}

cage_cleanup:
		/* reverting data back */
		if ((ob_cage == NULL) && is_cage) {
			ob_low->modifiers = modifiers_original;

			while ((md = BLI_pophead(&modifiers_tmp))) {
				modifier_free(md);
			}
		}

		if (!ok) {
			goto cleanup;
		}
	}
	else {
		/* make sure low poly renders */
		ob_low->restrictflag &= ~OB_RESTRICT_RENDER;

		if (RE_bake_has_engine(re)) {
			ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result);
		}
		else {
			BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
			goto cleanup;
		}
	}

	/* normal space conversion
	 * the normals are expected to be in world space, +X +Y +Z */
	if (ok && pass_type == SCE_PASS_NORMAL) {
		switch (normal_space) {
			case R_BAKE_SPACE_WORLD:
			{
				/* Cycles internal format */
				if ((normal_swizzle[0] == R_BAKE_POSX) &&
				    (normal_swizzle[1] == R_BAKE_POSY) &&
				    (normal_swizzle[2] == R_BAKE_POSZ))
				{
					break;
				}
				else {
					RE_bake_normal_world_to_world(pixel_array_low, num_pixels,  depth, result, normal_swizzle);
				}
				break;
			}
			case R_BAKE_SPACE_OBJECT:
			{
				RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle);
				break;
			}
			case R_BAKE_SPACE_TANGENT:
			{
				if (is_selected_to_active) {
					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat);
				}
				else {
					/* from multiresolution */
					Mesh *me_nores = NULL;
					ModifierData *md = NULL;
					int mode;

					md = modifiers_findByType(ob_low, eModifierType_Multires);

					if (md) {
						mode = md->mode;
						md->mode &= ~eModifierMode_Render;
					}

					me_nores = bake_mesh_new_from_object(bmain, scene, ob_low);
					RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);

					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
					BKE_libblock_free(bmain, me_nores);

					if (md)
						md->mode = mode;
				}
				break;
			}
			default:
				break;
		}
	}

	if (!ok) {
		BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2);
		op_result = OPERATOR_CANCELLED;
	}
	else {
		/* save the results */
		for (int i = 0; i < bake_images.size; i++) {
			BakeImage *bk_image = &bake_images.data[i];

			if (is_save_internal) {
				ok = write_internal_bake_pixels(
				         bk_image->image,
				         pixel_array_low + bk_image->offset,
				         result + bk_image->offset * depth,
				         bk_image->width, bk_image->height,
				         margin, is_clear, is_noncolor);

				/* might be read by UI to set active image for display */
				bake_update_image(sa, bk_image->image);

				if (!ok) {
					BKE_reportf(reports, RPT_ERROR,
					           "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2);
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_report(reports, RPT_INFO,
					           "Baking map saved to internal image, save it externally or pack it");
					op_result = OPERATOR_FINISHED;
				}
			}
			/* save externally */
			else {
				BakeData *bake = &scene->r.bake;
				char name[FILE_MAX];

				BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);

				if (is_automatic_name) {
					BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
					BLI_path_suffix(name, FILE_MAX, identifier, "_");
				}

				if (is_split_materials) {
					if (bk_image->image) {
						BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_");
					}
					else {
						if (ob_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_");
						}
						else if (me_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_");
						}
						else {
							/* if everything else fails, use the material index */
							char tmp[5];
							sprintf(tmp, "%d", i % 1000);
							BLI_path_suffix(name, FILE_MAX, tmp, "_");
						}
					}
				}

				/* save it externally */
				ok = write_external_bake_pixels(
				        name,
				        pixel_array_low + bk_image->offset,
				        result + bk_image->offset * depth,
				        bk_image->width, bk_image->height,
				        margin, &bake->im_format, is_noncolor);

				if (!ok) {
					BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name);
					op_result = OPERATOR_FINISHED;
				}

				if (!is_split_materials) {
					break;
				}
			}
		}
	}

	if (is_save_internal)
		refresh_images(&bake_images);

cleanup:

	if (highpoly) {
		int i;
		for (i = 0; i < tot_highpoly; i++) {
			highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;

			if (highpoly[i].tri_mod)
				ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);

			if (highpoly[i].me)
				BKE_libblock_free(bmain, highpoly[i].me);
		}
		MEM_freeN(highpoly);
	}

	ob_low->restrictflag = restrict_flag_low;

	if (mmd_low)
		mmd_low->flags = mmd_flags_low;

	if (ob_cage)
		ob_cage->restrictflag = restrict_flag_cage;

	if (pixel_array_low)
		MEM_freeN(pixel_array_low);

	if (pixel_array_high)
		MEM_freeN(pixel_array_high);

	if (bake_images.data)
		MEM_freeN(bake_images.data);

	if (bake_images.lookup)
		MEM_freeN(bake_images.lookup);

	if (result)
		MEM_freeN(result);

	if (me_low)
		BKE_libblock_free(bmain, me_low);

	if (me_cage)
		BKE_libblock_free(bmain, me_cage);

	return op_result;
}
Example #4
0
/**
 * Specialized slerp that uses a sphere defined by each points normal.
 */
static void interp_slerp_co_no_v3(
    const float co_a[3],
    const float no_a[3],
    const float co_b[3],
    const float no_b[3],
    const float no_dir[3], /* caller already knows, avoid normalize */
    float fac,
    float r_co[3])
{
  /* center of the sphere defined by both normals */
  float center[3];

  BLI_assert(len_squared_v3v3(no_a, no_b) != 0);

  /* calculate sphere 'center' */
  {
    /* use point on plane to */
    float no_mid[3], no_ortho[3];
    /* pass this as an arg instead */
#if 0
    float no_dir[3];
#endif

    add_v3_v3v3(no_mid, no_a, no_b);
    normalize_v3(no_mid);

#if 0
    sub_v3_v3v3(no_dir, co_a, co_b);
    normalize_v3(no_dir);
#endif

    /* axis of slerp */
    bool center_ok = false;
    cross_v3_v3v3(no_ortho, no_mid, no_dir);
    if (normalize_v3(no_ortho) != 0.0f) {
      float plane_a[4], plane_b[4], plane_c[4];
      float v_a_no_ortho[3], v_b_no_ortho[3];

      /* create planes */
      cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
      cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
      project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
      project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);

      plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
      plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
      plane_from_point_normal_v3(plane_c, co_b, no_ortho);

      /* find the sphere center from 3 planes */
      if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
        center_ok = true;
      }
    }
    if (center_ok == false) {
      mid_v3_v3v3(center, co_a, co_b);
    }
  }

  /* calculate the final output 'r_co' */
  {
    float ofs_a[3], ofs_b[3], ofs_slerp[3];
    float dist_a, dist_b;

    sub_v3_v3v3(ofs_a, co_a, center);
    sub_v3_v3v3(ofs_b, co_b, center);

    dist_a = normalize_v3(ofs_a);
    dist_b = normalize_v3(ofs_b);

    if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
      madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
    }
    else {
      interp_v3_v3v3(r_co, co_a, co_b, fac);
    }
  }
}
Example #5
0
void BLI_task_pool_stop(TaskPool *pool)
{
	task_scheduler_clear(pool->scheduler, pool);

	BLI_assert(pool->num == 0);
}
Example #6
0
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
	Scene *scene = oglrender->scene;
	ARegion *ar = oglrender->ar;
	View3D *v3d = oglrender->v3d;
	RegionView3D *rv3d = oglrender->rv3d;
	Object *camera = NULL;
	int sizex = oglrender->sizex;
	int sizey = oglrender->sizey;
	const short view_context = (v3d != NULL);
	bool draw_bgpic = true;
	bool draw_sky = (scene->r.alphamode == R_ADDSKY);
	unsigned char *rect = NULL;
	const char *viewname = RE_GetActiveRenderView(oglrender->re);
	ImBuf *ibuf_result = NULL;

	if (oglrender->is_sequencer) {
		SpaceSeq *sseq = oglrender->sseq;
		struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;

		/* use pre-calculated ImBuf (avoids deadlock), see: */
		ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];

		if (ibuf) {
			ImBuf *out = IMB_dupImBuf(ibuf);
			IMB_freeImBuf(ibuf);
			/* OpenGL render is considered to be preview and should be
			 * as fast as possible. So currently we're making sure sequencer
			 * result is always byte to simplify color management pipeline.
			 *
			 * TODO(sergey): In the case of output to float container (EXR)
			 * it actually makes sense to keep float buffer instead.
			 */
			if (out->rect_float != NULL) {
				IMB_rect_from_float(out);
				imb_freerectfloatImBuf(out);
			}
			BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
			RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
			IMB_freeImBuf(out);
		}
		else if (gpd){
			/* If there are no strips, Grease Pencil still needs a buffer to draw on */
			ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
			RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
			IMB_freeImBuf(out);
		}

		if (gpd) {
			int i;
			unsigned char *gp_rect;
			unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;

			GPU_offscreen_bind(oglrender->ofs, true);

			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			wmOrtho2(0, sizex, 0, sizey);
			glTranslatef(sizex / 2, sizey / 2, 0.0f);

			G.f |= G_RENDER_OGL;
			ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
			G.f &= ~G_RENDER_OGL;

			gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);

			for (i = 0; i < sizex * sizey * 4; i += 4) {
				blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
			}
			GPU_offscreen_unbind(oglrender->ofs, true);

			MEM_freeN(gp_rect);
		}
	}
	else {
		/* shouldnt suddenly give errors mid-render but possible */
		char err_out[256] = "unknown";
		ImBuf *ibuf_view;
		const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;

		if (view_context) {
			ibuf_view = ED_view3d_draw_offscreen_imbuf(
			       scene, v3d, ar, sizex, sizey,
			       IB_rect, draw_bgpic,
			       alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
			       oglrender->fx, oglrender->ofs, err_out);

			/* for stamp only */
			if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
				camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
			}
		}
		else {
			ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(
			        scene, scene->camera, oglrender->sizex, oglrender->sizey,
			        IB_rect, OB_SOLID, false, true, true,
			        alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
			        oglrender->fx, oglrender->ofs, err_out);
			camera = scene->camera;
		}

		if (ibuf_view) {
			ibuf_result = ibuf_view;
			rect = (unsigned char *)ibuf_view->rect;
		}
		else {
			fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
		}
	}

	if (ibuf_result != NULL) {
		if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
			BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4);
		}
		RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
		IMB_freeImBuf(ibuf_result);
	}
}
Example #7
0
/*------------------------obj * obj------------------------------
 * multiplication */
static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
{
	float quat[QUAT_SIZE], scalar;
	QuaternionObject *quat1 = NULL, *quat2 = NULL;

	if (QuaternionObject_Check(q1)) {
		quat1 = (QuaternionObject *)q1;
		if (BaseMath_ReadCallback(quat1) == -1)
			return NULL;
	}
	if (QuaternionObject_Check(q2)) {
		quat2 = (QuaternionObject *)q2;
		if (BaseMath_ReadCallback(quat2) == -1)
			return NULL;
	}

	if (quat1 && quat2) { /* QUAT * QUAT (cross product) */
		mul_qt_qtqt(quat, quat1->quat, quat2->quat);
		return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1));
	}
	/* the only case this can happen (for a supported type is "FLOAT * QUAT") */
	else if (quat2) { /* FLOAT * QUAT */
		if (((scalar = PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred()) == 0) {
			return quat_mul_float(quat2, scalar);
		}
	}
	else if (quat1) {
		/* QUAT * VEC */
		if (VectorObject_Check(q2)) {
			VectorObject *vec2 = (VectorObject *)q2;
			float tvec[3];

			if (vec2->size != 3) {
				PyErr_SetString(PyExc_ValueError,
				                "Vector multiplication: "
				                "only 3D vector rotations (with quats) "
				                "currently supported");
				return NULL;
			}
			if (BaseMath_ReadCallback(vec2) == -1) {
				return NULL;
			}

			copy_v3_v3(tvec, vec2->vec);
			mul_qt_v3(quat1->quat, tvec);

			return Vector_CreatePyObject(tvec, 3, Py_NEW, Py_TYPE(vec2));
		}
		/* QUAT * FLOAT */
		else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
			return quat_mul_float(quat1, scalar);
		}
	}
	else {
		BLI_assert(!"internal error");
	}

	PyErr_Format(PyExc_TypeError,
	             "Quaternion multiplication: "
	             "not supported between '%.200s' and '%.200s' types",
	             Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
	return NULL;
}
void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
{
    VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data;
    MemoryBuffer *inputProgramBuffer = tileData->color;
    MemoryBuffer *inputBokehBuffer = tileData->bokeh;
    MemoryBuffer *inputSizeBuffer = tileData->size;
    float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer();
    float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer();
    float readColor[4];
    float bokeh[4];
    float tempSize[4];
    float multiplier_accum[4];
    float color_accum[4];

    const float max_dim = max(m_width, m_height);
    const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
    int maxBlurScalar = tileData->maxBlurScalar;

    BLI_assert(inputBokehBuffer->getWidth()  == COM_BLUR_BOKEH_PIXELS);
    BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS);

#ifdef COM_DEFOCUS_SEARCH
    float search[4];
    this->m_inputSearchProgram->read(search, x / InverseSearchRadiusOperation::DIVIDER, y / InverseSearchRadiusOperation::DIVIDER, NULL);
    int minx = search[0];
    int miny = search[1];
    int maxx = search[2];
    int maxy = search[3];
#else
    int minx = max(x - maxBlurScalar, 0);
    int miny = max(y - maxBlurScalar, 0);
    int maxx = min(x + maxBlurScalar, (int)m_width);
    int maxy = min(y + maxBlurScalar, (int)m_height);
#endif
    {
        inputSizeBuffer->readNoCheck(tempSize, x, y);
        inputProgramBuffer->readNoCheck(readColor, x, y);

        copy_v4_v4(color_accum, readColor);
        copy_v4_fl(multiplier_accum, 1.0f);
        float size_center = tempSize[0] * scalar;

        const int addXStep = QualityStepHelper::getStep() * COM_NUMBER_OF_CHANNELS;

        if (size_center > this->m_threshold) {
            for (int ny = miny; ny < maxy; ny += QualityStepHelper::getStep()) {
                float dy = ny - y;
                int offsetNy = ny * inputSizeBuffer->getWidth() * COM_NUMBER_OF_CHANNELS;
                int offsetNxNy = offsetNy + (minx * COM_NUMBER_OF_CHANNELS);
                for (int nx = minx; nx < maxx; nx += QualityStepHelper::getStep()) {
                    if (nx != x || ny != y) {
                        float size = inputSizeFloatBuffer[offsetNxNy] * scalar;
                        if (size > this->m_threshold) {
                            float dx = nx - x;
                            if (size > fabsf(dx) && size > fabsf(dy)) {
                                float uv[2] = {
                                    (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
                                    (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1)
                                };
                                inputBokehBuffer->readNoCheck(bokeh, uv[0], uv[1]);
                                madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetNxNy]);
                                add_v4_v4(multiplier_accum, bokeh);
                            }
                        }
                    }
                    offsetNxNy += addXStep;
                }
            }
        }

        output[0] = color_accum[0] / multiplier_accum[0];
        output[1] = color_accum[1] / multiplier_accum[1];
        output[2] = color_accum[2] / multiplier_accum[2];
        output[3] = color_accum[3] / multiplier_accum[3];

        /* blend in out values over the threshold, otherwise we get sharp, ugly transitions */
        if ((size_center > this->m_threshold) &&
                (size_center < this->m_threshold * 2.0f))
        {
            /* factor from 0-1 */
            float fac = (size_center - this->m_threshold) / this->m_threshold;
            interp_v4_v4v4(output, readColor, output, fac);
        }
    }

}
Example #9
0
void *BLI_stack_peek(BLI_Stack *stack)
{
	BLI_assert(BLI_stack_is_empty(stack) == false);

	return CHUNK_LAST_ELEM(stack);
}
Example #10
0
/**
 * Replace all references in given Main to \a old_id by \a new_id
 * (if \a new_id is NULL, it unlinks \a old_id).
 */
void BKE_libblock_remap_locked(
        Main *bmain, void *old_idv, void *new_idv,
        const short remap_flags)
{
	IDRemap id_remap_data;
	ID *old_id = old_idv;
	ID *new_id = new_idv;
	int skipped_direct, skipped_refcounted;

	BLI_assert(old_id != NULL);
	BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
	BLI_assert(old_id != new_id);

	libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);

	if (free_notifier_reference_cb) {
		free_notifier_reference_cb(old_id);
	}

	/* We assume editors do not hold references to their IDs... This is false in some cases
	 * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
	if (remap_editor_id_reference_cb) {
		remap_editor_id_reference_cb(old_id, new_id);
	}

	skipped_direct = id_remap_data.skipped_direct;
	skipped_refcounted = id_remap_data.skipped_refcounted;

	/* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
	 * been incremented for that, we have to decrease once more its user count... unless we had to skip
	 * some 'user_one' cases. */
	if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
		id_us_min(old_id);
		old_id->tag &= ~LIB_TAG_EXTRAUSER_SET;
	}

	BLI_assert(old_id->us - skipped_refcounted >= 0);
	UNUSED_VARS_NDEBUG(skipped_refcounted);

	if (skipped_direct == 0) {
		/* old_id is assumed to not be used directly anymore... */
		if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
			old_id->tag &= ~LIB_TAG_EXTERN;
			old_id->tag |= LIB_TAG_INDIRECT;
		}
	}

	/* Some after-process updates.
	 * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
	 */
	switch (GS(old_id->name)) {
		case ID_OB:
			libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id);
			break;
		case ID_GR:
			if (!new_id) {  /* Only affects us in case group was unlinked. */
				for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
					libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
				}
			}
			break;
		case ID_ME:
		case ID_CU:
		case ID_MB:
			if (new_id) {  /* Only affects us in case obdata was relinked (changed). */
				for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
					libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
				}
			}
			break;
		default:
			break;
	}
	/* Node trees may virtually use any kind of data-block... */
	libblock_remap_data_postprocess_nodetree_update(bmain, new_id);

	/* Full rebuild of DAG! */
	DAG_relations_tag_update(bmain);
}
Example #11
0
/* XXX Arg! Naming... :(
 *     _relink? avoids confusion with _remap, but is confusing with _unlink
 *     _remap_used_ids?
 *     _remap_datablocks?
 *     BKE_id_remap maybe?
 *     ... sigh
 */
void BKE_libblock_relink_ex(
        Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
{
	ID *id = idv;
	ID *old_id = old_idv;
	ID *new_id = new_idv;
	int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;

	/* No need to lock here, we are only affecting given ID, not bmain database. */

	BLI_assert(id);
	if (old_id) {
		BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
		BLI_assert(old_id != new_id);
	}
	else {
		BLI_assert(new_id == NULL);
	}

	libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL);

	/* Some after-process updates.
	 * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
	 */
	switch (GS(id->name)) {
		case ID_SCE:
		{
			Scene *sce = (Scene *)id;

			if (old_id) {
				switch (GS(old_id->name)) {
					case ID_OB:
					{
						libblock_remap_data_postprocess_object_fromgroup_update(
						            bmain, (Object *)old_id, (Object *)new_id);
						break;
					}
					case ID_GR:
						if (!new_id) {  /* Only affects us in case group was unlinked. */
							libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
						}
						break;
					default:
						break;
				}
			}
			else {
				/* No choice but to check whole objects/groups. */
				for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
					libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL);
				}
				for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
					libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
				}
			}
			break;
		}
		case ID_OB:
			if (new_id) {  /* Only affects us in case obdata was relinked (changed). */
				libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
			}
			break;
		default:
			break;
	}
}
Example #12
0
static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
{
	IDRemap *id_remap_data = user_data;
	ID *old_id = id_remap_data->old_id;
	ID *new_id = id_remap_data->new_id;
	ID *id = id_remap_data->id;

	if (!old_id) {  /* Used to cleanup all IDs used by a specific one. */
		BLI_assert(!new_id);
		old_id = *id_p;
	}

	if (*id_p && (*id_p == old_id)) {
		const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0;
		const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
		/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
		 *       on the other hand since they get reset to lib data on file open/reload it is indirect too...
		 *       Edit Mode is also a 'skip direct' case. */
		const bool is_obj = (GS(id->name) == ID_OB);
		const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
		const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) &&
		                            (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
		const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;

#ifdef DEBUG_PRINT
		printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n",
		       id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
#endif

		if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) {
			id->tag |= LIB_TAG_DOIT;
		}

		/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
		if ((is_never_null && skip_never_null) ||
		    (is_obj_editmode && (((Object *)id)->data == *id_p)) ||
		    (skip_indirect && is_indirect))
		{
			if (is_indirect) {
				id_remap_data->skipped_indirect++;
			}
			else if (is_never_null || is_obj_editmode) {
				id_remap_data->skipped_direct++;
			}
			else {
				BLI_assert(0);
			}
			if (cb_flag & IDWALK_USER) {
				id_remap_data->skipped_refcounted++;
			}
			else if (cb_flag & IDWALK_USER_ONE) {
				/* No need to count number of times this happens, just a flag is enough. */
				id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
			}
		}
		else {
			if (!is_never_null) {
				*id_p = new_id;
				DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
			}
			if (cb_flag & IDWALK_USER) {
				id_us_min(old_id);
				/* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
				if (new_id)
					new_id->us++;
			}
			else if (cb_flag & IDWALK_USER_ONE) {
				id_us_ensure_real(new_id);
				/* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
				 * that extra user is processed in final handling... */
			}
			if (!is_indirect) {
				id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
			}
		}
	}

	return IDWALK_RET_NOP;
}
/**
 * Initializes the #PolyFill structure before tessellating with #polyfill_calc.
 */
static void polyfill_prepare(
        PolyFill *pf,
        const float (*coords)[2],
        const unsigned int coords_tot,
        int coords_sign,
        unsigned int (*r_tris)[3],
        PolyIndex *r_indices)
{
	/* localize */
	PolyIndex *indices = r_indices;

	unsigned int i;

	/* assign all polyfill members here */
	pf->indices = r_indices;
	pf->coords = coords;
	pf->coords_tot = coords_tot;
#ifdef USE_CONVEX_SKIP
	pf->coords_tot_concave = 0;
#endif
	pf->tris = r_tris;
	pf->tris_tot = 0;

	if (coords_sign == 0) {
		coords_sign = (cross_poly_v2(coords, coords_tot) >= 0.0f) ? 1 : -1;
	}
	else {
		/* check we're passing in correcty args */
#ifdef USE_STRICT_ASSERT
#ifndef NDEBUG
		if (coords_sign == 1) {
			BLI_assert(cross_poly_v2(coords, coords_tot) >= 0.0f);
		}
		else {
			BLI_assert(cross_poly_v2(coords, coords_tot) <= 0.0f);
		}
#endif
#endif
	}

	if (coords_sign == 1) {
		for (i = 0; i < coords_tot; i++) {
			indices[i].next = &indices[i + 1];
			indices[i].prev = &indices[i - 1];
			indices[i].index = i;
		}
	}
	else {
		/* reversed */
		unsigned int n = coords_tot - 1;
		for (i = 0; i < coords_tot; i++) {
			indices[i].next = &indices[i + 1];
			indices[i].prev = &indices[i - 1];
			indices[i].index = (n - i);
		}
	}
	indices[0].prev = &indices[coords_tot - 1];
	indices[coords_tot - 1].next = &indices[0];

	for (i = 0; i < coords_tot; i++) {
		PolyIndex *pi = &indices[i];
		pf_coord_sign_calc(pf, pi);
#ifdef USE_CONVEX_SKIP
		if (pi->sign != CONVEX) {
			pf->coords_tot_concave += 1;
		}
#endif
	}
}
static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
{
#ifndef USE_KDTREE
	/* localize */
	const float (*coords)[2] = pf->coords;
	PolyIndex *pi_curr;

	const float *v1, *v2, *v3;
#endif

#if defined(USE_CONVEX_SKIP) && !defined(USE_KDTREE)
	unsigned int coords_tot_concave_checked = 0;
#endif


#ifdef USE_CONVEX_SKIP

#ifdef USE_CONVEX_SKIP_TEST
	/* check if counting is wrong */
	{
		unsigned int coords_tot_concave_test = 0;
		unsigned int i = pf->coords_tot;
		while (i--) {
			if (coords_sign[indices[i]] != CONVEX) {
				coords_tot_concave_test += 1;
			}
		}
		BLI_assert(coords_tot_concave_test == pf->coords_tot_concave);
	}
#endif

	/* fast-path for circles */
	if (pf->coords_tot_concave == 0) {
		return true;
	}
#endif

	if (UNLIKELY(pi_ear_tip->sign == CONCAVE)) {
		return false;
	}

#ifdef USE_KDTREE
	{
		const unsigned int ind[3] = {
		    pi_ear_tip->index,
		    pi_ear_tip->next->index,
		    pi_ear_tip->prev->index};

		if (kdtree2d_isect_tri(&pf->kdtree, ind)) {
			return false;
		}
	}
#else

	v1 = coords[pi_ear_tip->prev->index];
	v2 = coords[pi_ear_tip->index];
	v3 = coords[pi_ear_tip->next->index];

	/* Check if any point is inside the triangle formed by previous, current and next vertices.
	 * Only consider vertices that are not part of this triangle, or else we'll always find one inside. */

	for (pi_curr = pi_ear_tip->next->next; pi_curr != pi_ear_tip->prev; pi_curr = pi_curr->next) {
		/* Concave vertices can obviously be inside the candidate ear, but so can tangential vertices
		 * if they coincide with one of the triangle's vertices. */
		if (pi_curr->sign != CONVEX) {
			const float *v = coords[pi_curr->index];
			/* Because the polygon has clockwise winding order,
			 * the area sign will be positive if the point is strictly inside.
			 * It will be 0 on the edge, which we want to include as well. */

			/* note: check (v3, v1) first since it fails _far_ more often then the other 2 checks (those fail equally).
			 * It's logical - the chance is low that points exist on the same side as the ear we're clipping off. */
			if ((span_tri_v2_sign(v3, v1, v) != CONCAVE) &&
			    (span_tri_v2_sign(v1, v2, v) != CONCAVE) &&
			    (span_tri_v2_sign(v2, v3, v) != CONCAVE))
			{
				return false;
			}

#ifdef USE_CONVEX_SKIP
			coords_tot_concave_checked += 1;
			if (coords_tot_concave_checked == pf->coords_tot_concave) {
				break;
			}
#endif
		}
	}
#endif  /* USE_KDTREE */

	return true;
}
Example #15
0
static void ntree_shader_link_builtin_group_normal(
    bNodeTree *ntree,
    bNode *group_node,
    bNode *node_from,
    bNodeSocket *socket_from,
    bNode *displacement_node,
    bNodeSocket *displacement_socket)
{
    bNodeTree *group_ntree = (bNodeTree *)group_node->id;
    /* Create input socket to plug displacement connection to. */
    bNodeSocket *group_normal_socket =
        ntreeAddSocketInterface(group_ntree,
                                SOCK_IN,
                                "NodeSocketVector",
                                "Normal");
    /* Need to update tree so all node instances nodes gets proper sockets. */
    bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT);
    node_group_verify(ntree, group_node, &group_ntree->id);
    if (group_input_node)
        node_group_input_verify(group_ntree, group_input_node, &group_ntree->id);
    ntreeUpdateTree(G.main, group_ntree);
    /* Assumes sockets are always added at the end. */
    bNodeSocket *group_node_normal_socket = group_node->inputs.last;
    if (displacement_node == group_node) {
        /* If displacement is coming from this node group we need to perform
         * some internal re-linking in order to avoid cycles.
         */
        bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT);
        BLI_assert(group_output_node != NULL);
        bNodeSocket *group_output_node_displacement_socket =
            nodeFindSocket(group_output_node,
                           SOCK_IN,
                           displacement_socket->identifier);
        bNodeLink *group_displacement_link = group_output_node_displacement_socket->link;
        if (group_displacement_link == NULL) {
            /* Displacement output is not connected to anything, can just stop
             * right away.
             */
            return;
        }
        /* This code is similar to ntree_shader_relink_displacement() */
        bNode *group_displacement_node = group_displacement_link->fromnode;
        bNodeSocket *group_displacement_socket = group_displacement_link->fromsock;
        /* Create and link bump node.
         * Can't re-use bump node from parent tree because it'll cause cycle.
         */
        bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP);
        bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
        bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
        BLI_assert(bump_input_socket != NULL);
        BLI_assert(bump_output_socket != NULL);
        nodeAddLink(group_ntree,
                    group_displacement_node, group_displacement_socket,
                    bump_node, bump_input_socket);
        /* Relink normals inside of the instanced tree. */
        ntree_shader_link_builtin_normal(group_ntree,
                                         bump_node,
                                         bump_output_socket,
                                         group_displacement_node,
                                         group_displacement_socket);
        ntreeUpdateTree(G.main, group_ntree);
    }
    else if (group_input_node) {
        /* Connect group node normal input. */
        nodeAddLink(ntree,
                    node_from, socket_from,
                    group_node, group_node_normal_socket);
        BLI_assert(group_input_node != NULL);
        bNodeSocket *group_input_node_normal_socket =
            nodeFindSocket(group_input_node,
                           SOCK_OUT,
                           group_normal_socket->identifier);
        BLI_assert(group_input_node_normal_socket != NULL);
        /* Relink normals inside of the instanced tree. */
        ntree_shader_link_builtin_normal(group_ntree,
                                         group_input_node,
                                         group_input_node_normal_socket,
                                         displacement_node,
                                         displacement_socket);
        ntreeUpdateTree(G.main, group_ntree);
    }
}
Example #16
0
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	SpaceOops *soops = CTX_wm_space_outliner(C);
	int event;
	const char *str = NULL;
	
	/* check for invalid states */
	if (soops == NULL)
		return OPERATOR_CANCELLED;
	
	event = RNA_enum_get(op->ptr, "type");

	if (event == OL_OP_SELECT) {
		Scene *sce = scene;  // to be able to delete, scenes are set...
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb);
		if (scene != sce) {
			ED_screen_set_scene(C, CTX_wm_screen(C), sce);
		}
		
		str = "Select Objects";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
	}
	else if (event == OL_OP_SELECT_HIERARCHY) {
		Scene *sce = scene;  // to be able to delete, scenes are set...
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb);
		if (scene != sce) {
			ED_screen_set_scene(C, CTX_wm_screen(C), sce);
		}	
		str = "Select Object Hierarchy";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
	}
	else if (event == OL_OP_DESELECT) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb);
		str = "Deselect Objects";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
	}
	else if (event == OL_OP_DELETE) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb);

		/* XXX: tree management normally happens from draw_outliner(), but when
		 *      you're clicking to fast on Delete object from context menu in
		 *      outliner several mouse events can be handled in one cycle without
		 *      handling notifiers/redraw which leads to deleting the same object twice.
		 *      cleanup tree here to prevent such cases. */
		outliner_cleanup_tree(soops);

		DAG_relations_tag_update(bmain);
		str = "Delete Objects";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
	}
	else if (event == OL_OP_LOCALIZED) {    /* disabled, see above enum (ton) */
		outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
		str = "Localized Objects";
	}
	else if (event == OL_OP_TOGVIS) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
		str = "Toggle Visibility";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
	}
	else if (event == OL_OP_TOGSEL) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
		str = "Toggle Selectability";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
	}
	else if (event == OL_OP_TOGREN) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
		str = "Toggle Renderability";
		WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
	}
	else if (event == OL_OP_RENAME) {
		outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb);
		str = "Rename Object";
	}
	else {
		BLI_assert(0);
		return OPERATOR_CANCELLED;
	}

	ED_undo_push(C, str);
	
	return OPERATOR_FINISHED;
}
Example #17
0
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
	Scene *scene = oglrender->scene;
	ARegion *ar = oglrender->ar;
	View3D *v3d = oglrender->v3d;
	RegionView3D *rv3d = oglrender->rv3d;
	Object *camera = NULL;
	ImBuf *ibuf;
	float winmat[4][4];
	float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
	int sizex = oglrender->sizex;
	int sizey = oglrender->sizey;
	const short view_context = (v3d != NULL);
	bool draw_bgpic = true;
	bool draw_sky = (scene->r.alphamode == R_ADDSKY);
	unsigned char *rect = NULL;
	const char *viewname = RE_GetActiveRenderView(oglrender->re);

	if (oglrender->is_sequencer) {
		SeqRenderData context;
		SpaceSeq *sseq = oglrender->sseq;
		int chanshown = sseq ? sseq->chanshown : 0;
		struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;

		BKE_sequencer_new_render_data(
		        oglrender->bmain->eval_ctx, oglrender->bmain, scene,
		        oglrender->sizex, oglrender->sizey, 100.0f,
		        &context);

		context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
		ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);

		if (ibuf) {
			ImBuf *linear_ibuf;

			BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));

			linear_ibuf = IMB_dupImBuf(ibuf);
			IMB_freeImBuf(ibuf);

			if (linear_ibuf->rect_float == NULL) {
				/* internally sequencer working in display space and stores both bytes and float buffers in that space.
				 * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie
				 * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear
				 */

				IMB_float_from_rect(linear_ibuf);
			}
			else {
				/* ensure float buffer is in linear space, not in display space */
				BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
			}

			memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);

			IMB_freeImBuf(linear_ibuf);
		}

		if (gpd) {
			int i;
			unsigned char *gp_rect;

			GPU_offscreen_bind(oglrender->ofs, true);

			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			wmOrtho2(0, sizex, 0, sizey);
			glTranslatef(sizex / 2, sizey / 2, 0.0f);

			G.f |= G_RENDER_OGL;
			ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
			G.f &= ~G_RENDER_OGL;

			gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);

			BLI_assert(rectf != NULL);

			for (i = 0; i < sizex * sizey * 4; i += 4) {
				float  col_src[4];
				rgba_uchar_to_float(col_src, &gp_rect[i]);
				blend_color_mix_float(&rectf[i], &rectf[i], col_src);
			}
			GPU_offscreen_unbind(oglrender->ofs, true);

			MEM_freeN(gp_rect);
		}
	}
	else if (view_context) {
		bool is_persp;
		/* full copy */
		GPUFXSettings fx_settings = v3d->fx_settings;

		ED_view3d_draw_offscreen_init(scene, v3d);

		GPU_offscreen_bind(oglrender->ofs, true); /* bind */

		/* render 3d view */
		if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
#if 0
			const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
#endif
			camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
			RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
			if (camera->type == OB_CAMERA) {
				Camera *cam = camera->data;
				is_persp = cam->type == CAM_PERSP;
			}
			else
				is_persp = true;
			BKE_camera_to_gpu_dof(camera, &fx_settings);
		}
		else {
			rctf viewplane;
			float clipsta, clipend;

			bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
			if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
			else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);

			is_persp = !is_ortho;
		}

		rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");

		if ((scene->r.mode & R_OSA) == 0) {
			ED_view3d_draw_offscreen(
			        scene, v3d, ar, sizex, sizey, NULL, winmat,
			        draw_bgpic, draw_sky, is_persp,
			        oglrender->ofs, oglrender->fx, &fx_settings, viewname);
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
		}
		else {
			/* simple accumulation, less hassle then FSAA FBO's */
			static float jit_ofs[32][2];
			float winmat_jitter[4][4];
			int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1");
			int i, j;

			BLI_jitter_init(jit_ofs, scene->r.osa);

			/* first sample buffer, also initializes 'rv3d->persmat' */
			ED_view3d_draw_offscreen(
			        scene, v3d, ar, sizex, sizey, NULL, winmat,
			        draw_bgpic, draw_sky, is_persp,
			        oglrender->ofs, oglrender->fx, &fx_settings, viewname);
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);

			for (i = 0; i < sizex * sizey * 4; i++)
				accum_buffer[i] = rect[i];

			/* skip the first sample */
			for (j = 1; j < scene->r.osa; j++) {
				copy_m4_m4(winmat_jitter, winmat);
				window_translate_m4(winmat_jitter, rv3d->persmat,
				                    (jit_ofs[j][0] * 2.0f) / sizex,
				                    (jit_ofs[j][1] * 2.0f) / sizey);

				ED_view3d_draw_offscreen(
				        scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
				        draw_bgpic, draw_sky, is_persp,
				        oglrender->ofs, oglrender->fx, &fx_settings, viewname);
				GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);

				for (i = 0; i < sizex * sizey * 4; i++)
					accum_buffer[i] += rect[i];
			}

			for (i = 0; i < sizex * sizey * 4; i++)
				rect[i] = accum_buffer[i] / scene->r.osa;

			MEM_freeN(accum_buffer);
		}

		GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */
	}
	else {
		/* shouldnt suddenly give errors mid-render but possible */
		char err_out[256] = "unknown";
		ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
		                                                         IB_rect, OB_SOLID, false, true, true,
		                                                         (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
		camera = scene->camera;

		if (ibuf_view) {
			/* steal rect reference from ibuf */
			rect = (unsigned char *)ibuf_view->rect;
			ibuf_view->mall &= ~IB_rect;

			IMB_freeImBuf(ibuf_view);
		}
		else {
			fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
		}
	}

	/* note on color management:
	 *
	 * OpenGL renders into sRGB colors, but render buffers are expected to be
	 * linear So we convert to linear here, so the conversion back to bytes can make it
	 * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
	 * correct linear float buffer.
	 */

	if (rect) {
		int profile_to;
		float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
		
		if (BKE_scene_check_color_management_enabled(scene))
			profile_to = IB_PROFILE_LINEAR_RGB;
		else
			profile_to = IB_PROFILE_SRGB;

		/* sequencer has got trickier conversion happened above
		 * also assume opengl's space matches byte buffer color space */
		IMB_buffer_float_from_byte(rectf, rect,
		                           profile_to, IB_PROFILE_SRGB, true,
		                           oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);

		/* rr->rectf is now filled with image data */

		if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
			BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);

		MEM_freeN(rect);
	}
}
Example #18
0
static bool add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
{
	Scene *scene = CTX_data_scene(C);
	const float ctime = CFRA;

	MaskSpline *spline;
	MaskSplinePoint *point;
	MaskSplinePoint *new_point = NULL, *ref_point = NULL;

	/* check on which side we want to add the point */
	int point_index;
	float tangent_point[2];
	float tangent_co[2];
	bool do_cyclic_correct = false;
	bool do_prev;                /* use prev point rather then next?? */

	if (!masklay) {
		return false;
	}
	else {
		finSelectedSplinePoint(masklay, &spline, &point, true);
	}

	ED_mask_select_toggle_all(mask, SEL_DESELECT);

	point_index = (point - spline->points);

	MASKPOINT_DESEL_ALL(point);

	if ((spline->flag & MASK_SPLINE_CYCLIC) ||
	    (point_index > 0 && point_index != spline->tot_point - 1))
	{
		BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
		sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);

		if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
			do_prev = true;
		}
		else {
			do_prev = false;
		}
	}
	else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
		do_prev = true;
	}
	else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
		do_prev = false;
	}
	else {
		do_prev = false;  /* quiet warning */
		/* should never get here */
		BLI_assert(0);
	}

	/* use the point before the active one */
	if (do_prev) {
		point_index--;
		if (point_index < 0) {
			point_index += spline->tot_point; /* wrap index */
			if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) {
				do_cyclic_correct = true;
				point_index = 0;
			}
		}
	}

//		print_v2("", tangent_point);
//		printf("%d\n", point_index);

	mask_spline_add_point_at_index(spline, point_index);

	if (do_cyclic_correct) {
		ref_point = &spline->points[point_index + 1];
		new_point = &spline->points[point_index];
		*ref_point = *new_point;
		memset(new_point, 0, sizeof(*new_point));
	}
	else {
		ref_point = &spline->points[point_index];
		new_point = &spline->points[point_index + 1];
	}

	masklay->act_point = new_point;

	setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false);

	if (masklay->splines_shapes.first) {
		point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
		BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
	}

	WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);

	return true;
}
Example #19
0
/* add new node connected to this socket, or replace an existing one */
static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to,
                                    int type, NodeLinkItem *item)
{
	bNode *node_from;
	bNodeSocket *sock_from_tmp;
	bNode *node_prev = NULL;

	/* unlink existing node */
	if (sock_to->link) {
		node_prev = sock_to->link->fromnode;
		nodeRemLink(ntree, sock_to->link);
	}

	/* find existing node that we can use */
	for (node_from = ntree->nodes.first; node_from; node_from = node_from->next)
		if (node_from->type == type)
			break;

	if (node_from)
		if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex)
			node_from = NULL;

	if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) {
		/* keep the previous node if it's the same type */
		node_from = node_prev;
	}
	else if (!node_from) {
		node_from = nodeAddStaticNode(C, ntree, type);
		if (node_prev != NULL) {
			/* If we're replacing existing node, use it's location. */
			node_from->locx = node_prev->locx;
			node_from->locy = node_prev->locy;
			node_from->offsetx = node_prev->offsetx;
			node_from->offsety = node_prev->offsety;
		}
		else {
			/* Avoid exact intersection of nodes.
			 * TODO(sergey): Still not ideal, but better than nothing.
			 */
			int index = BLI_findindex(&node_to->inputs, sock_to);
			BLI_assert(index != -1);
			node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
			node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
		}
		
		node_link_item_apply(node_from, item);
	}

	nodeSetActive(ntree, node_from);

	/* add link */
	sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
	nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
	sock_to->flag &= ~SOCK_COLLAPSED;

	/* copy input sockets from previous node */
	if (node_prev && node_from != node_prev) {
		bNodeSocket *sock_prev, *sock_from;

		for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
			for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
				if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit)
					continue;

				if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) {
					bNodeLink *link = sock_prev->link;

					if (link && link->fromnode) {
						nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
						nodeRemLink(ntree, link);
					}

					node_socket_copy_default_value(sock_from, sock_prev);
				}
			}
		}

		/* also preserve mapping for texture nodes */
		if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
		    node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
		{
			memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
		}

		/* remove node */
		node_remove_linked(ntree, node_prev);
	}

	nodeUpdate(ntree, node_from);
	nodeUpdate(ntree, node_to);
	ntreeUpdateTree(CTX_data_main(C), ntree);

	ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
}
Example #20
0
/**
 * This function populates an array of verts for the triangles of a mesh
 * Tangent and Normals are also stored
 */
static void mesh_calc_tri_tessface(
        TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm)
{
	int i;
	int p_id;
	MFace *mface;
	MVert *mvert;
	TSpace *tspace;
	float *precomputed_normals = NULL;
	bool calculate_normal;

	mface = CustomData_get_layer(&me->fdata, CD_MFACE);
	mvert = CustomData_get_layer(&me->vdata, CD_MVERT);

	if (tangent) {
		DM_ensure_normals(dm);
		DM_add_tangent_layer(dm);

		precomputed_normals = dm->getTessFaceDataArray(dm, CD_NORMAL);
		calculate_normal = precomputed_normals ? false : true;

		//mface = dm->getTessFaceArray(dm);
		//mvert = dm->getVertArray(dm);

		tspace = dm->getTessFaceDataArray(dm, CD_TANGENT);
		BLI_assert(tspace);
	}

	p_id = -1;
	for (i = 0; i < me->totface; i++) {
		MFace *mf = &mface[i];
		TSpace *ts = tangent ? &tspace[i * 4] : NULL;

		p_id++;

		triangles[p_id].mverts[0] = &mvert[mf->v1];
		triangles[p_id].mverts[1] = &mvert[mf->v2];
		triangles[p_id].mverts[2] = &mvert[mf->v3];
		triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0;

		if (tangent) {
			triangles[p_id].tspace[0] = &ts[0];
			triangles[p_id].tspace[1] = &ts[1];
			triangles[p_id].tspace[2] = &ts[2];

			if (calculate_normal) {
				if (mf->v4 != 0) {
					normal_quad_v3(triangles[p_id].normal,
					               mvert[mf->v1].co,
					               mvert[mf->v2].co,
					               mvert[mf->v3].co,
					               mvert[mf->v4].co);
				}
				else {
					normal_tri_v3(triangles[p_id].normal,
					              triangles[p_id].mverts[0]->co,
					              triangles[p_id].mverts[1]->co,
					              triangles[p_id].mverts[2]->co);
				}
			}
			else {
				copy_v3_v3(triangles[p_id].normal, &precomputed_normals[3 * i]);
			}
		}

		/* 4 vertices in the face */
		if (mf->v4 != 0) {
			p_id++;

			triangles[p_id].mverts[0] = &mvert[mf->v1];
			triangles[p_id].mverts[1] = &mvert[mf->v3];
			triangles[p_id].mverts[2] = &mvert[mf->v4];
			triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0;

			if (tangent) {
				triangles[p_id].tspace[0] = &ts[0];
				triangles[p_id].tspace[1] = &ts[2];
				triangles[p_id].tspace[2] = &ts[3];

				/* same normal as the other "triangle" */
				copy_v3_v3(triangles[p_id].normal, triangles[p_id - 1].normal);
			}
		}
	}

	BLI_assert(p_id < me->totface * 2);
}
Example #21
0
/**
 * Validate the mesh, \a do_fixes requires \a mesh to be non-null.
 *
 * \return false if no changes needed to be made.
 */
bool BKE_mesh_validate_arrays(Mesh *mesh,
                              MVert *mverts, unsigned int totvert,
                              MEdge *medges, unsigned int totedge,
                              MFace *mfaces, unsigned int totface,
                              MLoop *mloops, unsigned int totloop,
                              MPoly *mpolys, unsigned int totpoly,
                              MDeformVert *dverts, /* assume totvert length */
                              const bool do_verbose, const bool do_fixes,
                              bool *r_changed)
{
#   define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; free_flag.edges = do_fixes; } (void)0
#   define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1)

#   define REMOVE_LOOP_TAG(_ml) { _ml->e = INVALID_LOOP_EDGE_MARKER; free_flag.polyloops = do_fixes; } (void)0
#   define REMOVE_POLY_TAG(_mp) { _mp->totloop *= -1; free_flag.polyloops = do_fixes; } (void)0

	MVert *mv = mverts;
	MEdge *me;
	MLoop *ml;
	MPoly *mp;
	unsigned int i, j;
	int *v;

	bool is_valid = true;

	union {
		struct {
			int verts : 1;
			int verts_weight : 1;
			int loops_edge : 1;
		};
		int as_flag;
	} fix_flag;

	union {
		struct {
			int edges : 1;
			int faces : 1;
			/* This regroups loops and polys! */
			int polyloops : 1;
			int mselect : 1;
		};
		int as_flag;
	} free_flag;

	union {
		struct {
			int edges : 1;
		};
		int as_flag;
	} recalc_flag;

	EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge);

	BLI_assert(!(do_fixes && mesh == NULL));

	fix_flag.as_flag = 0;
	free_flag.as_flag = 0;
	recalc_flag.as_flag = 0;

	PRINT_MSG("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n",
	          __func__, totvert, totedge, totloop, totpoly);

	if (totedge == 0 && totpoly != 0) {
		PRINT_ERR("\tLogical error, %u polygons and 0 edges\n", totpoly);
		recalc_flag.edges = do_fixes;
	}

	for (i = 0; i < totvert; i++, mv++) {
		bool fix_normal = true;

		for (j = 0; j < 3; j++) {
			if (!finite(mv->co[j])) {
				PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);

				if (do_fixes) {
					zero_v3(mv->co);

					fix_flag.verts = true;
				}
			}

			if (mv->no[j] != 0)
				fix_normal = false;
		}

		if (fix_normal) {
			PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal\n", i);
			if (do_fixes) {
				mv->no[2] = SHRT_MAX;
				fix_flag.verts = true;
			}
		}
	}

	for (i = 0, me = medges; i < totedge; i++, me++) {
		bool remove = false;

		if (me->v1 == me->v2) {
			PRINT_ERR("\tEdge %u: has matching verts, both %u\n", i, me->v1);
			remove = do_fixes;
		}
		if (me->v1 >= totvert) {
			PRINT_ERR("\tEdge %u: v1 index out of range, %u\n", i, me->v1);
			remove = do_fixes;
		}
		if (me->v2 >= totvert) {
			PRINT_ERR("\tEdge %u: v2 index out of range, %u\n", i, me->v2);
			remove = do_fixes;
		}

		if ((me->v1 != me->v2) && BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
			PRINT_ERR("\tEdge %u: is a duplicate of %d\n", i,
			          GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
			remove = do_fixes;
		}

		if (remove == false) {
			if (me->v1 != me->v2) {
				BLI_edgehash_insert(edge_hash, me->v1, me->v2, SET_INT_IN_POINTER(i));
			}
		}
		else {
			REMOVE_EDGE_TAG(me);
		}
	}

	if (mfaces && !mpolys) {
#		define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; free_flag.faces = do_fixes; } (void)0
#		define CHECK_FACE_VERT_INDEX(a, b) \
					if (mf->a == mf->b) { \
						PRINT_ERR("    face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \
						remove = do_fixes; \
					} (void)0
#		define CHECK_FACE_EDGE(a, b) \
					if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
						PRINT_ERR("    face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \
						          " (%u,%u) is missing edge data\n", i, mf->a, mf->b); \
						recalc_flag.edges = do_fixes; \
					} (void)0

		MFace *mf;
		MFace *mf_prev;

		SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
		SortFace *sf;
		SortFace *sf_prev;
		unsigned int totsortface = 0;

		PRINT_ERR("No Polys, only tesselated Faces\n");

		for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
			bool remove = false;
			int fidx;
			unsigned int fv[4];

			fidx = mf->v4 ? 3 : 2;
			do {
				fv[fidx] = *(&(mf->v1) + fidx);
				if (fv[fidx] >= totvert) {
					PRINT_ERR("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
					remove = do_fixes;
				}
			} while (fidx--);

			if (remove == false) {
				if (mf->v4) {
					CHECK_FACE_VERT_INDEX(v1, v2);
					CHECK_FACE_VERT_INDEX(v1, v3);
					CHECK_FACE_VERT_INDEX(v1, v4);

					CHECK_FACE_VERT_INDEX(v2, v3);
					CHECK_FACE_VERT_INDEX(v2, v4);

					CHECK_FACE_VERT_INDEX(v3, v4);
				}
				else {
					CHECK_FACE_VERT_INDEX(v1, v2);
					CHECK_FACE_VERT_INDEX(v1, v3);

					CHECK_FACE_VERT_INDEX(v2, v3);
				}

				if (remove == false) {
					if (totedge) {
						if (mf->v4) {
							CHECK_FACE_EDGE(v1, v2);
							CHECK_FACE_EDGE(v2, v3);
							CHECK_FACE_EDGE(v3, v4);
							CHECK_FACE_EDGE(v4, v1);
						}
						else {
							CHECK_FACE_EDGE(v1, v2);
							CHECK_FACE_EDGE(v2, v3);
							CHECK_FACE_EDGE(v3, v1);
						}
					}

					sf->index = i;

					if (mf->v4) {
						edge_store_from_mface_quad(sf->es, mf);

						qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
					}
					else {
						edge_store_from_mface_tri(sf->es, mf);
						qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
					}

					totsortface++;
					sf++;
				}
			}

			if (remove) {
				REMOVE_FACE_TAG(mf);
			}
		}

		qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);

		sf = sort_faces;
		sf_prev = sf;
		sf++;

		for (i = 1; i < totsortface; i++, sf++) {
			bool remove = false;

			/* on a valid mesh, code below will never run */
			if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
				mf = mfaces + sf->index;

				if (do_verbose) {
					mf_prev = mfaces + sf_prev->index;

					if (mf->v4) {
						PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n",
						          sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4,
						          mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
					}
					else {
						PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n",
						          sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3,
						          mf_prev->v1, mf_prev->v2, mf_prev->v3);
					}
				}

				remove = do_fixes;
			}
			else {
				sf_prev = sf;
			}

			if (remove) {
				REMOVE_FACE_TAG(mf);
			}
		}

		MEM_freeN(sort_faces);

#		undef REMOVE_FACE_TAG
#		undef CHECK_FACE_VERT_INDEX
#		undef CHECK_FACE_EDGE
	}

	/* Checking loops and polys is a bit tricky, as they are quite intricate...
	 *
	 * Polys must have:
	 * - a valid loopstart value.
	 * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop).
	 *
	 * Loops must have:
	 * - a valid v value.
	 * - a valid e value (corresponding to the edge it defines with the next loop in poly).
	 *
	 * Also, loops not used by polys can be discarded.
	 * And "intersecting" loops (i.e. loops used by more than one poly) are invalid,
	 * so be sure to leave at most one poly per loop!
	 */
	{
		SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
		SortPoly *prev_sp, *sp = sort_polys;
		int prev_end;

		for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
			sp->index = i;

			if (mp->loopstart < 0 || mp->totloop < 3) {
				/* Invalid loop data. */
				PRINT_ERR("\tPoly %u is invalid (loopstart: %d, totloop: %d)\n",
				          sp->index, mp->loopstart, mp->totloop);
				sp->invalid = true;
			}
			else if (mp->loopstart + mp->totloop > totloop) {
				/* Invalid loop data. */
				PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)\n",
				          sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
				sp->invalid = true;
			}
			else {
				/* Poly itself is valid, for now. */
				int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */
				sp->invalid = false;
				sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly");
				sp->numverts = mp->totloop;
				sp->loopstart = mp->loopstart;

				/* Ideally we would only have to do that once on all vertices before we start checking each poly, but
				 * several polys can use same vert, so we have to ensure here all verts of current poly are cleared. */
				for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
					if (ml->v < totvert) {
						mverts[ml->v].flag &= ~ME_VERT_TMP_TAG;
					}
				}

				/* Test all poly's loops' vert idx. */
				for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
					if (ml->v >= totvert) {
						/* Invalid vert idx. */
						PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
						sp->invalid = true;
					}
					else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) {
						PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)\n", i, j);
						sp->invalid = true;
					}
					else {
						mverts[ml->v].flag |= ME_VERT_TMP_TAG;
					}
					*v = ml->v;
				}

				if (sp->invalid)
					continue;

				/* Test all poly's loops. */
				for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
					v1 = ml->v;
					v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
					if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
						/* Edge not existing. */
						PRINT_ERR("\tPoly %u needs missing edge (%d, %d)\n", sp->index, v1, v2);
						if (do_fixes)
							recalc_flag.edges = true;
						else
							sp->invalid = true;
					}
					else if (ml->e >= totedge) {
						/* Invalid edge idx.
						 * We already know from previous text that a valid edge exists, use it (if allowed)! */
						if (do_fixes) {
							int prev_e = ml->e;
							ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
							fix_flag.loops_edge = true;
							PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u\n",
							          sp->loopstart + j, prev_e, ml->e);
						}
						else {
							PRINT_ERR("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e);
							sp->invalid = true;
						}
					}
					else {
						me = &medges[ml->e];
						if (IS_REMOVED_EDGE(me) || !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) {
							/* The pointed edge is invalid (tagged as removed, or vert idx mismatch),
							 * and we already know from previous test that a valid one exists, use it (if allowed)! */
							if (do_fixes) {
								int prev_e = ml->e;
								ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
								fix_flag.loops_edge = true;
								PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n",
								          sp->index, prev_e, ml->e);
							}
							else {
								PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
								sp->invalid = true;
							}
						}
					}
				}

				if (!sp->invalid) {
					/* Needed for checking polys using same verts below. */
					qsort(sp->verts, sp->numverts, sizeof(int), int_cmp);
				}
			}
		}

		/* Second check pass, testing polys using the same verts. */
		qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp);
		sp = prev_sp = sort_polys;
		sp++;

		for (i = 1; i < totpoly; i++, sp++) {
			int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
			const int *p1_v = sp->verts, *p2_v = prev_sp->verts;

			if (sp->invalid) {
				/* break, because all known invalid polys have been put at the end by qsort with search_poly_cmp. */
				break;
			}

			/* Test same polys. */
#if 0
			{
				bool p1_sub = true, p2_sub = true;

				/* NOTE: This performs a sub-set test. */
				/* XXX This (and the sort of verts list) is better than systematic
				 *     search of all verts of one list into the other if lists have
				 *     a fair amount of elements.
				 *     Not sure however it's worth it in this case?
				 *     But as we also need sorted vert list to check verts multi-used
				 *     (in first pass of checks)... */
				/* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
				 *     as invalid, better to replace this by a simple memory cmp... */
				while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
					if (*p1_v < *p2_v) {
						if (p1_sub)
							p1_sub = false;
						p1_nv--;
						p1_v++;
					}
					else if (*p2_v < *p1_v) {
						if (p2_sub)
							p2_sub = false;
						p2_nv--;
						p2_v++;
					}
					else {
						/* Equality, both next verts. */
						p1_nv--;
						p2_nv--;
						p1_v++;
						p2_v++;
					}
				}
				if (p1_nv && p1_sub)
					p1_sub = false;
				else if (p2_nv && p2_sub)
					p2_sub = false;

				if (p1_sub && p2_sub) {
					PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
						  prev_sp->index, sp->index, sp->index);
					sp->invalid = true;
				}
				/* XXX In fact, these might be valid? :/ */
				else if (p1_sub) {
					PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
					sp->invalid = true;
				}
				else if (p2_sub) {
					PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
					prev_sp->invalid = true;
					prev_sp = sp; /* sp is new reference poly. */
				}
			}
#else
			if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
				if (do_verbose) {
					PRINT_ERR("\tPolys %u and %u use same vertices (%d",
					          prev_sp->index, sp->index, *p1_v);
					for (j = 1; j < p1_nv; j++)
						PRINT_ERR(", %d", p1_v[j]);
					PRINT_ERR("), considering poly %u as invalid.\n", sp->index);
				}
				else {
					is_valid = false;
				}
				sp->invalid = true;
			}
#endif
			else {
				prev_sp = sp;
			}
		}

		/* Third check pass, testing loops used by none or more than one poly. */
		qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp);
		sp = sort_polys;
		prev_sp = NULL;
		prev_end = 0;
		for (i = 0; i < totpoly; i++, sp++) {
			/* Free this now, we don't need it anymore, and avoid us another loop! */
			if (sp->verts)
				MEM_freeN(sp->verts);

			/* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */
			if (sp->invalid) {
				if (do_fixes) {
					REMOVE_POLY_TAG((&mpolys[sp->index]));
					/* DO NOT REMOVE ITS LOOPS!!!
					 * As already invalid polys are at the end of the SortPoly list, the loops they
					 * were the only users have already been tagged as "to remove" during previous
					 * iterations, and we don't want to remove some loops that may be used by
					 * another valid poly! */
				}
			}
			/* Test loops users. */
			else {
				/* Unused loops. */
				if (prev_end < sp->loopstart) {
					for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
						PRINT_ERR("\tLoop %u is unused.\n", j);
						if (do_fixes)
							REMOVE_LOOP_TAG(ml);
					}
					prev_end = sp->loopstart + sp->numverts;
					prev_sp = sp;
				}
				/* Multi-used loops. */
				else if (prev_end > sp->loopstart) {
					PRINT_ERR("\tPolys %u and %u share loops from %d to %d, considering poly %u as invalid.\n",
					          prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
					if (do_fixes) {
						REMOVE_POLY_TAG((&mpolys[sp->index]));
						/* DO NOT REMOVE ITS LOOPS!!!
						 * They might be used by some next, valid poly!
						 * Just not updating prev_end/prev_sp vars is enough to ensure the loops
						 * effectively no more needed will be marked as "to be removed"! */
					}
				}
				else {
					prev_end = sp->loopstart + sp->numverts;
					prev_sp = sp;
				}
			}
		}
		/* We may have some remaining unused loops to get rid of! */
		if (prev_end < totloop) {
			for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
				PRINT_ERR("\tLoop %u is unused.\n", j);
				if (do_fixes)
					REMOVE_LOOP_TAG(ml);
			}
		}

		MEM_freeN(sort_polys);
	}

	BLI_edgehash_free(edge_hash, NULL);

	/* fix deform verts */
	if (dverts) {
		MDeformVert *dv;
		for (i = 0, dv = dverts; i < totvert; i++, dv++) {
			MDeformWeight *dw;

			for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
				/* note, greater than max defgroups is accounted for in our code, but not < 0 */
				if (!finite(dw->weight)) {
					PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						dw->weight = 0.0f;
						fix_flag.verts_weight = true;
					}
				}
				else if (dw->weight < 0.0f || dw->weight > 1.0f) {
					PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						CLAMP(dw->weight, 0.0f, 1.0f);
						fix_flag.verts_weight = true;
					}
				}

				if (dw->def_nr < 0) {
					PRINT_ERR("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr);
					if (do_fixes) {
						defvert_remove_group(dv, dw);
						fix_flag.verts_weight = true;

						if (dv->dw) {
							/* re-allocated, the new values compensate for stepping
							 * within the for loop and may not be valid */
							j--;
							dw = dv->dw + j;

						}
						else { /* all freed */
							break;
						}
					}
				}
			}
		}
	}

#   undef REMOVE_EDGE_TAG
#   undef IS_REMOVED_EDGE
#   undef REMOVE_LOOP_TAG
#   undef REMOVE_POLY_TAG

	if (mesh) {
		if (free_flag.faces) {
			BKE_mesh_strip_loose_faces(mesh);
		}

		if (free_flag.polyloops) {
			BKE_mesh_strip_loose_polysloops(mesh);
		}

		if (free_flag.edges) {
			BKE_mesh_strip_loose_edges(mesh);
		}

		if (recalc_flag.edges) {
			BKE_mesh_calc_edges(mesh, true, false);
		}
	}

	if (mesh && mesh->mselect) {
		MSelect *msel;

		for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
			int tot_elem = 0;

			if (msel->index < 0) {
				PRINT_ERR("\tMesh select element %u type %d index is negative, "
				          "resetting selection stack.\n", i, msel->type);
				free_flag.mselect = do_fixes;
				break;
			}

			switch (msel->type) {
				case ME_VSEL:
					tot_elem = mesh->totvert;
					break;
				case ME_ESEL:
					tot_elem = mesh->totedge;
					break;
				case ME_FSEL:
					tot_elem = mesh->totface;
					break;
			}

			if (msel->index > tot_elem) {
				PRINT_ERR("\tMesh select element %u type %d index %d is larger than data array size %d, "
				          "resetting selection stack.\n", i, msel->type, msel->index, tot_elem);

				free_flag.mselect = do_fixes;
				break;
			}
		}

		if (free_flag.mselect) {
			MEM_freeN(mesh->mselect);
			mesh->mselect = NULL;
			mesh->totselect = 0;
		}
	}

	PRINT_MSG("%s: finished\n\n", __func__);

	*r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);

	BLI_assert((*r_changed == false) || (do_fixes == true));

	return is_valid;
}
Example #22
0
/**
 * This function converts an object space normal map to a tangent space normal map for a given low poly mesh
 */
void RE_bake_normal_world_to_tangent(
        const BakePixel pixel_array[], const size_t num_pixels, const int depth,
        float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3],
        float mat[4][4])
{
	size_t i;

	TriTessFace *triangles;

	DerivedMesh *dm = CDDM_from_mesh(me);

	triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh");
	mesh_calc_tri_tessface(triangles, me, true, dm);

	BLI_assert(num_pixels >= 3);

	for (i = 0; i < num_pixels; i++) {
		TriTessFace *triangle;
		float tangents[3][3];
		float normals[3][3];
		float signs[3];
		int j;

		float tangent[3];
		float normal[3];
		float binormal[3];
		float sign;
		float u, v, w;

		float tsm[3][3]; /* tangent space matrix */
		float itsm[3][3];

		size_t offset;
		float nor[3]; /* texture normal */

		bool is_smooth;

		int primitive_id = pixel_array[i].primitive_id;

		offset = i * depth;

		if (primitive_id == -1) {
			copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
			continue;
		}

		triangle = &triangles[primitive_id];
		is_smooth = triangle->is_smooth;

		for (j = 0; j < 3; j++) {
			const TSpace *ts;

			if (is_smooth)
				normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
			else
				normal[j] = triangle->normal[j];

			ts = triangle->tspace[j];
			copy_v3_v3(tangents[j], ts->tangent);
			signs[j] = ts->sign;
		}

		u = pixel_array[i].uv[0];
		v = pixel_array[i].uv[1];
		w = 1.0f - u - v;

		/* normal */
		if (is_smooth)
			interp_barycentric_tri_v3(normals, u, v, normal);

		/* tangent */
		interp_barycentric_tri_v3(tangents, u, v, tangent);

		/* sign */
		/* The sign is the same at all face vertices for any non degenerate face.
		 * Just in case we clamp the interpolated value though. */
		sign = (signs[0]  * u + signs[1]  * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f;

		/* binormal */
		/* B = sign * cross(N, T)  */
		cross_v3_v3v3(binormal, normal, tangent);
		mul_v3_fl(binormal, sign);

		/* populate tangent space matrix */
		copy_v3_v3(tsm[0], tangent);
		copy_v3_v3(tsm[1], binormal);
		copy_v3_v3(tsm[2], normal);

		/* texture values */
		normal_uncompress(nor, &result[offset]);

		/* converts from world space to local space */
		mul_transposed_mat3_m4_v3(mat, nor);

		invert_m3_m3(itsm, tsm);
		mul_m3_v3(itsm, nor);
		normalize_v3(nor);

		/* save back the values */
		normal_compress(&result[offset], nor, normal_swizzle);
	}

	/* garbage collection */
	MEM_freeN(triangles);

	if (dm)
		dm->release(dm);
}
Example #23
0
/* calculates offset for co, based on fractal, sphere or smooth settings  */
static void alter_co(BMVert *v,
                     BMEdge *UNUSED(e_orig),
                     const SubDParams *params,
                     const float perc,
                     const BMVert *v_a,
                     const BMVert *v_b)
{
  float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
  int i;

  copy_v3_v3(co, v->co);

  if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
    normalize_v3_length(co, params->smooth);
  }
  else if (params->use_smooth) {
    /* calculating twice and blending gives smoother results,
     * removing visible seams. */
#define USE_SPHERE_DUAL_BLEND

    const float eps_unit_vec = 1e-5f;
    float smooth;
    float no_dir[3];

#ifdef USE_SPHERE_DUAL_BLEND
    float no_reflect[3], co_a[3], co_b[3];
#endif

    sub_v3_v3v3(no_dir, v_a->co, v_b->co);
    normalize_v3(no_dir);

#ifndef USE_SPHERE_DUAL_BLEND
    if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
      interp_v3_v3v3(co, v_a->co, v_b->co, perc);
    }
    else {
      interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
    }
#else
    /* sphere-a */
    reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
    if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
      interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
    }
    else {
      interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
    }

    /* sphere-b */
    reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
    if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
      interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
    }
    else {
      interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
    }

    /* blend both spheres */
    interp_v3_v3v3(co, co_a, co_b, perc);
#endif /* USE_SPHERE_DUAL_BLEND */

    /* apply falloff */
    if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
      smooth = 1.0f;
    }
    else {
      smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
      smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
    }

    if (params->use_smooth_even) {
      smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
    }

    smooth *= params->smooth;
    if (smooth != 1.0f) {
      float co_flat[3];
      interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
      interp_v3_v3v3(co, co_flat, co, smooth);
    }

#undef USE_SPHERE_DUAL_BLEND
  }

  if (params->use_fractal) {
    float normal[3], co2[3], base1[3], base2[3], tvec[3];
    const float len = len_v3v3(v_a->co, v_b->co);
    float fac;

    fac = params->fractal * len;

    mid_v3_v3v3(normal, v_a->no, v_b->no);
    ortho_basis_v3v3_v3(base1, base2, normal);

    add_v3_v3v3(co2, v->co, params->fractal_ofs);
    mul_v3_fl(co2, 10.0f);

    tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f);
    tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f);
    tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f);

    /* add displacement */
    madd_v3_v3fl(co, normal, tvec[0]);
    madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
    madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
  }

  /* apply the new difference to the rest of the shape keys,
   * note that this doesn't take rotations into account, we _could_ support
   * this by getting the normals and coords for each shape key and
   * re-calculate the smooth value for each but this is quite involved.
   * for now its ok to simply apply the difference IMHO - campbell */

  if (params->shape_info.totlayer > 1) {
    float tvec[3];

    sub_v3_v3v3(tvec, v->co, co);

    /* skip the last layer since its the temp */
    i = params->shape_info.totlayer - 1;
    co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
    while (i--) {
      BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
      sub_v3_v3(co += 3, tvec);
    }
  }
}
/* Set list of adjucent loops to the poly specified by it's index. */
static void exporter_SetPoly(ExportMeshData *export_data,
                             int poly_index, int start_loop, int num_loops,
                             int which_orig_mesh, int orig_poly_index)
{
	DerivedMesh *dm = export_data->dm;
	MPoly *mpoly = &export_data->mpoly[poly_index];
	DerivedMesh *dm_orig;
	int i;

	/* Poly is always to be either from left or right operand. */
	dm_orig = which_dm(export_data, which_orig_mesh);

	BLI_assert(poly_index >= 0 && poly_index < dm->getNumPolys(dm));
	BLI_assert(start_loop >= 0 && start_loop <= dm->getNumLoops(dm) - num_loops);
	BLI_assert(num_loops >= 3);
	BLI_assert(dm_orig != NULL);
	BLI_assert(orig_poly_index >= 0 && orig_poly_index < dm_orig->getNumPolys(dm_orig));

	/* Copy all poly layers, including mpoly. */
	*mpoly = which_mpoly(export_data, which_orig_mesh)[orig_poly_index];
	CustomData_copy_data(&dm_orig->polyData, &dm->polyData, orig_poly_index, poly_index, 1);

	/* Set material of the curren poly.
	 * This would re-map materials from right operand to materials from the
	 * left one as well.
	 */
	setMPolyMaterial(export_data, mpoly, which_orig_mesh);

	/* Set original index of the poly. */
	if (export_data->poly_origindex) {
		if (which_orig_mesh == CARVE_MESH_LEFT) {
			export_data->poly_origindex[poly_index] = orig_poly_index;
		}
		else {
			export_data->poly_origindex[poly_index] = ORIGINDEX_NONE;
		}
	}

	/* Set poly data itself. */
	mpoly->loopstart = start_loop;
	mpoly->totloop = num_loops;

	/* Interpolate data for poly loops. */
	{
		MVert *source_mverts = which_mvert(export_data, which_orig_mesh);
		MLoop *source_mloops = which_mloop(export_data, which_orig_mesh);
		MPoly *source_mpolys = which_mpoly(export_data, which_orig_mesh);
		MPoly *source_poly = &source_mpolys[orig_poly_index];
		MVert *target_mverts = export_data->mvert;
		MLoop *target_mloops = export_data->mloop;
		float (*transform)[4] = NULL;

		if (which_orig_mesh == CARVE_MESH_RIGHT) {
			transform = export_data->left_to_right_mat;
		}

		for (i = 0; i < mpoly->totloop; i++) {
			DM_loop_interp_from_poly(dm_orig,
			                         source_mverts,
			                         source_mloops,
			                         source_poly,
			                         dm,
			                         target_mverts,
			                         target_mloops,
			                         transform,
			                         i + mpoly->loopstart);
		}
	}
}
Example #25
0
const struct SDNA *DNA_sdna_current_get(void)
{
	BLI_assert(g_sdna != NULL);
	return g_sdna;
}
Example #26
0
/* Draw given image buffer on a screen using GLSL for display transform */
void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
                       ColorManagedViewSettings *view_settings,
                       ColorManagedDisplaySettings *display_settings)
{
	bool force_fallback = false;
	bool need_fallback = true;

	/* Early out */
	if (ibuf->rect == NULL && ibuf->rect_float == NULL)
		return;

	/* Single channel images could not be transformed using GLSL yet */
	force_fallback |= ibuf->channels == 1;

	/* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */
	force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL);

	/* Try to draw buffer using GLSL display transform */
	if (force_fallback == false) {
		int ok;

		if (ibuf->rect_float) {
			if (ibuf->float_colorspace) {
				ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
				                                                    ibuf->float_colorspace,
				                                                    ibuf->dither, true);
			}
			else {
				ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings,
				                                         ibuf->dither, true);
			}
		}
		else {
			ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
			                                                    ibuf->rect_colorspace,
			                                                    ibuf->dither, false);
		}

		if (ok) {
			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
			glColor4f(1.0, 1.0, 1.0, 1.0);

			if (ibuf->rect_float) {
				int format = 0;

				if (ibuf->channels == 3)
					format = GL_RGB;
				else if (ibuf->channels == 4)
					format = GL_RGBA;
				else
					BLI_assert(!"Incompatible number of channels for GLSL display");

				if (format != 0) {
					glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
					                 zoomfilter, ibuf->rect_float);
				}
			}
			else if (ibuf->rect) {
				/* ibuf->rect is always RGBA */
				glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
				                 zoomfilter, ibuf->rect);
			}

			IMB_colormanagement_finish_glsl_draw();

			need_fallback = false;
		}
	}

	/* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */
	if (need_fallback) {
		unsigned char *display_buffer;
		void *cache_handle;

		display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);

		if (display_buffer)
			glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
			                  zoomfilter, display_buffer);

		IMB_display_buffer_release(cache_handle);
	}
}
Example #27
0
/**
 * Expand buckets to the next size up or down.
 */
static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
{
	Entry **buckets_old = gh->buckets;
	Entry **buckets_new;
	const unsigned int nbuckets_old = gh->nbuckets;
	unsigned int i;

	BLI_assert((gh->nbuckets != nbuckets) || !gh->buckets);
//	printf("%s: %d -> %d\n", __func__, nbuckets_old, nbuckets);

	gh->nbuckets = nbuckets;
#ifdef GHASH_USE_MODULO_BUCKETS
#else
	gh->bucket_mask = nbuckets - 1;
#endif

	buckets_new = (Entry **)MEM_callocN(sizeof(*gh->buckets) * gh->nbuckets, __func__);

	if (buckets_old) {
		if (nbuckets > nbuckets_old) {
			for (i = 0; i < nbuckets_old; i++) {
				for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
					const unsigned hash = ghash_entryhash(gh, e);
					const unsigned bucket_index = ghash_bucket_index(gh, hash);
					e_next = e->next;
					e->next = buckets_new[bucket_index];
					buckets_new[bucket_index] = e;
				}
			}
		}
		else {
			for (i = 0; i < nbuckets_old; i++) {
#ifdef GHASH_USE_MODULO_BUCKETS
				for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
					const unsigned hash = ghash_entryhash(gh, e);
					const unsigned bucket_index = ghash_bucket_index(gh, hash);
					e_next = e->next;
					e->next = buckets_new[bucket_index];
					buckets_new[bucket_index] = e;
				}
#else
				/* No need to recompute hashes in this case, since our mask is just smaller, all items in old bucket i
				 * will go in same new bucket (i & new_mask)! */
				const unsigned bucket_index = ghash_bucket_index(gh, i);
				BLI_assert(!buckets_old[i] || (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i]))));
				Entry *e;
				for (e = buckets_old[i]; e && e->next; e = e->next);
				if (e) {
					e->next = buckets_new[bucket_index];
					buckets_new[bucket_index] = buckets_old[i];
				}
#endif
			}
		}
	}

	gh->buckets = buckets_new;
	if (buckets_old) {
		MEM_freeN(buckets_old);
	}
}
Example #28
0
void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY)
{
	unsigned char *uc_rect = (unsigned char *) rect;
	const float *f_rect = (float *)rect;
	float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y);
	int ltexid = glaGetOneInteger(GL_TEXTURE_2D);
	int lrowlength = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
	int subpart_x, subpart_y, tex_w, tex_h;
	int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
	int texid = get_cached_work_texture(&tex_w, &tex_h);
	int components;

	/* Specify the color outside this function, and tex will modulate it.
	 * This is useful for changing alpha without using glPixelTransferf()
	 */
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
	glBindTexture(GL_TEXTURE_2D, texid);

	/* don't want nasty border artifacts */
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);

#ifdef __APPLE__
	/* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
	glPixelZoom(1.f, 1.f);
#endif
	
	/* setup seamless 2=on, 0=off */
	seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
	
	offset_x = tex_w - seamless;
	offset_y = tex_h - seamless;
	
	nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
	nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);

	if (format == GL_RGBA)
		components = 4;
	else if (format == GL_RGB)
		components = 3;
	else if (ELEM(format,  GL_LUMINANCE, GL_ALPHA))
		components = 1;
	else {
		BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
		return;
	}

	if (type == GL_FLOAT) {
		/* need to set internal format to higher range float */

		/* NOTE: this could fail on some drivers, like mesa,
		 *       but currently this code is only used by color
		 *       management stuff which already checks on whether
		 *       it's possible to use GL_RGBA16F_ARB
		 */

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
	}
	else {
		/* switch to 8bit RGBA for byte buffer  */
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
	}

	for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) {
		for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) {
			int remainder_x = img_w - subpart_x * offset_x;
			int remainder_y = img_h - subpart_y * offset_y;
			int subpart_w = (remainder_x < tex_w) ? remainder_x : tex_w;
			int subpart_h = (remainder_y < tex_h) ? remainder_y : tex_h;
			int offset_left = (seamless && subpart_x != 0) ? 1 : 0;
			int offset_bot = (seamless && subpart_y != 0) ? 1 : 0;
			int offset_right = (seamless && remainder_x > tex_w) ? 1 : 0;
			int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0;
			float rast_x = x + subpart_x * offset_x * xzoom;
			float rast_y = y + subpart_y * offset_y * yzoom;
			
			/* check if we already got these because we always get 2 more when doing seamless*/
			if (subpart_w <= seamless || subpart_h <= seamless)
				continue;
			
			if (type == GL_FLOAT) {
				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
				
				/* add an extra border of pixels so linear looks ok at edges of full image. */
				if (subpart_w < tex_w)
					glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
				if (subpart_h < tex_h)
					glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
				if (subpart_w < tex_w && subpart_h < tex_h)
					glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_FLOAT, &f_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
			}
			else {
				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + subpart_x * offset_x * components]);
				
				if (subpart_w < tex_w)
					glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[subpart_y * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
				if (subpart_h < tex_h)
					glTexSubImage2D(GL_TEXTURE_2D, 0, 0, subpart_h, subpart_w, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + subpart_x * offset_x * components]);
				if (subpart_w < tex_w && subpart_h < tex_h)
					glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
			}

			glEnable(GL_TEXTURE_2D);
			glBegin(GL_QUADS);
			glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
			glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);

			glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
			glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);

			glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
			glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);

			glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
			glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
			glEnd();
			glDisable(GL_TEXTURE_2D);
		}
	}

	glBindTexture(GL_TEXTURE_2D, ltexid);
	glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	
#ifdef __APPLE__
	/* workaround for os x 10.5/10.6 driver bug (above) */
	glPixelZoom(xzoom, yzoom);
#endif
}
Example #29
0
static int add_vertex_extrude(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
{
	MaskSpline *spline;
	MaskSplinePoint *point;
	MaskSplinePoint *new_point = NULL, *ref_point = NULL;

	/* check on which side we want to add the point */
	int point_index;
	float tangent_point[2];
	float tangent_co[2];
	int do_cyclic_correct = FALSE;
	int do_recalc_src = FALSE;  /* when extruding from endpoints only */
	int do_prev;                /* use prev point rather then next?? */

	if (!masklay) {
		return FALSE;
	}
	else {
		finSelectedSplinePoint(masklay, &spline, &point, TRUE);
	}

	ED_mask_select_toggle_all(mask, SEL_DESELECT);

	point_index = (point - spline->points);

	MASKPOINT_DESEL_ALL(point);

	if ((spline->flag & MASK_SPLINE_CYCLIC) ||
	    (point_index > 0 && point_index != spline->tot_point - 1))
	{
		BKE_mask_calc_tangent_polyline(spline, point, tangent_point);
		sub_v2_v2v2(tangent_co, co, point->bezt.vec[1]);

		if (dot_v2v2(tangent_point, tangent_co) < 0.0f) {
			do_prev = TRUE;
		}
		else {
			do_prev = FALSE;
		}
	}
	else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == 0)) {
		do_prev = TRUE;
		do_recalc_src = TRUE;
	}
	else if (((spline->flag & MASK_SPLINE_CYCLIC) == 0) && (point_index == spline->tot_point - 1)) {
		do_prev = FALSE;
		do_recalc_src = TRUE;
	}
	else {
		do_prev = FALSE;  /* quiet warning */
		/* should never get here */
		BLI_assert(0);
	}

	/* use the point before the active one */
	if (do_prev) {
		point_index--;
		if (point_index < 0) {
			point_index += spline->tot_point; /* wrap index */
			if ((spline->flag & MASK_SPLINE_CYCLIC) == 0) {
				do_cyclic_correct = TRUE;
				point_index = 0;
			}
		}
	}

//		print_v2("", tangent_point);
//		printf("%d\n", point_index);

	mask_spline_add_point_at_index(spline, point_index);

	if (do_cyclic_correct) {
		ref_point = &spline->points[point_index + 1];
		new_point = &spline->points[point_index];
		*ref_point = *new_point;
		memset(new_point, 0, sizeof(*new_point));
	}
	else {
		ref_point = &spline->points[point_index];
		new_point = &spline->points[point_index + 1];
	}

	masklay->act_point = new_point;

	setup_vertex_point(mask, spline, new_point, co, NULL, 0.5f, ref_point, FALSE, 1.0f);

	if (masklay->splines_shapes.first) {
		point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
		BKE_mask_layer_shape_changed_add(masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, TRUE, TRUE);
	}

	if (do_recalc_src) {
		/* TODO, update keyframes in time */
		BKE_mask_calc_handle_point_auto(spline, ref_point, FALSE);
	}

	WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);

	return TRUE;
}
Example #30
0
int BKE_mesh_validate_arrays( Mesh *me,
                              MVert *mverts, unsigned int totvert,
                              MEdge *medges, unsigned int totedge,
                              MFace *mfaces, unsigned int totface,
                              MDeformVert *dverts, /* assume totvert length */
                              const short do_verbose, const short do_fixes)
{
#	define REMOVE_EDGE_TAG(_med) { _med->v2= _med->v1; do_edge_free= 1; }
#	define REMOVE_FACE_TAG(_mf) { _mf->v3=0; do_face_free= 1; }

//	MVert *mv;
	MEdge *med;
	MFace *mf;
	MFace *mf_prev;
	MVert *mvert= mverts;
	unsigned int i;

	short do_face_free= FALSE;
	short do_edge_free= FALSE;

	short verts_fixed= FALSE;
	short vert_weights_fixed= FALSE;

	int do_edge_recalc= FALSE;

	EdgeHash *edge_hash = BLI_edgehash_new();

	SortFace *sort_faces= MEM_callocN(sizeof(SortFace) * totface, "search faces");
	SortFace *sf;
	SortFace *sf_prev;
	unsigned int totsortface= 0;

	BLI_assert(!(do_fixes && me == NULL));

	PRINT("%s: verts(%u), edges(%u), faces(%u)\n", __func__, totvert, totedge, totface);

	if(totedge == 0 && totface != 0) {
		PRINT("    locical error, %u faces and 0 edges\n", totface);
		do_edge_recalc= TRUE;
	}

	for(i=1; i<totvert; i++, mvert++) {
		int j;
		int fix_normal= TRUE;

		for(j=0; j<3; j++) {
			if(!finite(mvert->co[j])) {
				PRINT("    vertex %u: has invalid coordinate\n", i);

				if (do_fixes) {
					zero_v3(mvert->co);

					verts_fixed= TRUE;
				}
			}

			if(mvert->no[j]!=0)
				fix_normal= FALSE;
		}

		if(fix_normal) {
			PRINT("    vertex %u: has zero normal, assuming Z-up normal\n", i);
			if (do_fixes) {
				mvert->no[2]= SHRT_MAX;
				verts_fixed= TRUE;
			}
		}
	}

	for(i=0, med= medges; i<totedge; i++, med++) {
		int remove= FALSE;
		if(med->v1 == med->v2) {
			PRINT("    edge %u: has matching verts, both %u\n", i, med->v1);
			remove= do_fixes;
		}
		if(med->v1 >= totvert) {
			PRINT("    edge %u: v1 index out of range, %u\n", i, med->v1);
			remove= do_fixes;
		}
		if(med->v2 >= totvert) {
			PRINT("    edge %u: v2 index out of range, %u\n", i, med->v2);
			remove= do_fixes;
		}

		if(BLI_edgehash_haskey(edge_hash, med->v1, med->v2)) {
			PRINT("    edge %u: is a duplicate of, %d\n", i, GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, med->v1, med->v2)));
			remove= do_fixes;
		}

		if(remove == FALSE){
			BLI_edgehash_insert(edge_hash, med->v1, med->v2, SET_INT_IN_POINTER(i));
		}
		else {
			REMOVE_EDGE_TAG(med);
		}
	}

	for(i=0, mf=mfaces, sf=sort_faces; i<totface; i++, mf++) {
		int remove= FALSE;
		int fidx;
		unsigned int fv[4];

		fidx = mf->v4 ? 3:2;
		do {
			fv[fidx]= *(&(mf->v1) + fidx);
			if(fv[fidx] >= totvert) {
				PRINT("    face %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
				remove= do_fixes;
			}
		} while (fidx--);

		if(remove == FALSE) {
			if(mf->v4) {
				if(mf->v1 == mf->v2) { PRINT("    face %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; }
				if(mf->v1 == mf->v3) { PRINT("    face %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes;  }
				if(mf->v1 == mf->v4) { PRINT("    face %u: verts invalid, v1/v4 both %u\n", i, mf->v1); remove= do_fixes;  }

				if(mf->v2 == mf->v3) { PRINT("    face %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes;  }
				if(mf->v2 == mf->v4) { PRINT("    face %u: verts invalid, v2/v4 both %u\n", i, mf->v2); remove= do_fixes;  }

				if(mf->v3 == mf->v4) { PRINT("    face %u: verts invalid, v3/v4 both %u\n", i, mf->v3); remove= do_fixes;  }
			}
			else {
				if(mf->v1 == mf->v2) { PRINT("    faceT %u: verts invalid, v1/v2 both %u\n", i, mf->v1); remove= do_fixes; }
				if(mf->v1 == mf->v3) { PRINT("    faceT %u: verts invalid, v1/v3 both %u\n", i, mf->v1); remove= do_fixes; }

				if(mf->v2 == mf->v3) { PRINT("    faceT %u: verts invalid, v2/v3 both %u\n", i, mf->v2); remove= do_fixes; }
			}

			if(remove == FALSE) {
				if(totedge) {
					if(mf->v4) {
						if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
						if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
						if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v4)) { PRINT("    face %u: edge v3/v4 (%u,%u) is missing egde data\n", i, mf->v3, mf->v4); do_edge_recalc= TRUE; }
						if(!BLI_edgehash_haskey(edge_hash, mf->v4, mf->v1)) { PRINT("    face %u: edge v4/v1 (%u,%u) is missing egde data\n", i, mf->v4, mf->v1); do_edge_recalc= TRUE; }
					}
					else {
						if(!BLI_edgehash_haskey(edge_hash, mf->v1, mf->v2)) { PRINT("    face %u: edge v1/v2 (%u,%u) is missing egde data\n", i, mf->v1, mf->v2); do_edge_recalc= TRUE; }
						if(!BLI_edgehash_haskey(edge_hash, mf->v2, mf->v3)) { PRINT("    face %u: edge v2/v3 (%u,%u) is missing egde data\n", i, mf->v2, mf->v3); do_edge_recalc= TRUE; }
						if(!BLI_edgehash_haskey(edge_hash, mf->v3, mf->v1)) { PRINT("    face %u: edge v3/v1 (%u,%u) is missing egde data\n", i, mf->v3, mf->v1); do_edge_recalc= TRUE; }
					}
				}

				sf->index = i;

				if(mf->v4) {
					edge_store_from_mface_quad(sf->es, mf);

					qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
				}
				else {
					edge_store_from_mface_tri(sf->es, mf);
					qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
				}

				totsortface++;
				sf++;
			}
		}
		if(remove) {
			REMOVE_FACE_TAG(mf);
		}
	}

	qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);

	sf= sort_faces;
	sf_prev= sf;
	sf++;

	for(i=1; i<totsortface; i++, sf++) {
		int remove= FALSE;
		/* on a valid mesh, code below will never run */
		if(memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
			mf= mfaces + sf->index;

			if(do_verbose) {
				mf_prev= mfaces + sf_prev->index;
				if(mf->v4) {
					PRINT("    face %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
				}
				else {
					PRINT("    face %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n", sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf_prev->v1, mf_prev->v2, mf_prev->v3);
				}
			}

			remove= do_fixes;
		}
		else {
			sf_prev= sf;
		}

		if(remove) {
			REMOVE_FACE_TAG(mf);
		}
	}

	BLI_edgehash_free(edge_hash, NULL);
	MEM_freeN(sort_faces);


	/* fix deform verts */
	if (dverts) {
		MDeformVert *dv;
		for(i=0, dv= dverts; i<totvert; i++, dv++) {
			MDeformWeight *dw;
			unsigned int j;

			for(j=0, dw= dv->dw; j < dv->totweight; j++, dw++) {
				/* note, greater then max defgroups is accounted for in our code, but not < 0 */
				if (!finite(dw->weight)) {
					PRINT("    vertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						dw->weight= 0.0f;
						vert_weights_fixed= TRUE;
					}
				}
				else if (dw->weight < 0.0f || dw->weight > 1.0f) {
					PRINT("    vertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						CLAMP(dw->weight, 0.0f, 1.0f);
						vert_weights_fixed= TRUE;
					}
				}

				if (dw->def_nr < 0) {
					PRINT("    vertex deform %u, has invalid group %d\n", i, dw->def_nr);
					if (do_fixes) {
						defvert_remove_group(dv, dw);
						if (dv->dw) {
							/* re-allocated, the new values compensate for stepping
							 * within the for loop and may not be valid */
							j--;
							dw= dv->dw + j;

							vert_weights_fixed= TRUE;
						}
						else { /* all freed */
							break;
						}
					}
				}
			}
		}
	}


	PRINT("BKE_mesh_validate: finished\n\n");

#	 undef REMOVE_EDGE_TAG
#	 undef REMOVE_FACE_TAG

	if(me) {
		if(do_face_free) {
			mesh_strip_loose_faces(me);
		}

		if (do_edge_free) {
			mesh_strip_loose_edges(me);
		}

		if(do_fixes && do_edge_recalc) {
			BKE_mesh_calc_edges(me, TRUE);
		}
	}

	return (verts_fixed || vert_weights_fixed || do_face_free || do_edge_free || do_edge_recalc);
}