Example #1
0
static void multires_reshape_propagate_prepare(MultiresPropagateData *data,
                                               Mesh *coarse_mesh,
                                               const int reshape_level,
                                               const int top_level)
{
  BLI_assert(reshape_level <= top_level);
  memset(data, 0, sizeof(*data));
  data->num_grids = coarse_mesh->totloop;
  data->reshape_level = reshape_level;
  data->top_level = top_level;
  if (reshape_level == top_level) {
    /* Nothing to do, reshape will happen on the whole grid content. */
    return;
  }
  data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
  data->grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
  data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level);
  data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
  /* Initialize keys to access CCG at different levels. */
  multires_reshape_init_level_key(&data->reshape_level_key, data, data->reshape_level);
  multires_reshape_init_level_key(&data->top_level_key, data, data->top_level);
  /* Make a copy of grids before reshaping, so we can calculate deltas
   * later on. */
  multires_reshape_store_original_grids(data);
}
static void data_transfer_dtdata_type_preprocess(
        Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
        const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
{
	if (dtdata_type == DT_TYPE_LNOR) {
		/* Compute custom normals into regular loop normals, which will be used for the transfer. */
		MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
		const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
		MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
		const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
		MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
		const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
		MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
		const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
		CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
		CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;

		const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
		const float split_angle_dst = me_dst->smoothresh;

		dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);

		if (dm_dst) {
			dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
		}
		else {
			float (*poly_nors_dst)[3];
			float (*loop_nors_dst)[3];
			short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);

			/* Cache poly nors into a temp CDLayer. */
			poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
			if (dirty_nors_dst || !poly_nors_dst) {
				if (!poly_nors_dst) {
					poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
					CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
				}
				BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst,
				                           num_loops_dst, num_polys_dst, poly_nors_dst, true);
			}
			/* Cache loop nors into a temp CDLayer. */
			loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
			if (dirty_nors_dst || loop_nors_dst) {
				if (!loop_nors_dst) {
					loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
					CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
				}
				BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
				                            loops_dst, loop_nors_dst, num_loops_dst,
				                            polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
				                            use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
			}
		}
	}
}
Example #3
0
static void mesh_calc_edges(Mesh *mesh)
{
	CustomData edata;
	EdgeHashIterator *ehi;
	MFace *mf = mesh->mface;
	MEdge *med;
	EdgeHash *eh = BLI_edgehash_new();
	int i, *index, totedge, totface = mesh->totface;

	for (i = 0; i < totface; i++, mf++) {
		if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
			BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
		if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
			BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
		
		if (mf->v4) {
			if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
				BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
			if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
				BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
		} else {
			if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
				BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
		}
	}

	totedge = BLI_edgehash_size(eh);

	/* write new edges into a temporary CustomData */
	memset(&edata, 0, sizeof(edata));
	CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);

	ehi = BLI_edgehashIterator_new(eh);
	med = CustomData_get_layer(&edata, CD_MEDGE);
	for(i = 0; !BLI_edgehashIterator_isDone(ehi);
	    BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
		BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);

		med->flag = ME_EDGEDRAW|ME_EDGERENDER;
	}
	BLI_edgehashIterator_free(ehi);

	/* free old CustomData and assign new one */
	CustomData_free(&mesh->edata, mesh->totedge);
	mesh->edata = edata;
	mesh->totedge = totedge;

	mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);

	BLI_edgehash_free(eh, NULL);
}
Example #4
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
                                  ModifierApplyFlag flag)
{
	MultiresModifierData *mmd = (MultiresModifierData *)md;
	DerivedMesh *result;
	Mesh *me = (Mesh *)ob->data;
	const int useRenderParams = flag & MOD_APPLY_RENDER;

	if (mmd->totlvl) {
		if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
			/* multires always needs a displacement layer */
			CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
		}
	}

	result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams);

	if (result == dm)
		return dm;

	if(useRenderParams || !(flag & MOD_APPLY_USECACHE)) {
		DerivedMesh *cddm;
		
		cddm = CDDM_copy(result);

		/* copy hidden flag to vertices */
		if (!useRenderParams) {
			struct MDisps *mdisps;
			mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
			if (mdisps) {
				subsurf_copy_grid_hidden(result, me->mpoly,
				                         cddm->getVertArray(cddm),
				                         mdisps);

				BKE_mesh_flush_hidden_from_verts(cddm->getVertArray(cddm),
				                                 cddm->getLoopArray(cddm),
				                                 cddm->getEdgeArray(cddm),
				                                 cddm->getNumEdges(cddm),
				                                 cddm->getPolyArray(cddm),
				                                 cddm->getNumPolys(cddm));
			}
		}

		result->release(result);
		result = cddm;
	}

	return result;
}
Example #5
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
						   int useRenderParams, int isFinalCalc)
{
	SculptSession *ss= ob->sculpt;
	int sculpting= (ob->mode & OB_MODE_SCULPT) && ss;
	MultiresModifierData *mmd = (MultiresModifierData*)md;
	DerivedMesh *result;
	Mesh *me= (Mesh*)ob->data;

	if(mmd->totlvl) {
		if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
			/* multires always needs a displacement layer */
			CustomData_add_layer(&me->fdata, CD_MDISPS, CD_CALLOC, NULL, me->totface);
		}
	}

	result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams, isFinalCalc);

	if(result == dm)
		return dm;

	if(useRenderParams || !isFinalCalc) {
		DerivedMesh *cddm= CDDM_copy(result);
		result->release(result);
		result= cddm;
	}
	else if(sculpting) {
		/* would be created on the fly too, just nicer this
		   way on first stroke after e.g. switching levels */
		ss->pbvh= result->getPBVH(ob, result);
	}

	return result;
}
Example #6
0
static void count_images(MultiresBakeRender *bkr)
{
	int a, totface;
	DerivedMesh *dm = bkr->lores_dm;
	MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE);

	bkr->image.first = bkr->image.last = NULL;
	bkr->tot_image = 0;

	totface = dm->getNumTessFaces(dm);

	for (a = 0; a < totface; a++)
		mtface[a].tpage->id.flag &= ~LIB_DOIT;

	for (a = 0; a < totface; a++) {
		Image *ima = mtface[a].tpage;
		if ((ima->id.flag & LIB_DOIT) == 0) {
			LinkData *data = BLI_genericNodeN(ima);
			BLI_addtail(&bkr->image, data);
			bkr->tot_image++;
			ima->id.flag |= LIB_DOIT;
		}
	}

	for (a = 0; a < totface; a++)
		mtface[a].tpage->id.flag &= ~LIB_DOIT;
}
Example #7
0
static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
{
  GridPaintMaskData *data = mask_evaluator->user_data;
  data->mpoly = mesh->mpoly;
  data->grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
  mask_data_init_mapping(mask_evaluator, mesh);
}
Example #8
0
/* Check poly normals and new loop normals are compatible, otherwise flip polygons
 * (and invert matching poly normals). */
static bool polygons_check_flip(
        MLoop *mloop, float (*nos)[3], CustomData *ldata,
        MPoly *mpoly, float (*polynors)[3], const int num_polys)
{
	MPoly *mp;
	MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
	int i;
	bool flipped = false;

	for (i = 0, mp = mpoly; i < num_polys; i++, mp++) {
		float norsum[3] = {0.0f};
		float (*no)[3];
		int j;

		for (j = 0, no = &nos[mp->loopstart]; j < mp->totloop; j++, no++) {
			add_v3_v3(norsum, *no);
		}

		if (!normalize_v3(norsum)) {
			continue;
		}

		/* If average of new loop normals is opposed to polygon normal, flip polygon. */
		if (dot_v3v3(polynors[i], norsum) < 0.0f) {
			BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true);
			negate_v3(polynors[i]);
			flipped = true;
		}
	}

	return flipped;
}
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
{
	DerivedMesh *result;

	GenerateOceanGeometryData gogd;

	int num_verts;
	int num_polys;

	const bool use_threading = omd->resolution > 4;

	gogd.rx = omd->resolution * omd->resolution;
	gogd.ry = omd->resolution * omd->resolution;
	gogd.res_x = gogd.rx * omd->repeat_x;
	gogd.res_y = gogd.ry * omd->repeat_y;

	num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
	num_polys = gogd.res_x * gogd.res_y;

	gogd.sx = omd->size * omd->spatial_size;
	gogd.sy = omd->size * omd->spatial_size;
	gogd.ox = -gogd.sx / 2.0f;
	gogd.oy = -gogd.sy / 2.0f;

	gogd.sx /= gogd.rx;
	gogd.sy /= gogd.ry;

	result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);

	gogd.mverts = CDDM_get_verts(result);
	gogd.mpolys = CDDM_get_polys(result);
	gogd.mloops = CDDM_get_loops(result);

	gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	/* create vertices */
	BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);

	/* create faces */
	BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);

	CDDM_calc_edges(result);

	/* add uvs */
	if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
		gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
		CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);

		if (gogd.mloopuvs) { /* unlikely to fail */
			gogd.ix = 1.0 / gogd.rx;
			gogd.iy = 1.0 / gogd.ry;

			BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
		}
	}

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
Example #10
0
static void multires_reshape_ensure_displacement_grids(Mesh *mesh, const int grid_level)
{
  const int num_grids = mesh->totloop;
  MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
  for (int grid_index = 0; grid_index < num_grids; grid_index++) {
    multires_reshape_ensure_displacement_grid(&mdisps[grid_index], grid_level);
  }
}
Example #11
0
void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
{
	std::map<Normal, unsigned int> shared_normal_indices;
	int last_normal_index = -1;

	MVert *verts  = me->mvert;
	MLoop *mloops = me->mloop;
	float(*lnors)[3];

	BKE_mesh_calc_normals_split(me);
	if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
		lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
	}

	for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
		MPoly *mpoly  = &me->mpoly[poly_index];

		if (!(mpoly->flag & ME_SMOOTH)) {
			// For flat faces use face normal as vertex normal:

			float vector[3];
			BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector);

			Normal n = { vector[0], vector[1], vector[2] };
			normals.push_back(n);
			last_normal_index++;
		}

		MLoop *mloop = mloops + mpoly->loopstart;
		BCPolygonNormalsIndices poly_indices;
		for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
			unsigned int loop_idx = mpoly->loopstart + loop_index;
			if (mpoly->flag & ME_SMOOTH) {

				float normalized[3];
				normalize_v3_v3(normalized, lnors[loop_idx]);
				Normal n = { normalized[0], normalized[1], normalized[2] };

				if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
					poly_indices.add_index(shared_normal_indices[n]);
				}
				else {
					last_normal_index++;
					poly_indices.add_index(last_normal_index);
					shared_normal_indices[n] = last_normal_index;
					normals.push_back(n);
				}
			}
			else {
				poly_indices.add_index(last_normal_index);
			}
		}

		polygons_normals.push_back(poly_indices);
	}
}
static void rna_Mesh_normals_split_custom_do(Mesh *mesh, float (*custom_loopnors)[3], const bool use_vertices)
{
	float (*polynors)[3];
	short (*clnors)[2];
	const int numloops = mesh->totloop;
	bool free_polynors = false;

	clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
	if (clnors) {
		memset(clnors, 0, sizeof(*clnors) * numloops);
	}
	else {
		clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, numloops);
	}

	if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
		polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
	}
	else {
		polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
		BKE_mesh_calc_normals_poly(
		            mesh->mvert, NULL, mesh->totvert,
		            mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
		free_polynors = true;
	}

	if (use_vertices) {
		BKE_mesh_normals_loop_custom_from_vertices_set(
		        mesh->mvert, custom_loopnors, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, mesh->totloop,
		        mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors);
	}
	else {
		BKE_mesh_normals_loop_custom_set(
		        mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, custom_loopnors, mesh->totloop,
		        mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors);
	}

	if (free_polynors) {
		MEM_freeN(polynors);
	}
}
Example #13
0
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
                                         const struct Mesh *mesh)
{
  GridPaintMask *grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
  if (grid_paint_mask == NULL) {
    return false;
  }
  /* Allocate all required memory. */
  mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData), "mask from grid data");
  mask_init_data(mask_evaluator, mesh);
  mask_init_functions(mask_evaluator);
  return true;
}
static void data_transfer_dtdata_type_postprocess(
        Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
        const int dtdata_type, const bool changed)
{
	if (dtdata_type == DT_TYPE_LNOR) {
		/* Bake edited destination loop normals into custom normals again. */
		MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
		const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
		MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
		const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
		MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
		const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
		MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
		const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
		CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
		CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;

		const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
		float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
		short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);

		BLI_assert(poly_nors_dst);

		if (!changed) {
			return;
		}

		if (!custom_nors_dst) {
			custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst);
		}

		/* Note loop_nors_dst contains our custom normals as transferred from source... */
		BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
		                                 loops_dst, loop_nors_dst, num_loops_dst,
		                                 polys_dst, poly_nors_dst, num_polys_dst,
		                                 custom_nors_dst);
	}
}
Example #15
0
void mesh_update_customdata_pointers(Mesh *me)
{
	me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
	me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
	me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY);

	me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);

	me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
	me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
	me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
}
Example #16
0
/* MultiresBake callback for normals' baking
   general idea:
     - find coord and normal of point with specified UV in hi-res mesh
     - multiply it by tangmat
     - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */
static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *UNUSED(bake_data),
                                   const int face_index, const int lvl, const float st[2],
                                   float tangmat[3][3], const int x, const int y)
{
	MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;
	Image *ima= mtface[face_index].tpage;
	ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
	float uv[2], *st0, *st1, *st2, *st3;
	int pixel= ibuf->x*y + x;
	float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5};

	lores_dm->getFace(lores_dm, face_index, &mface);

	st0= mtface[face_index].uv[0];
	st1= mtface[face_index].uv[1];
	st2= mtface[face_index].uv[2];

	if(mface.v4) {
		st3= mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	} else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], NULL, n);

	mul_v3_m3v3(vec, tangmat, n);
	normalize_v3(vec);
	mul_v3_fl(vec, 0.5);
	add_v3_v3(vec, tmp);

	if(ibuf->rect_float) {
		float *rrgbf= ibuf->rect_float + pixel*4;
		rrgbf[0]= vec[0];
		rrgbf[1]= vec[1];
		rrgbf[2]= vec[2];
		rrgbf[3]= 1.0f;

		ibuf->userflags= IB_RECT_INVALID;
	} else {
		char *rrgb= (char*)ibuf->rect + pixel*4;
		rrgb[0]= FTOCHAR(vec[0]);
		rrgb[1]= FTOCHAR(vec[1]);
		rrgb[2]= FTOCHAR(vec[2]);
		rrgb[3]= 255;
	}
}
Example #17
0
/* MultiresBake callback for normals' baking
 * general idea:
 *   - find coord and normal of point with specified UV in hi-res mesh
 *   - multiply it by tangmat
 *   - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */
static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
                                   ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
                                   float tangmat[3][3], const int x, const int y)
{
	MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;
	MNormalBakeData *normal_data = (MNormalBakeData *)bake_data;
	float uv[2], *st0, *st1, *st2, *st3;
	int pixel = ibuf->x * y + x;
	float n[3], vec[3], tmp[3] = {0.5, 0.5, 0.5};

	lores_dm->getTessFace(lores_dm, face_index, &mface);

	st0 = mtface[face_index].uv[0];
	st1 = mtface[face_index].uv[1];
	st2 = mtface[face_index].uv[2];

	if (mface.v4) {
		st3 = mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	}
	else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm,
	               normal_data->orig_index_mf_to_mpoly, normal_data->orig_index_mp_to_orig,
	               lvl, face_index, uv[0], uv[1], NULL, n);

	mul_v3_m3v3(vec, tangmat, n);
	normalize_v3(vec);
	mul_v3_fl(vec, 0.5);
	add_v3_v3(vec, tmp);

	if (ibuf->rect_float) {
		float *rrgbf = ibuf->rect_float + pixel * 4;
		rrgbf[0] = vec[0];
		rrgbf[1] = vec[1];
		rrgbf[2] = vec[2];
		rrgbf[3] = 1.0f;
	}
	else {
		unsigned char *rrgb = (unsigned char *)ibuf->rect + pixel * 4;
		rgb_float_to_uchar(rrgb, vec);
		rrgb[3] = 255;
	}
}
Example #18
0
/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
 * use in object mode when selecting faces (while painting) */
void paintface_flush_flags(Object *ob, short flag)
{
	Mesh *me = BKE_mesh_from_object(ob);
	DerivedMesh *dm = ob->derivedFinal;
	MPoly *polys, *mp_orig;
	const int *index_array = NULL;
	int totpoly;
	int i;
	
	BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0);

	if (me == NULL)
		return;

	/* note, call #BKE_mesh_flush_hidden_from_verts_ex first when changing hidden flags */

	/* we could call this directly in all areas that change selection,
	 * since this could become slow for realtime updates (circle-select for eg) */
	if (flag & SELECT) {
		BKE_mesh_flush_select_from_polys(me);
	}

	if (dm == NULL)
		return;

	/* Mesh polys => Final derived polys */

	if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) {
		polys = dm->getPolyArray(dm);
		totpoly = dm->getNumPolys(dm);

		/* loop over final derived polys */
		for (i = 0; i < totpoly; i++) {
			if (index_array[i] != ORIGINDEX_NONE) {
				/* Copy flags onto the final derived poly from the original mesh poly */
				mp_orig = me->mpoly + index_array[i];
				polys[i].flag = mp_orig->flag;

			}
		}
	}

	if (flag & ME_HIDE) {
		/* draw-object caches hidden faces, force re-generation T46867 */
		GPU_drawobject_free(dm);
	}
}
Example #19
0
/*  (similar to void paintface_flush_flags(Object *ob))
 * copy the vertex flags, most importantly selection from the mesh to the final derived mesh,
 * use in object mode when selecting vertices (while painting) */
void paintvert_flush_flags(Object *ob)
{
  Mesh *me = BKE_mesh_from_object(ob);
  Mesh *me_eval = ob->runtime.mesh_eval;
  MVert *mvert_eval, *mv;
  const int *index_array = NULL;
  int totvert;
  int i;

  if (me == NULL) {
    return;
  }

  /* we could call this directly in all areas that change selection,
   * since this could become slow for realtime updates (circle-select for eg) */
  BKE_mesh_flush_select_from_verts(me);

  if (me_eval == NULL) {
    return;
  }

  index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);

  mvert_eval = me_eval->mvert;
  totvert = me_eval->totvert;

  mv = mvert_eval;

  if (index_array) {
    int orig_index;
    for (i = 0; i < totvert; i++, mv++) {
      orig_index = index_array[i];
      if (orig_index != ORIGINDEX_NONE) {
        mv->flag = me->mvert[index_array[i]].flag;
      }
    }
  }
  else {
    for (i = 0; i < totvert; i++, mv++) {
      mv->flag = me->mvert[i].flag;
    }
  }

  BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
}
Example #20
0
static void partialvis_update_mesh(Object *ob,
                                   PBVH *pbvh,
                                   PBVHNode *node,
                                   PartialVisAction action,
                                   PartialVisArea area,
                                   float planes[4][4])
{
	Mesh *me = ob->data;
	MVert *mvert;
	float *paint_mask;
	int *vert_indices;
	int totvert, i;
	bool any_changed = false, any_visible = false;
			
	BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
	BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
	paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);

	sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);

	for (i = 0; i < totvert; i++) {
		MVert *v = &mvert[vert_indices[i]];
		float vmask = paint_mask ? paint_mask[vert_indices[i]] : 0;

		/* hide vertex if in the hide volume */
		if (is_effected(area, planes, v->co, vmask)) {
			if (action == PARTIALVIS_HIDE)
				v->flag |= ME_HIDE;
			else
				v->flag &= ~ME_HIDE;
			any_changed = true;
		}

		if (!(v->flag & ME_HIDE))
			any_visible = true;
	}

	if (any_changed) {
		BKE_pbvh_node_mark_rebuild_draw(node);
		BKE_pbvh_node_fully_hidden_set(node, !any_visible);
	}
}
static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap)
{
	float (*r_looptangents)[4];

	if (CustomData_has_layer(&mesh->ldata, CD_MLOOPTANGENT)) {
		r_looptangents = CustomData_get_layer(&mesh->ldata, CD_MLOOPTANGENT);
		memset(r_looptangents, 0, sizeof(float[4]) * mesh->totloop);
	}
	else {
		r_looptangents = CustomData_add_layer(&mesh->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, mesh->totloop);
		CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
	}

	/* Compute loop normals if needed. */
	if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
		BKE_mesh_calc_normals_split(mesh);
	}

	BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
}
Example #22
0
static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level)
{
  GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
  if (grid_paint_masks == NULL) {
    return;
  }
  const int num_grids = mesh->totloop;
  const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
  const int grid_area = grid_size * grid_size;
  for (int grid_index = 0; grid_index < num_grids; grid_index++) {
    GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
    if (grid_paint_mask->level == grid_level) {
      continue;
    }
    grid_paint_mask->level = grid_level;
    if (grid_paint_mask->data) {
      MEM_freeN(grid_paint_mask->data);
    }
    grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data");
  }
}
Example #23
0
static bool multires_reshape_from_vertcos(struct Depsgraph *depsgraph,
                                          Object *object,
                                          const MultiresModifierData *mmd,
                                          const float (*deformed_verts)[3],
                                          const int num_deformed_verts,
                                          const bool use_render_params)
{
  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
  Mesh *coarse_mesh = object->data;
  MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
  /* Pick maximum between multires level and dispalcement level.
   * This is because mesh can be used by objects with multires at different
   * levels.
   *
   * TODO(sergey): At this point it should be possible to always use
   * mdisps->level. */
  const int top_level = max_ii(mmd->totlvl, mdisps->level);
  /* Make sure displacement grids are ready. */
  multires_reshape_ensure_grids(coarse_mesh, top_level);
  /* Initialize subdivision surface. */
  Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd);
  if (subdiv == NULL) {
    return false;
  }
  /* Construct context. */
  MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = {
      .reshape_ctx =
          {
              .subdiv = subdiv,
              .coarse_mesh = coarse_mesh,
              .mdisps = mdisps,
              .grid_paint_mask = NULL,
              .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
              .top_level = top_level,
              .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
          },
      .deformed_verts = deformed_verts,
      .num_deformed_verts = num_deformed_verts,
  };
void RE_bake_pixels_populate(
        Mesh *me, BakePixel pixel_array[],
        const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer)
{
	BakeDataZSpan bd;
	size_t i;
	int a, p_id;

	MTFace *mtface;
	MFace *mface;

	/* we can't bake in edit mode */
	if (me->edit_btmesh)
		return;

	bd.pixel_array = pixel_array;
	bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan");

	/* initialize all pixel arrays so we know which ones are 'blank' */
	for (i = 0; i < num_pixels; i++) {
		pixel_array[i].primitive_id = -1;
	}

	for (i = 0; i < bake_images->size; i++) {
		zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
	}

	if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
		mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
	}
	else {
		int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer);
		mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id);
	}

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

	if (mtface == NULL)
		return;

	p_id = -1;
	for (i = 0; i < me->totface; i++) {
		float vec[4][2];
		MTFace *mtf = &mtface[i];
		MFace *mf = &mface[i];
		int mat_nr = mf->mat_nr;
		int image_id = bake_images->lookup[mat_nr];

		bd.bk_image = &bake_images->data[image_id];
		bd.primitive_id = ++p_id;

		for (a = 0; a < 4; a++) {
			/* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
			 * where a pixel gets in between 2 faces or the middle of a quad,
			 * camera aligned quads also have this problem but they are less common.
			 * Add a small offset to the UVs, fixes bug #18685 - Campbell */
			vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f);
			vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f);
		}

		bake_differentials(&bd, vec[0], vec[1], vec[2]);
		zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);

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

			bake_differentials(&bd, vec[0], vec[2], vec[3]);
			zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel);
		}
	}

	for (i = 0; i < bake_images->size; i++) {
		zbuf_free_span(&bd.zspan[i]);
	}
	MEM_freeN(bd.zspan);
}
/**
 * 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;
	MVert *mvert;
	TSpace *tspace;
	float *precomputed_normals = NULL;
	bool calculate_normal;
	const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
	MLoopTri *looptri;
	/* calculate normal for each polygon only once */
	unsigned int mpoly_prev = UINT_MAX;
	float no[3];

	mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
	looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);

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

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

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

	BKE_mesh_recalc_looptri(
	            me->mloop, me->mpoly,
	            me->mvert,
	            me->totloop, me->totpoly,
	            looptri);

	for (i = 0; i < tottri; i++) {
		MLoopTri *lt = &looptri[i];
		MPoly *mp = &me->mpoly[lt->poly];

		triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
		triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
		triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
		triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0;

		if (tangent) {
			triangles[i].tspace[0] = &tspace[lt->tri[0]];
			triangles[i].tspace[1] = &tspace[lt->tri[1]];
			triangles[i].tspace[2] = &tspace[lt->tri[2]];

			if (calculate_normal) {
				if (lt->poly != mpoly_prev) {
					const MPoly *mp = &me->mpoly[lt->poly];
					BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no);
					mpoly_prev = lt->poly;
				}
				copy_v3_v3(triangles[i].normal, no);
			}
			else {
				copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]);
			}
		}
	}

	MEM_freeN(looptri);
}
Example #26
0
bool data_transfer_layersmapping_vgroups(
        ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
        const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst,
        CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers)
{
	int idx_src, idx_dst;
	MDeformVert *data_src, *data_dst = NULL;

	const size_t elem_size = sizeof(*((MDeformVert *)NULL));

	/* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual
	 *       data is a (mesh) CD layer.
	 *       This implies we may have to handle data layout itself while having NULL data itself,
	 *       and even have to support NULL data_src in transfer data code (we always create a data_dst, though).
	 */

	if (BLI_listbase_is_empty(&ob_src->defbase)) {
		if (use_delete) {
			BKE_object_defgroup_remove_all(ob_dst);
		}
		return true;
	}

	data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);

	data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
	if (data_dst && use_dupref_dst && r_map) {
		/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
		data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst);
	}

	if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
		/* Note: use_delete has not much meaning in this case, ignored. */

		if (fromlayers >= 0) {
			idx_src = fromlayers;
			BLI_assert(idx_src < BLI_listbase_count(&ob_src->defbase));
		}
		else if ((idx_src = ob_src->actdef - 1) == -1) {
			return false;
		}

		if (tolayers >= 0) {
			/* Note: in this case we assume layer exists! */
			idx_dst = tolayers;
			BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase));
		}
		else if (tolayers == DT_LAYERS_ACTIVE_DST) {
			if ((idx_dst = ob_dst->actdef - 1) == -1) {
				bDeformGroup *dg_src;
				if (!use_create) {
					return true;
				}
				dg_src = BLI_findlink(&ob_src->defbase, idx_src);
				BKE_object_defgroup_add_name(ob_dst, dg_src->name);
				idx_dst = ob_dst->actdef - 1;
			}
		}
		else if (tolayers == DT_LAYERS_INDEX_DST) {
			int num = BLI_listbase_count(&ob_src->defbase);
			idx_dst = idx_src;
			if (num <= idx_dst) {
				if (!use_create) {
					return true;
				}
				/* Create as much vgroups as necessary! */
				for (; num <= idx_dst; num++) {
					BKE_object_defgroup_add(ob_dst);
				}
			}
		}
		else if (tolayers == DT_LAYERS_NAME_DST) {
			bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src);
			if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
				if (!use_create) {
					return true;
				}
				BKE_object_defgroup_add_name(ob_dst, dg_src->name);
				idx_dst = ob_dst->actdef - 1;
			}
		}
		else {
			return false;
		}

		if (r_map) {
			/* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
			 * use_create is not relevant in this case */
			if (!data_dst) {
				data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
			}

			data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
			                                     data_src, data_dst, idx_src, idx_dst,
			                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
		}
	}
	else {
		int num_src, num_sel_unused;
		bool *use_layers_src = NULL;
		bool ret = false;

		switch (fromlayers) {
			case DT_LAYERS_ALL_SRC:
				use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL,
				                                                             &num_src, &num_sel_unused);
				break;
			case DT_LAYERS_VGROUP_SRC_BONE_SELECT:
				use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT,
				                                                             &num_src, &num_sel_unused);
				break;
			case DT_LAYERS_VGROUP_SRC_BONE_DEFORM:
				use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM,
				                                                             &num_src, &num_sel_unused);
				break;
		}

		if (use_layers_src) {
			ret = data_transfer_layersmapping_vgroups_multisrc_to_dst(
			        r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete,
			        ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst,
			        tolayers, use_layers_src, num_src);
		}

		MEM_SAFE_FREE(use_layers_src);
		return ret;
	}

	return true;
}
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
        DisplaceModifierData *dmd, Object *ob,
        DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
	int i;
	MVert *mvert;
	MDeformVert *dvert;
	int direction = dmd->direction;
	int defgrp_index;
	float (*tex_co)[3];
	float weight = 1.0f; /* init value unused but some compilers may complain */
	const float delta_fixed = 1.0f - dmd->midlevel;  /* when no texture is used, we fallback to white */
	float (*vert_clnors)[3] = NULL;

	if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
	if (dmd->strength == 0.0f) return;

	mvert = CDDM_get_verts(dm);
	modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);

	if (dmd->texture) {
		tex_co = MEM_callocN(sizeof(*tex_co) * numVerts,
		                     "displaceModifier_do tex_co");
		get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts);

		modifier_init_texture(dmd->modifier.scene, dmd->texture);
	}
	else {
		tex_co = NULL;
	}

	if (direction == MOD_DISP_DIR_CLNOR) {
		CustomData *ldata = dm->getLoopDataLayout(dm);

		if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
			float (*clnors)[3] = NULL;

			if ((dm->dirty & DM_DIRTY_NORMALS) || !CustomData_has_layer(ldata, CD_NORMAL)) {
				dm->calcLoopNormals(dm, true, (float)M_PI);
			}

			clnors = CustomData_get_layer(ldata, CD_NORMAL);
			vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__);
			BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm),
			                                (const float (*)[3])clnors, vert_clnors);
		}
		else {
			direction = MOD_DISP_DIR_NOR;
		}
	}

	for (i = 0; i < numVerts; i++) {
		TexResult texres;
		float strength = dmd->strength;
		float delta;

		if (dvert) {
			weight = defvert_find_weight(dvert + i, defgrp_index);
			if (weight == 0.0f) continue;
		}

		if (dmd->texture) {
			texres.nor = NULL;
			BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false);
			delta = texres.tin - dmd->midlevel;
		}
		else {
			delta = delta_fixed;  /* (1.0f - dmd->midlevel) */  /* never changes */
		}

		if (dvert) strength *= weight;

		delta *= strength;
		CLAMP(delta, -10000, 10000);

		switch (direction) {
			case MOD_DISP_DIR_X:
				vertexCos[i][0] += delta;
				break;
			case MOD_DISP_DIR_Y:
				vertexCos[i][1] += delta;
				break;
			case MOD_DISP_DIR_Z:
				vertexCos[i][2] += delta;
				break;
			case MOD_DISP_DIR_RGB_XYZ:
				vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
				vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
				vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
				break;
			case MOD_DISP_DIR_NOR:
				vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
				vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
				vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
				break;
			case MOD_DISP_DIR_CLNOR:
				madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta);
				break;
		}
	}

	if (tex_co) {
		MEM_freeN(tex_co);
	}

	if (vert_clnors) {
		MEM_freeN(vert_clnors);
	}
}
Example #28
0
/* MultiresBake callback for heights baking
 * general idea:
 *   - find coord of point with specified UV in hi-res mesh (let's call it p1)
 *   - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res
 *     mesh to make texture smoother) let's call this point p0 and n.
 *   - height wound be dot(n, p1-p0) */
static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
                                   ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
                                   float UNUSED(tangmat[3][3]), const int x, const int y)
{
	MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;
	MHeightBakeData *height_data = (MHeightBakeData *)bake_data;
	float uv[2], *st0, *st1, *st2, *st3;
	int pixel = ibuf->x * y + x;
	float vec[3], p0[3], p1[3], n[3], len;

	lores_dm->getTessFace(lores_dm, face_index, &mface);

	st0 = mtface[face_index].uv[0];
	st1 = mtface[face_index].uv[1];
	st2 = mtface[face_index].uv[2];

	if (mface.v4) {
		st3 = mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	}
	else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm,
	               height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly,
	               lvl, face_index, uv[0], uv[1], p1, 0);

	if (height_data->ssdm) {
		get_ccgdm_data(lores_dm, height_data->ssdm,
		               height_data->orig_index_mf_to_mpoly, height_data->orig_index_mf_to_mpoly,
		               0, face_index, uv[0], uv[1], p0, n);
	}
	else {
		lores_dm->getTessFace(lores_dm, face_index, &mface);

		if (mface.v4) {
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		}
		else {
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		}
	}

	sub_v3_v3v3(vec, p1, p0);
	len = dot_v3v3(n, vec);

	height_data->heights[pixel] = len;
	if (len < height_data->height_min) height_data->height_min = len;
	if (len > height_data->height_max) height_data->height_max = len;

	if (ibuf->rect_float) {
		float *rrgbf = ibuf->rect_float + pixel * 4;
		rrgbf[3] = 1.0f;
	}
	else {
		char *rrgb = (char *)ibuf->rect + pixel * 4;
		rrgb[3] = 255;
	}
}
Example #29
0
static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
{
	DerivedMesh *result;

	MVert *mverts;
	MPoly *mpolys;
	MLoop *mloops;
	int *origindex;

	int cdlayer;

	const int rx = omd->resolution * omd->resolution;
	const int ry = omd->resolution * omd->resolution;
	const int res_x = rx * omd->repeat_x;
	const int res_y = ry * omd->repeat_y;

	const int num_verts = (res_x + 1) * (res_y + 1);
	/* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */
	const int num_faces = res_x * res_y;

	float sx = omd->size * omd->spatial_size;
	float sy = omd->size * omd->spatial_size;
	const float ox = -sx / 2.0f;
	const float oy = -sy / 2.0f;

	float ix, iy;

	int x, y;

	sx /= rx;
	sy /= ry;

	result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);

	mverts = CDDM_get_verts(result);
	mpolys = CDDM_get_polys(result);
	mloops = CDDM_get_loops(result);

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	/* create vertices */
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
	for (y = 0; y <= res_y; y++) {
		for (x = 0; x <= res_x; x++) {
			const int i = y * (res_x + 1) + x;
			float *co = mverts[i].co;
			co[0] = ox + (x * sx);
			co[1] = oy + (y * sy);
			co[2] = 0;
		}
	}

	/* create faces */
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
	for (y = 0; y < res_y; y++) {
		for (x = 0; x < res_x; x++) {
			const int fi = y * res_x + x;
			const int vi = y * (res_x + 1) + x;
			MPoly *mp = &mpolys[fi];
			MLoop *ml = &mloops[fi * 4];

			ml->v = vi;
			ml++;
			ml->v = vi + 1;
			ml++;
			ml->v = vi + 1 + res_x + 1;
			ml++;
			ml->v = vi + res_x + 1;
			ml++;

			mp->loopstart = fi * 4;
			mp->totloop = 4;

			mp->flag |= ME_SMOOTH;

			/* generated geometry does not map to original faces */
			origindex[fi] = ORIGINDEX_NONE;
		}
	}

	CDDM_calc_edges(result);

	/* add uvs */
	cdlayer = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
	if (cdlayer < MAX_MTFACE) {
		MLoopUV *mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4);
		CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_faces);

		if (mloopuvs) { /* unlikely to fail */
			ix = 1.0 / rx;
			iy = 1.0 / ry;
#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
			for (y = 0; y < res_y; y++) {
				for (x = 0; x < res_x; x++) {
					const int i = y * res_x + x;
					MLoopUV *luv = &mloopuvs[i * 4];

					luv->uv[0] = x * ix;
					luv->uv[1] = y * iy;
					luv++;

					luv->uv[0] = (x + 1) * ix;
					luv->uv[1] = y * iy;
					luv++;

					luv->uv[0] = (x + 1) * ix;
					luv->uv[1] = (y + 1) * iy;
					luv++;

					luv->uv[0] = x * ix;
					luv->uv[1] = (y + 1) * iy;
					luv++;

				}
			}
		}
	}

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
Example #30
0
static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
                              ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
                              float UNUSED(tangmat[3][3]), const int x, const int y)
{
	MAOBakeData *ao_data = (MAOBakeData *) bake_data;
	MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;

	int i, k, perm_offs;
	float pos[3], nrm[3];
	float cen[3];
	float axisX[3], axisY[3], axisZ[3];
	float shadow = 0;
	float value;
	int pixel = ibuf->x * y + x;
	float uv[2], *st0, *st1, *st2, *st3;

	lores_dm->getTessFace(lores_dm, face_index, &mface);

	st0 = mtface[face_index].uv[0];
	st1 = mtface[face_index].uv[1];
	st2 = mtface[face_index].uv[2];

	if (mface.v4) {
		st3 = mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	}
	else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm,
	               ao_data->orig_index_mf_to_mpoly, ao_data->orig_index_mp_to_orig,
	               lvl, face_index, uv[0], uv[1], pos, nrm);

	/* offset ray origin by user bias along normal */
	for (i = 0; i < 3; i++)
		cen[i] = pos[i] + ao_data->bias * nrm[i];

	/* build tangent frame */
	for (i = 0; i < 3; i++)
		axisZ[i] = nrm[i];

	build_coordinate_frame(axisX, axisY, axisZ);

	/* static noise */
	perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);

	/* importance sample shadow rays (cosine weighted) */
	for (i = 0; i < ao_data->number_of_rays; i++) {
		int hit_something;

		/* use N-Rooks to distribute our N ray samples across
		 * a multi-dimensional domain (2D)
		 */
		const unsigned short I = ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays];
		const unsigned short J = ao_data->permutation_table_2[i];

		const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS);
		const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS);
		const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays;
		const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays);

		/* this gives results identical to the so-called cosine
		 * weighted distribution relative to the north pole.
		 */
		float SiPhi = sqrt(SiSqPhi);
		float CoPhi = SiSqPhi < 1.0f ? sqrtf(1.0f - SiSqPhi) : 0;
		float CoThe = cos(Theta);
		float SiThe = sin(Theta);

		const float dx = CoThe * CoPhi;
		const float dy = SiThe * CoPhi;
		const float dz = SiPhi;

		/* transform ray direction out of tangent frame */
		float dv[3];
		for (k = 0; k < 3; k++)
			dv[k] = axisX[k] * dx + axisY[k] * dy + axisZ[k] * dz;

		hit_something = trace_ao_ray(ao_data, cen, dv);

		if (hit_something != 0)
			shadow += 1;
	}

	value = 1.0f - (shadow / ao_data->number_of_rays);

	if (ibuf->rect_float) {
		float *rrgbf = ibuf->rect_float + pixel * 4;
		rrgbf[0] = rrgbf[1] = rrgbf[2] = value;
		rrgbf[3] = 1.0f;
	}
	else {
		unsigned char *rrgb = (unsigned char *) ibuf->rect + pixel * 4;
		rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(value);
		rrgb[3] = 255;
	}
}